diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs
index 4c81983c24296..a5986f2bba57c 100644
--- a/compiler/rustc_ast_lowering/src/asm.rs
+++ b/compiler/rustc_ast_lowering/src/asm.rs
@@ -32,7 +32,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let asm_arch =
             if self.tcx.sess.opts.actually_rustdoc { None } else { self.tcx.sess.asm_arch };
         if asm_arch.is_none() && !self.tcx.sess.opts.actually_rustdoc {
-            self.tcx.sess.emit_err(InlineAsmUnsupportedTarget { span: sp });
+            self.dcx().emit_err(InlineAsmUnsupportedTarget { span: sp });
         }
         if let Some(asm_arch) = asm_arch {
             // Inline assembly is currently only stable for these architectures.
@@ -60,7 +60,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             && !matches!(asm_arch, Some(asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64))
             && !self.tcx.sess.opts.actually_rustdoc
         {
-            self.tcx.sess.emit_err(AttSyntaxOnlyX86 { span: sp });
+            self.dcx().emit_err(AttSyntaxOnlyX86 { span: sp });
         }
         if asm.options.contains(InlineAsmOptions::MAY_UNWIND) && !self.tcx.features().asm_unwind {
             feature_err(
@@ -87,7 +87,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                     != source_map.span_to_snippet(*abi_span))
                                 .then_some(());
 
-                                self.tcx.sess.emit_err(AbiSpecifiedMultipleTimes {
+                                self.dcx().emit_err(AbiSpecifiedMultipleTimes {
                                     abi_span: *abi_span,
                                     prev_name: *prev_name,
                                     prev_span: *prev_sp,
@@ -100,14 +100,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                     }
                     Err(&[]) => {
-                        self.tcx.sess.emit_err(ClobberAbiNotSupported { abi_span: *abi_span });
+                        self.dcx().emit_err(ClobberAbiNotSupported { abi_span: *abi_span });
                     }
                     Err(supported_abis) => {
                         let mut abis = format!("`{}`", supported_abis[0]);
                         for m in &supported_abis[1..] {
                             let _ = write!(abis, ", `{m}`");
                         }
-                        self.tcx.sess.emit_err(InvalidAbiClobberAbi {
+                        self.dcx().emit_err(InvalidAbiClobberAbi {
                             abi_span: *abi_span,
                             supported_abis: abis,
                         });
@@ -128,7 +128,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     InlineAsmRegOrRegClass::Reg(reg) => {
                         asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch {
                             asm::InlineAsmReg::parse(asm_arch, reg).unwrap_or_else(|error| {
-                                sess.emit_err(InvalidRegister { op_span: *op_sp, reg, error });
+                                self.dcx().emit_err(InvalidRegister {
+                                    op_span: *op_sp,
+                                    reg,
+                                    error,
+                                });
                                 asm::InlineAsmReg::Err
                             })
                         } else {
@@ -139,7 +143,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         asm::InlineAsmRegOrRegClass::RegClass(if let Some(asm_arch) = asm_arch {
                             asm::InlineAsmRegClass::parse(asm_arch, reg_class).unwrap_or_else(
                                 |error| {
-                                    sess.emit_err(InvalidRegisterClass {
+                                    self.dcx().emit_err(InvalidRegisterClass {
                                         op_span: *op_sp,
                                         reg_class,
                                         error,
@@ -276,7 +280,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                     class_name: class.name(),
                                 }
                             };
-                            sess.emit_err(InvalidAsmTemplateModifierRegClass {
+                            self.dcx().emit_err(InvalidAsmTemplateModifierRegClass {
                                 placeholder_span,
                                 op_span: op_sp,
                                 sub,
@@ -284,14 +288,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         }
                     }
                     hir::InlineAsmOperand::Const { .. } => {
-                        sess.emit_err(InvalidAsmTemplateModifierConst {
+                        self.dcx().emit_err(InvalidAsmTemplateModifierConst {
                             placeholder_span,
                             op_span: op_sp,
                         });
                     }
                     hir::InlineAsmOperand::SymFn { .. }
                     | hir::InlineAsmOperand::SymStatic { .. } => {
-                        sess.emit_err(InvalidAsmTemplateModifierSym {
+                        self.dcx().emit_err(InvalidAsmTemplateModifierSym {
                             placeholder_span,
                             op_span: op_sp,
                         });
@@ -315,7 +319,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 // require that the operand name an explicit register, not a
                 // register class.
                 if reg_class.is_clobber_only(asm_arch.unwrap()) && !op.is_clobber() {
-                    sess.emit_err(RegisterClassOnlyClobber {
+                    self.dcx().emit_err(RegisterClassOnlyClobber {
                         op_span: op_sp,
                         reg_class_name: reg_class.name(),
                     });
@@ -384,7 +388,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                                     }
                                 };
 
-                                sess.emit_err(RegisterConflict {
+                                self.dcx().emit_err(RegisterConflict {
                                     op_span1: op_sp,
                                     op_span2: op_sp2,
                                     reg1_name: reg_str(idx),
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 1f6d47ab4535b..7e63826647835 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -249,7 +249,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     self.lower_expr_range(e.span, e1.as_deref(), e2.as_deref(), *lims)
                 }
                 ExprKind::Underscore => {
-                    let guar = self.tcx.sess.emit_err(UnderscoreExprLhsAssign { span: e.span });
+                    let guar = self.dcx().emit_err(UnderscoreExprLhsAssign { span: e.span });
                     hir::ExprKind::Err(guar)
                 }
                 ExprKind::Path(qself, path) => {
@@ -294,8 +294,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     let rest = match &se.rest {
                         StructRest::Base(e) => Some(self.lower_expr(e)),
                         StructRest::Rest(sp) => {
-                            let guar =
-                                self.tcx.sess.emit_err(BaseExpressionDoubleDot { span: *sp });
+                            let guar = self.dcx().emit_err(BaseExpressionDoubleDot { span: *sp });
                             Some(&*self.arena.alloc(self.expr_err(*sp, guar)))
                         }
                         StructRest::None => None,
@@ -332,9 +331,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         |this| this.with_new_scopes(e.span, |this| this.lower_block_expr(block)),
                     ),
                 ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()),
-                ExprKind::Err => hir::ExprKind::Err(
-                    self.tcx.sess.span_delayed_bug(e.span, "lowered ExprKind::Err"),
-                ),
+                ExprKind::Err => {
+                    hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err"))
+                }
                 ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr),
 
                 ExprKind::Paren(_) | ExprKind::ForLoop { .. } => {
@@ -584,13 +583,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 if self.tcx.features().never_patterns {
                     // If the feature is off we already emitted the error after parsing.
                     let suggestion = span.shrink_to_hi();
-                    self.tcx.sess.emit_err(MatchArmWithNoBody { span, suggestion });
+                    self.dcx().emit_err(MatchArmWithNoBody { span, suggestion });
                 }
             } else if let Some(body) = &arm.body {
-                self.tcx.sess.emit_err(NeverPatternWithBody { span: body.span });
+                self.dcx().emit_err(NeverPatternWithBody { span: body.span });
                 guard = None;
             } else if let Some(g) = &arm.guard {
-                self.tcx.sess.emit_err(NeverPatternWithGuard { span: g.span });
+                self.dcx().emit_err(NeverPatternWithGuard { span: g.span });
                 guard = None;
             }
 
@@ -902,7 +901,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             Some(hir::CoroutineKind::Coroutine)
             | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _))
             | None => {
-                return hir::ExprKind::Err(self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks {
+                return hir::ExprKind::Err(self.dcx().emit_err(AwaitOnlyInAsyncFnAndBlocks {
                     await_kw_span,
                     item_span: self.current_item,
                 }));
@@ -1129,7 +1128,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         match coroutine_kind {
             Some(hir::CoroutineKind::Coroutine) => {
                 if decl.inputs.len() > 1 {
-                    self.tcx.sess.emit_err(CoroutineTooManyParameters { fn_decl_span });
+                    self.dcx().emit_err(CoroutineTooManyParameters { fn_decl_span });
                 }
                 Some(movability)
             }
@@ -1142,7 +1141,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             }
             None => {
                 if movability == Movability::Static {
-                    self.tcx.sess.emit_err(ClosureCannotBeStatic { fn_decl_span });
+                    self.dcx().emit_err(ClosureCannotBeStatic { fn_decl_span });
                 }
                 None
             }
@@ -1181,7 +1180,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         };
 
         if let &ClosureBinder::For { span, .. } = binder {
-            self.tcx.sess.emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
+            self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
         }
 
         let (binder_clause, generic_params) = self.lower_closure_binder(binder);
@@ -1192,7 +1191,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         let body = self.with_new_scopes(fn_decl_span, |this| {
             // FIXME(cramertj): allow `async` non-`move` closures with arguments.
             if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
-                this.tcx.sess.emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span });
+                this.dcx().emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span });
             }
 
             // Transform `async |x: u8| -> X { ... }` into
@@ -1448,7 +1447,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 );
                 let fields_omitted = match &se.rest {
                     StructRest::Base(e) => {
-                        self.tcx.sess.emit_err(FunctionalRecordUpdateDestructuringAssignment {
+                        self.dcx().emit_err(FunctionalRecordUpdateDestructuringAssignment {
                             span: e.span,
                         });
                         true
@@ -1544,7 +1543,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             (None, Some(..), Closed) => hir::LangItem::RangeToInclusive,
             (Some(..), Some(..), Closed) => unreachable!(),
             (start, None, Closed) => {
-                self.tcx.sess.emit_err(InclusiveRangeWithNoEnd { span });
+                self.dcx().emit_err(InclusiveRangeWithNoEnd { span });
                 match start {
                     Some(..) => hir::LangItem::RangeFrom,
                     None => hir::LangItem::RangeFull,
@@ -1653,7 +1652,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _)) => true,
             Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)) => {
                 return hir::ExprKind::Err(
-                    self.tcx.sess.emit_err(AsyncCoroutinesNotSupported { span }),
+                    self.dcx().emit_err(AsyncCoroutinesNotSupported { span }),
                 );
             }
             Some(hir::CoroutineKind::Coroutine) | None => {
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index 6a82005c44842..00cb09d7a541a 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -267,7 +267,7 @@ fn make_count<'hir>(
                 ctx.expr(
                     sp,
                     hir::ExprKind::Err(
-                        ctx.tcx.sess.span_delayed_bug(sp, "lowered bad format_args count"),
+                        ctx.dcx().span_delayed_bug(sp, "lowered bad format_args count"),
                     ),
                 )
             }
@@ -306,7 +306,7 @@ fn make_format_spec<'hir>(
         }
         Err(_) => ctx.expr(
             sp,
-            hir::ExprKind::Err(ctx.tcx.sess.span_delayed_bug(sp, "lowered bad format_args count")),
+            hir::ExprKind::Err(ctx.dcx().span_delayed_bug(sp, "lowered bad format_args count")),
         ),
     };
     let &FormatOptions {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 9c990cb4619d2..81457018b37af 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -265,7 +265,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| match ty {
                         None => {
-                            let guar = this.tcx.sess.span_delayed_bug(
+                            let guar = this.dcx().span_delayed_bug(
                                 span,
                                 "expected to lower type alias type, but it was missing",
                             );
@@ -879,7 +879,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                     &ImplTraitContext::Disallowed(ImplTraitPosition::Generic),
                     |this| match ty {
                         None => {
-                            let guar = this.tcx.sess.span_delayed_bug(
+                            let guar = this.dcx().span_delayed_bug(
                                 i.span,
                                 "expected to lower associated type, but it was missing",
                             );
@@ -1012,7 +1012,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
     fn lower_block_expr_opt(&mut self, span: Span, block: Option<&Block>) -> hir::Expr<'hir> {
         match block {
             Some(block) => self.lower_block_expr(block),
-            None => self.expr_err(span, self.tcx.sess.span_delayed_bug(span, "no block")),
+            None => self.expr_err(span, self.dcx().span_delayed_bug(span, "no block")),
         }
     }
 
@@ -1022,7 +1022,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 &[],
                 match expr {
                     Some(expr) => this.lower_expr_mut(expr),
-                    None => this.expr_err(span, this.tcx.sess.span_delayed_bug(span, "no block")),
+                    None => this.expr_err(span, this.dcx().span_delayed_bug(span, "no block")),
                 },
             )
         })
@@ -1296,7 +1296,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             .map(|s| Symbol::intern(s))
             .collect::<Vec<_>>();
         let suggested_name = find_best_match_for_name(&abi_names, abi.symbol_unescaped, None);
-        self.tcx.sess.emit_err(InvalidAbi {
+        self.dcx().emit_err(InvalidAbi {
             abi: abi.symbol_unescaped,
             span: abi.span,
             explain: match err {
@@ -1383,7 +1383,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                 }
                 let is_param = *is_param.get_or_insert_with(compute_is_param);
                 if !is_param {
-                    self.tcx.sess.emit_err(MisplacedRelaxTraitBound { span: bound.span() });
+                    self.dcx().emit_err(MisplacedRelaxTraitBound { span: bound.span() });
                 }
             }
         }
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index e35d7d62cad48..e395411628886 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -53,7 +53,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
 use rustc_data_structures::sorted_map::SortedMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_data_structures::sync::Lrc;
-use rustc_errors::{DiagnosticArgFromDisplay, StashKey};
+use rustc_errors::{DiagCtxt, DiagnosticArgFromDisplay, StashKey};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
 use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE};
@@ -183,6 +183,10 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             host_param_id: None,
         }
     }
+
+    pub(crate) fn dcx(&self) -> &'hir DiagCtxt {
+        self.tcx.dcx()
+    }
 }
 
 trait ResolverAstLoweringExt {
@@ -1035,11 +1039,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         && first_char.is_ascii_lowercase()
                     {
                         let mut err = if !data.inputs.is_empty() {
-                            self.tcx.sess.create_err(errors::BadReturnTypeNotation::Inputs {
+                            self.dcx().create_err(errors::BadReturnTypeNotation::Inputs {
                                 span: data.inputs_span,
                             })
                         } else if let FnRetTy::Ty(ty) = &data.output {
-                            self.tcx.sess.create_err(errors::BadReturnTypeNotation::Output {
+                            self.dcx().create_err(errors::BadReturnTypeNotation::Output {
                                 span: data.inputs_span.shrink_to_hi().to(ty.span),
                             })
                         } else {
@@ -1163,7 +1167,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         hir::TypeBindingKind::Constraint { bounds }
                     }
                     DesugarKind::Error(position) => {
-                        let guar = self.tcx.sess.emit_err(errors::MisplacedAssocTyBinding {
+                        let guar = self.dcx().emit_err(errors::MisplacedAssocTyBinding {
                             span: constraint.span,
                             position: DiagnosticArgFromDisplay(position),
                         });
@@ -1205,7 +1209,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 data.inputs.last().unwrap().span.shrink_to_hi().to(data.inputs_span.shrink_to_hi());
             AssocTyParenthesesSub::NotEmpty { open_param, close_param }
         };
-        self.tcx.sess.emit_err(AssocTyParentheses { span: data.span, sub });
+        self.dcx().emit_err(AssocTyParentheses { span: data.span, sub });
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -1347,20 +1351,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         let kind = match &t.kind {
             TyKind::Infer => hir::TyKind::Infer,
             TyKind::Err => {
-                hir::TyKind::Err(self.tcx.sess.span_delayed_bug(t.span, "TyKind::Err lowered"))
+                hir::TyKind::Err(self.dcx().span_delayed_bug(t.span, "TyKind::Err lowered"))
             }
             // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
             #[allow(rustc::untranslatable_diagnostic)]
             #[allow(rustc::diagnostic_outside_of_impl)]
-            TyKind::AnonStruct(ref _fields) => hir::TyKind::Err(
-                self.tcx.sess.span_err(t.span, "anonymous structs are unimplemented"),
-            ),
+            TyKind::AnonStruct(ref _fields) => {
+                hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous structs are unimplemented"))
+            }
             // FIXME(unnamed_fields): IMPLEMENTATION IN PROGRESS
             #[allow(rustc::untranslatable_diagnostic)]
             #[allow(rustc::diagnostic_outside_of_impl)]
-            TyKind::AnonUnion(ref _fields) => hir::TyKind::Err(
-                self.tcx.sess.span_err(t.span, "anonymous unions are unimplemented"),
-            ),
+            TyKind::AnonUnion(ref _fields) => {
+                hir::TyKind::Err(self.dcx().span_err(t.span, "anonymous unions are unimplemented"))
+            }
             TyKind::Slice(ty) => hir::TyKind::Slice(self.lower_ty(ty, itctx)),
             TyKind::Ptr(mt) => hir::TyKind::Ptr(self.lower_mt(mt, itctx)),
             TyKind::Ref(region, mt) => {
@@ -1518,7 +1522,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         hir::TyKind::Err(guar)
                     }
                     ImplTraitContext::Disallowed(position) => {
-                        let guar = self.tcx.sess.emit_err(MisplacedImplTrait {
+                        let guar = self.dcx().emit_err(MisplacedImplTrait {
                             span: t.span,
                             position: DiagnosticArgFromDisplay(position),
                         });
@@ -1528,7 +1532,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             }
             TyKind::MacCall(_) => panic!("`TyKind::MacCall` should have been expanded by now"),
             TyKind::CVarArgs => {
-                let guar = self.tcx.sess.span_delayed_bug(
+                let guar = self.dcx().span_delayed_bug(
                     t.span,
                     "`TyKind::CVarArgs` should have been handled elsewhere",
                 );
@@ -1672,8 +1676,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     if let Some(old_def_id) = self.orig_opt_local_def_id(param) {
                         old_def_id
                     } else {
-                        self.tcx
-                            .sess
+                        self.dcx()
                             .span_delayed_bug(lifetime.ident.span, "no def-id for fresh lifetime");
                         continue;
                     }
@@ -2569,7 +2572,7 @@ impl<'hir> GenericArgsCtor<'hir> {
         let hir_id = lcx.next_id();
 
         let Some(host_param_id) = lcx.host_param_id else {
-            lcx.tcx.sess.span_delayed_bug(
+            lcx.dcx().span_delayed_bug(
                 span,
                 "no host param id for call in const yet no errors reported",
             );
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 3ffa4f1f2e6eb..1c405fac7e40a 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -140,7 +140,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 // This is not allowed as a sub-tuple pattern
                 PatKind::Ident(_, ident, Some(sub)) if sub.is_rest() => {
                     let sp = pat.span;
-                    self.tcx.sess.emit_err(SubTupleBinding {
+                    self.dcx().emit_err(SubTupleBinding {
                         span: sp,
                         ident_name: ident.name,
                         ident: *ident,
@@ -289,12 +289,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
     /// Emit a friendly error for extra `..` patterns in a tuple/tuple struct/slice pattern.
     pub(crate) fn ban_extra_rest_pat(&self, sp: Span, prev_sp: Span, ctx: &str) {
-        self.tcx.sess.emit_err(ExtraDoubleDot { span: sp, prev_span: prev_sp, ctx });
+        self.dcx().emit_err(ExtraDoubleDot { span: sp, prev_span: prev_sp, ctx });
     }
 
     /// Used to ban the `..` pattern in places it shouldn't be semantically.
     fn ban_illegal_rest_pat(&self, sp: Span) -> hir::PatKind<'hir> {
-        self.tcx.sess.emit_err(MisplacedDoubleDot { span: sp });
+        self.dcx().emit_err(MisplacedDoubleDot { span: sp });
 
         // We're not in a list context so `..` can be reasonably treated
         // as `_` because it should always be valid and roughly matches the
@@ -334,7 +334,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             ExprKind::Path(..) if allow_paths => {}
             ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {}
             _ => {
-                let guar = self.tcx.sess.emit_err(ArbitraryExpressionInPattern { span: expr.span });
+                let guar = self.dcx().emit_err(ArbitraryExpressionInPattern { span: expr.span });
                 return self.arena.alloc(self.expr_err(expr.span, guar));
             }
         }
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 5ceeb72f2912a..130eb3521c3f4 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -140,7 +140,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         // We should've returned in the for loop above.
 
-        self.tcx.sess.dcx().span_bug(
+        self.dcx().span_bug(
             p.span,
             format!(
                 "lower_qpath: no final extension segment in {}..{}",
@@ -214,7 +214,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         } else {
                             None
                         };
-                        self.tcx.sess.emit_err(GenericTypeWithParentheses { span: data.span, sub });
+                        self.dcx().emit_err(GenericTypeWithParentheses { span: data.span, sub });
                         (
                             self.lower_angle_bracketed_parameter_data(
                                 &data.as_angle_bracketed_args(),
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 23a457494554f..3600e4960afd2 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -228,13 +228,13 @@ impl<'a> AstValidator<'a> {
     fn check_lifetime(&self, ident: Ident) {
         let valid_names = [kw::UnderscoreLifetime, kw::StaticLifetime, kw::Empty];
         if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
-            self.session.emit_err(errors::KeywordLifetime { span: ident.span });
+            self.dcx().emit_err(errors::KeywordLifetime { span: ident.span });
         }
     }
 
     fn check_label(&self, ident: Ident) {
         if ident.without_first_quote().is_reserved() {
-            self.session.emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
+            self.dcx().emit_err(errors::InvalidLabel { span: ident.span, name: ident.name });
         }
     }
 
@@ -243,7 +243,7 @@ impl<'a> AstValidator<'a> {
             return;
         }
 
-        self.session.emit_err(errors::VisibilityNotPermitted { span: vis.span, note });
+        self.dcx().emit_err(errors::VisibilityNotPermitted { span: vis.span, note });
     }
 
     fn check_decl_no_pat(decl: &FnDecl, mut report_err: impl FnMut(Span, Option<Ident>, bool)) {
@@ -293,7 +293,7 @@ impl<'a> AstValidator<'a> {
 
     fn check_trait_fn_not_const(&self, constness: Const) {
         if let Const::Yes(span) = constness {
-            self.session.emit_err(errors::TraitFnConst { span });
+            self.dcx().emit_err(errors::TraitFnConst { span });
         }
     }
 
@@ -310,7 +310,7 @@ impl<'a> AstValidator<'a> {
         let max_num_args: usize = u16::MAX.into();
         if fn_decl.inputs.len() > max_num_args {
             let Param { span, .. } = fn_decl.inputs[0];
-            self.session.emit_fatal(errors::FnParamTooMany { span, max_num_args });
+            self.dcx().emit_fatal(errors::FnParamTooMany { span, max_num_args });
         }
     }
 
@@ -318,13 +318,13 @@ impl<'a> AstValidator<'a> {
         match &*fn_decl.inputs {
             [Param { ty, span, .. }] => {
                 if let TyKind::CVarArgs = ty.kind {
-                    self.session.emit_err(errors::FnParamCVarArgsOnly { span: *span });
+                    self.dcx().emit_err(errors::FnParamCVarArgsOnly { span: *span });
                 }
             }
             [ps @ .., _] => {
                 for Param { ty, span, .. } in ps {
                     if let TyKind::CVarArgs = ty.kind {
-                        self.session.emit_err(errors::FnParamCVarArgsNotLast { span: *span });
+                        self.dcx().emit_err(errors::FnParamCVarArgsNotLast { span: *span });
                     }
                 }
             }
@@ -351,9 +351,9 @@ impl<'a> AstValidator<'a> {
             })
             .for_each(|attr| {
                 if attr.is_doc_comment() {
-                    self.session.emit_err(errors::FnParamDocComment { span: attr.span });
+                    self.dcx().emit_err(errors::FnParamDocComment { span: attr.span });
                 } else {
-                    self.session.emit_err(errors::FnParamForbiddenAttr { span: attr.span });
+                    self.dcx().emit_err(errors::FnParamForbiddenAttr { span: attr.span });
                 }
             });
     }
@@ -361,7 +361,7 @@ impl<'a> AstValidator<'a> {
     fn check_decl_self_param(&self, fn_decl: &FnDecl, self_semantic: SelfSemantic) {
         if let (SelfSemantic::No, [param, ..]) = (self_semantic, &*fn_decl.inputs) {
             if param.is_self() {
-                self.session.emit_err(errors::FnParamForbiddenSelf { span: param.span });
+                self.dcx().emit_err(errors::FnParamForbiddenSelf { span: param.span });
             }
         }
     }
@@ -369,7 +369,7 @@ impl<'a> AstValidator<'a> {
     fn check_defaultness(&self, span: Span, defaultness: Defaultness) {
         if let Defaultness::Default(def_span) = defaultness {
             let span = self.session.source_map().guess_head_span(span);
-            self.session.emit_err(errors::ForbiddenDefault { span, def_span });
+            self.dcx().emit_err(errors::ForbiddenDefault { span, def_span });
         }
     }
 
@@ -532,24 +532,24 @@ impl<'a> AstValidator<'a> {
             return;
         }
         let span = self.session.source_map().guess_head_span(item_span);
-        self.session.emit_err(errors::NoMangleAscii { span });
+        self.dcx().emit_err(errors::NoMangleAscii { span });
     }
 
     fn check_mod_file_item_asciionly(&self, ident: Ident) {
         if ident.name.as_str().is_ascii() {
             return;
         }
-        self.session.emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });
+        self.dcx().emit_err(errors::ModuleNonAscii { span: ident.span, name: ident.name });
     }
 
     fn deny_generic_params(&self, generics: &Generics, ident: Span) {
         if !generics.params.is_empty() {
-            self.session.emit_err(errors::AutoTraitGeneric { span: generics.span, ident });
+            self.dcx().emit_err(errors::AutoTraitGeneric { span: generics.span, ident });
         }
     }
 
     fn emit_e0568(&self, span: Span, ident: Span) {
-        self.session.emit_err(errors::AutoTraitBounds { span, ident });
+        self.dcx().emit_err(errors::AutoTraitBounds { span, ident });
     }
 
     fn deny_super_traits(&self, bounds: &GenericBounds, ident_span: Span) {
@@ -569,7 +569,7 @@ impl<'a> AstValidator<'a> {
         if !trait_items.is_empty() {
             let spans: Vec<_> = trait_items.iter().map(|i| i.ident.span).collect();
             let total = trait_items.first().unwrap().span.to(trait_items.last().unwrap().span);
-            self.session.emit_err(errors::AutoTraitItems { spans, total, ident });
+            self.dcx().emit_err(errors::AutoTraitItems { spans, total, ident });
         }
     }
 
@@ -633,7 +633,7 @@ impl<'a> AstValidator<'a> {
             TyKind::BareFn(bfty) => {
                 self.check_fn_decl(&bfty.decl, SelfSemantic::No);
                 Self::check_decl_no_pat(&bfty.decl, |span, _, _| {
-                    self.session.emit_err(errors::PatternFnPointer { span });
+                    self.dcx().emit_err(errors::PatternFnPointer { span });
                 });
                 if let Extern::Implicit(_) = bfty.ext {
                     let sig_span = self.session.source_map().next_point(ty.span.shrink_to_lo());
@@ -645,7 +645,7 @@ impl<'a> AstValidator<'a> {
                 for bound in bounds {
                     if let GenericBound::Outlives(lifetime) = bound {
                         if any_lifetime_bounds {
-                            self.session
+                            self.dcx()
                                 .emit_err(errors::TraitObjectBound { span: lifetime.ident.span });
                             break;
                         }
@@ -655,11 +655,11 @@ impl<'a> AstValidator<'a> {
             }
             TyKind::ImplTrait(_, bounds) => {
                 if self.is_impl_trait_banned {
-                    self.session.emit_err(errors::ImplTraitPath { span: ty.span });
+                    self.dcx().emit_err(errors::ImplTraitPath { span: ty.span });
                 }
 
                 if let Some(outer_impl_trait_sp) = self.outer_impl_trait {
-                    self.session.emit_err(errors::NestedImplTrait {
+                    self.dcx().emit_err(errors::NestedImplTrait {
                         span: ty.span,
                         outer: outer_impl_trait_sp,
                         inner: ty.span,
@@ -827,7 +827,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     }
                     if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity)
                     {
-                        this.session.emit_err(errors::UnsafeNegativeImpl {
+                        this.dcx().emit_err(errors::UnsafeNegativeImpl {
                             span: sp.to(t.path.span),
                             negative: sp,
                             r#unsafe: span,
@@ -902,7 +902,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 self.check_defaultness(item.span, *defaultness);
 
                 if body.is_none() {
-                    self.session.emit_err(errors::FnWithoutBody {
+                    self.dcx().emit_err(errors::FnWithoutBody {
                         span: item.span,
                         replace_span: self.ending_semi_or_hi(item.span),
                         extern_block_suggestion: match sig.header.ext {
@@ -1031,14 +1031,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             ItemKind::Const(box ConstItem { defaultness, expr, .. }) => {
                 self.check_defaultness(item.span, *defaultness);
                 if expr.is_none() {
-                    self.session.emit_err(errors::ConstWithoutBody {
+                    self.dcx().emit_err(errors::ConstWithoutBody {
                         span: item.span,
                         replace_span: self.ending_semi_or_hi(item.span),
                     });
                 }
             }
             ItemKind::Static(box StaticItem { expr: None, .. }) => {
-                self.session.emit_err(errors::StaticWithoutBody {
+                self.dcx().emit_err(errors::StaticWithoutBody {
                     span: item.span,
                     replace_span: self.ending_semi_or_hi(item.span),
                 });
@@ -1048,7 +1048,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             ) => {
                 self.check_defaultness(item.span, *defaultness);
                 if ty.is_none() {
-                    self.session.emit_err(errors::TyAliasWithoutBody {
+                    self.dcx().emit_err(errors::TyAliasWithoutBody {
                         span: item.span,
                         replace_span: self.ending_semi_or_hi(item.span),
                     });
@@ -1357,14 +1357,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         if ctxt == AssocCtxt::Impl {
             match &item.kind {
                 AssocItemKind::Const(box ConstItem { expr: None, .. }) => {
-                    self.session.emit_err(errors::AssocConstWithoutBody {
+                    self.dcx().emit_err(errors::AssocConstWithoutBody {
                         span: item.span,
                         replace_span: self.ending_semi_or_hi(item.span),
                     });
                 }
                 AssocItemKind::Fn(box Fn { body, .. }) => {
                     if body.is_none() {
-                        self.session.emit_err(errors::AssocFnWithoutBody {
+                        self.dcx().emit_err(errors::AssocFnWithoutBody {
                             span: item.span,
                             replace_span: self.ending_semi_or_hi(item.span),
                         });
@@ -1372,7 +1372,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
                 AssocItemKind::Type(box TyAlias { bounds, ty, .. }) => {
                     if ty.is_none() {
-                        self.session.emit_err(errors::AssocTypeWithoutBody {
+                        self.dcx().emit_err(errors::AssocTypeWithoutBody {
                             span: item.span,
                             replace_span: self.ending_semi_or_hi(item.span),
                         });
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index b20a0b9461f09..2b746789a769f 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -168,7 +168,7 @@ impl<'a> PostExpansionVisitor<'a> {
         for param in params {
             if !param.bounds.is_empty() {
                 let spans: Vec<_> = param.bounds.iter().map(|b| b.span()).collect();
-                self.sess.emit_err(errors::ForbiddenBound { spans });
+                self.sess.dcx().emit_err(errors::ForbiddenBound { spans });
             }
         }
     }
@@ -226,7 +226,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
                 || attr.has_name(sym::rustc_const_stable)
                 || attr.has_name(sym::rustc_default_body_unstable)
             {
-                self.sess.emit_err(errors::StabilityOutsideStd { span: attr.span });
+                self.sess.dcx().emit_err(errors::StabilityOutsideStd { span: attr.span });
             }
         }
     }
@@ -579,7 +579,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
                     .emit();
                 } else {
                     let suggestion = span.shrink_to_hi();
-                    sess.emit_err(errors::MatchArmWithNoBody { span, suggestion });
+                    sess.dcx().emit_err(errors::MatchArmWithNoBody { span, suggestion });
                 }
             }
         }
@@ -587,7 +587,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
 
     if !visitor.features.negative_bounds {
         for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
-            sess.emit_err(errors::NegativeBoundUnsupported { span });
+            sess.dcx().emit_err(errors::NegativeBoundUnsupported { span });
         }
     }
 
@@ -677,7 +677,11 @@ fn check_incompatible_features(sess: &Session, features: &Features) {
             if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2)
             {
                 let spans = vec![f1_span, f2_span];
-                sess.emit_err(errors::IncompatibleFeatures { spans, f1: f1_name, f2: f2_name });
+                sess.dcx().emit_err(errors::IncompatibleFeatures {
+                    spans,
+                    f1: f1_name,
+                    f2: f2_name,
+                });
             }
         }
     }
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 0959e8d304338..77678dcaba9e1 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -207,7 +207,8 @@ pub fn find_stability(
             sym::rustc_allowed_through_unstable_modules => allowed_through_unstable_modules = true,
             sym::unstable => {
                 if stab.is_some() {
-                    sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
+                    sess.dcx()
+                        .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
                     break;
                 }
 
@@ -217,7 +218,8 @@ pub fn find_stability(
             }
             sym::stable => {
                 if stab.is_some() {
-                    sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
+                    sess.dcx()
+                        .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
                     break;
                 }
                 if let Some((feature, level)) = parse_stability(sess, attr) {
@@ -238,7 +240,8 @@ pub fn find_stability(
                 _,
             )) => *allowed_through_unstable_modules = true,
             _ => {
-                sess.emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
+                sess.dcx()
+                    .emit_err(session_diagnostics::RustcAllowedUnstablePairing { span: item_sp });
             }
         }
     }
@@ -261,7 +264,8 @@ pub fn find_const_stability(
             sym::rustc_promotable => promotable = true,
             sym::rustc_const_unstable => {
                 if const_stab.is_some() {
-                    sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
+                    sess.dcx()
+                        .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
                     break;
                 }
 
@@ -272,7 +276,8 @@ pub fn find_const_stability(
             }
             sym::rustc_const_stable => {
                 if const_stab.is_some() {
-                    sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
+                    sess.dcx()
+                        .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
                     break;
                 }
                 if let Some((feature, level)) = parse_stability(sess, attr) {
@@ -288,7 +293,11 @@ pub fn find_const_stability(
     if promotable {
         match &mut const_stab {
             Some((stab, _)) => stab.promotable = promotable,
-            _ => _ = sess.emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp }),
+            _ => {
+                _ = sess
+                    .dcx()
+                    .emit_err(session_diagnostics::RustcPromotablePairing { span: item_sp })
+            }
         }
     }
 
@@ -306,7 +315,8 @@ pub fn find_body_stability(
     for attr in attrs {
         if attr.has_name(sym::rustc_default_body_unstable) {
             if body_stab.is_some() {
-                sess.emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
+                sess.dcx()
+                    .emit_err(session_diagnostics::MultipleStabilityLevels { span: attr.span });
                 break;
             }
 
@@ -321,7 +331,7 @@ pub fn find_body_stability(
 
 fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -> Option<()> {
     if item.is_some() {
-        sess.emit_err(session_diagnostics::MultipleItem {
+        sess.dcx().emit_err(session_diagnostics::MultipleItem {
             span: meta.span,
             item: pprust::path_to_string(&meta.path),
         });
@@ -330,7 +340,7 @@ fn insert_or_error(sess: &Session, meta: &MetaItem, item: &mut Option<Symbol>) -
         *item = Some(v);
         Some(())
     } else {
-        sess.emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
+        sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem { span: meta.span });
         None
     }
 }
@@ -345,7 +355,7 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
     let mut since = None;
     for meta in metas {
         let Some(mi) = meta.meta_item() else {
-            sess.emit_err(session_diagnostics::UnsupportedLiteral {
+            sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
                 span: meta.span(),
                 reason: UnsupportedLiteralReason::Generic,
                 is_bytestr: false,
@@ -358,7 +368,7 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
             sym::feature => insert_or_error(sess, mi, &mut feature)?,
             sym::since => insert_or_error(sess, mi, &mut since)?,
             _ => {
-                sess.emit_err(session_diagnostics::UnknownMetaItem {
+                sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
                     span: meta.span(),
                     item: pprust::path_to_string(&mi.path),
                     expected: &["feature", "since"],
@@ -371,9 +381,9 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
     let feature = match feature {
         Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
         Some(_bad_feature) => {
-            Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
+            Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
         }
-        None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
+        None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span })),
     };
 
     let since = if let Some(since) = since {
@@ -382,11 +392,11 @@ fn parse_stability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabilit
         } else if let Some(version) = parse_version(since) {
             StableSince::Version(version)
         } else {
-            sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
+            sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span });
             StableSince::Err
         }
     } else {
-        sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
+        sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span });
         StableSince::Err
     };
 
@@ -413,7 +423,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
     let mut implied_by = None;
     for meta in metas {
         let Some(mi) = meta.meta_item() else {
-            sess.emit_err(session_diagnostics::UnsupportedLiteral {
+            sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
                 span: meta.span(),
                 reason: UnsupportedLiteralReason::Generic,
                 is_bytestr: false,
@@ -435,7 +445,7 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
                     issue => match issue.parse::<NonZeroU32>() {
                         Ok(num) => Some(num),
                         Err(err) => {
-                            sess.emit_err(
+                            sess.dcx().emit_err(
                                 session_diagnostics::InvalidIssueString {
                                     span: mi.span,
                                     cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind(
@@ -451,13 +461,13 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
             }
             sym::soft => {
                 if !mi.is_word() {
-                    sess.emit_err(session_diagnostics::SoftNoArgs { span: mi.span });
+                    sess.dcx().emit_err(session_diagnostics::SoftNoArgs { span: mi.span });
                 }
                 is_soft = true;
             }
             sym::implied_by => insert_or_error(sess, mi, &mut implied_by)?,
             _ => {
-                sess.emit_err(session_diagnostics::UnknownMetaItem {
+                sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
                     span: meta.span(),
                     item: pprust::path_to_string(&mi.path),
                     expected: &["feature", "reason", "issue", "soft", "implied_by"],
@@ -470,13 +480,13 @@ fn parse_unstability(sess: &Session, attr: &Attribute) -> Option<(Symbol, Stabil
     let feature = match feature {
         Some(feature) if rustc_lexer::is_ident(feature.as_str()) => Ok(feature),
         Some(_bad_feature) => {
-            Err(sess.emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
+            Err(sess.dcx().emit_err(session_diagnostics::NonIdentFeature { span: attr.span }))
         }
-        None => Err(sess.emit_err(session_diagnostics::MissingFeature { span: attr.span })),
+        None => Err(sess.dcx().emit_err(session_diagnostics::MissingFeature { span: attr.span })),
     };
 
-    let issue =
-        issue.ok_or_else(|| sess.emit_err(session_diagnostics::MissingIssue { span: attr.span }));
+    let issue = issue
+        .ok_or_else(|| sess.dcx().emit_err(session_diagnostics::MissingIssue { span: attr.span }));
 
     match (feature, issue) {
         (Ok(feature), Ok(_)) => {
@@ -588,6 +598,7 @@ pub fn eval_condition(
     features: Option<&Features>,
     eval: &mut impl FnMut(Condition) -> bool,
 ) -> bool {
+    let dcx = &sess.dcx;
     match &cfg.kind {
         ast::MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => {
             try_gate_cfg(sym::version, cfg.span, sess, features);
@@ -599,18 +610,18 @@ pub fn eval_condition(
                     NestedMetaItem::Lit(MetaItemLit { span, .. })
                     | NestedMetaItem::MetaItem(MetaItem { span, .. }),
                 ] => {
-                    sess.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
+                    dcx.emit_err(session_diagnostics::ExpectedVersionLiteral { span: *span });
                     return false;
                 }
                 [..] => {
-                    sess.emit_err(session_diagnostics::ExpectedSingleVersionLiteral {
+                    dcx.emit_err(session_diagnostics::ExpectedSingleVersionLiteral {
                         span: cfg.span,
                     });
                     return false;
                 }
             };
             let Some(min_version) = parse_version(*min_version) else {
-                sess.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span });
+                dcx.emit_warning(session_diagnostics::UnknownVersionLiteral { span: *span });
                 return false;
             };
 
@@ -624,7 +635,7 @@ pub fn eval_condition(
         ast::MetaItemKind::List(mis) => {
             for mi in mis.iter() {
                 if !mi.is_meta_item() {
-                    sess.emit_err(session_diagnostics::UnsupportedLiteral {
+                    dcx.emit_err(session_diagnostics::UnsupportedLiteral {
                         span: mi.span(),
                         reason: UnsupportedLiteralReason::Generic,
                         is_bytestr: false,
@@ -653,9 +664,7 @@ pub fn eval_condition(
                     }),
                 sym::not => {
                     if mis.len() != 1 {
-                        sess.emit_err(session_diagnostics::ExpectedOneCfgPattern {
-                            span: cfg.span,
-                        });
+                        dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
                         return false;
                     }
 
@@ -684,7 +693,7 @@ pub fn eval_condition(
                     })
                 }
                 _ => {
-                    sess.emit_err(session_diagnostics::InvalidPredicate {
+                    dcx.emit_err(session_diagnostics::InvalidPredicate {
                         span: cfg.span,
                         predicate: pprust::path_to_string(&cfg.path),
                     });
@@ -693,11 +702,11 @@ pub fn eval_condition(
             }
         }
         ast::MetaItemKind::Word | MetaItemKind::NameValue(..) if cfg.path.segments.len() != 1 => {
-            sess.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
+            dcx.emit_err(session_diagnostics::CfgPredicateIdentifier { span: cfg.path.span });
             true
         }
         MetaItemKind::NameValue(lit) if !lit.kind.is_str() => {
-            sess.emit_err(session_diagnostics::UnsupportedLiteral {
+            dcx.emit_err(session_diagnostics::UnsupportedLiteral {
                 span: lit.span,
                 reason: UnsupportedLiteralReason::CfgString,
                 is_bytestr: lit.kind.is_bytestr(),
@@ -791,7 +800,7 @@ pub fn find_deprecation(
             MetaItemKind::List(list) => {
                 let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
                     if item.is_some() {
-                        sess.emit_err(session_diagnostics::MultipleItem {
+                        sess.dcx().emit_err(session_diagnostics::MultipleItem {
                             span: meta.span,
                             item: pprust::path_to_string(&meta.path),
                         });
@@ -802,14 +811,14 @@ pub fn find_deprecation(
                         true
                     } else {
                         if let Some(lit) = meta.name_value_literal() {
-                            sess.emit_err(session_diagnostics::UnsupportedLiteral {
+                            sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
                                 span: lit.span,
                                 reason: UnsupportedLiteralReason::DeprecatedString,
                                 is_bytestr: lit.kind.is_bytestr(),
                                 start_point_span: sess.source_map().start_point(lit.span),
                             });
                         } else {
-                            sess.emit_err(session_diagnostics::IncorrectMetaItem {
+                            sess.dcx().emit_err(session_diagnostics::IncorrectMetaItem {
                                 span: meta.span,
                             });
                         }
@@ -833,11 +842,13 @@ pub fn find_deprecation(
                             }
                             sym::suggestion => {
                                 if !features.deprecated_suggestion {
-                                    sess.emit_err(session_diagnostics::DeprecatedItemSuggestion {
-                                        span: mi.span,
-                                        is_nightly: sess.is_nightly_build().then_some(()),
-                                        details: (),
-                                    });
+                                    sess.dcx().emit_err(
+                                        session_diagnostics::DeprecatedItemSuggestion {
+                                            span: mi.span,
+                                            is_nightly: sess.is_nightly_build().then_some(()),
+                                            details: (),
+                                        },
+                                    );
                                 }
 
                                 if !get(mi, &mut suggestion) {
@@ -845,7 +856,7 @@ pub fn find_deprecation(
                                 }
                             }
                             _ => {
-                                sess.emit_err(session_diagnostics::UnknownMetaItem {
+                                sess.dcx().emit_err(session_diagnostics::UnknownMetaItem {
                                     span: meta.span(),
                                     item: pprust::path_to_string(&mi.path),
                                     expected: if features.deprecated_suggestion {
@@ -858,7 +869,7 @@ pub fn find_deprecation(
                             }
                         },
                         NestedMetaItem::Lit(lit) => {
-                            sess.emit_err(session_diagnostics::UnsupportedLiteral {
+                            sess.dcx().emit_err(session_diagnostics::UnsupportedLiteral {
                                 span: lit.span,
                                 reason: UnsupportedLiteralReason::DeprecatedKvPair,
                                 is_bytestr: false,
@@ -879,18 +890,18 @@ pub fn find_deprecation(
             } else if let Some(version) = parse_version(since) {
                 DeprecatedSince::RustcVersion(version)
             } else {
-                sess.emit_err(session_diagnostics::InvalidSince { span: attr.span });
+                sess.dcx().emit_err(session_diagnostics::InvalidSince { span: attr.span });
                 DeprecatedSince::Err
             }
         } else if is_rustc {
-            sess.emit_err(session_diagnostics::MissingSince { span: attr.span });
+            sess.dcx().emit_err(session_diagnostics::MissingSince { span: attr.span });
             DeprecatedSince::Err
         } else {
             DeprecatedSince::Unspecified
         };
 
         if is_rustc && note.is_none() {
-            sess.emit_err(session_diagnostics::MissingNote { span: attr.span });
+            sess.dcx().emit_err(session_diagnostics::MissingNote { span: attr.span });
             continue;
         }
 
@@ -945,7 +956,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
     assert!(attr.has_name(sym::repr), "expected `#[repr(..)]`, found: {attr:?}");
     use ReprAttr::*;
     let mut acc = Vec::new();
-    let diagnostic = sess.dcx();
+    let dcx = sess.dcx();
 
     if let Some(items) = attr.meta_item_list() {
         for item in items {
@@ -958,7 +969,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                     sym::simd => Some(ReprSimd),
                     sym::transparent => Some(ReprTransparent),
                     sym::align => {
-                        sess.emit_err(session_diagnostics::InvalidReprAlignNeedArg {
+                        sess.dcx().emit_err(session_diagnostics::InvalidReprAlignNeedArg {
                             span: item.span(),
                         });
                         recognised = true;
@@ -989,13 +1000,13 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                     || int_type_of_word(name).is_some()
                 {
                     recognised = true;
-                    sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
+                    sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
                         span: item.span(),
                         name: name.to_ident_string(),
                     });
                 }
                 if let Some(literal_error) = literal_error {
-                    sess.emit_err(session_diagnostics::InvalidReprGeneric {
+                    sess.dcx().emit_err(session_diagnostics::InvalidReprGeneric {
                         span: item.span(),
                         repr_arg: name.to_ident_string(),
                         error_part: literal_error,
@@ -1007,7 +1018,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                         if meta_item.has_name(sym::align) || meta_item.has_name(sym::packed) {
                             let name = meta_item.name_or_empty().to_ident_string();
                             recognised = true;
-                            sess.emit_err(session_diagnostics::IncorrectReprFormatGeneric {
+                            sess.dcx().emit_err(session_diagnostics::IncorrectReprFormatGeneric {
                                 span: item.span(),
                                 repr_arg: &name,
                                 cause: IncorrectReprFormatGenericCause::from_lit_kind(
@@ -1022,7 +1033,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                         ) || int_type_of_word(meta_item.name_or_empty()).is_some()
                         {
                             recognised = true;
-                            sess.emit_err(session_diagnostics::InvalidReprHintNoValue {
+                            sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoValue {
                                 span: meta_item.span,
                                 name: meta_item.name_or_empty().to_ident_string(),
                             });
@@ -1031,12 +1042,14 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                     MetaItemKind::List(_) => {
                         if meta_item.has_name(sym::align) {
                             recognised = true;
-                            sess.emit_err(session_diagnostics::IncorrectReprFormatAlignOneArg {
-                                span: meta_item.span,
-                            });
+                            sess.dcx().emit_err(
+                                session_diagnostics::IncorrectReprFormatAlignOneArg {
+                                    span: meta_item.span,
+                                },
+                            );
                         } else if meta_item.has_name(sym::packed) {
                             recognised = true;
-                            sess.emit_err(
+                            sess.dcx().emit_err(
                                 session_diagnostics::IncorrectReprFormatPackedOneOrZeroArg {
                                     span: meta_item.span,
                                 },
@@ -1047,7 +1060,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                         ) || int_type_of_word(meta_item.name_or_empty()).is_some()
                         {
                             recognised = true;
-                            sess.emit_err(session_diagnostics::InvalidReprHintNoParen {
+                            sess.dcx().emit_err(session_diagnostics::InvalidReprHintNoParen {
                                 span: meta_item.span,
                                 name: meta_item.name_or_empty().to_ident_string(),
                             });
@@ -1062,7 +1075,7 @@ pub fn parse_repr_attr(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
                 // (e.g. if we only pretty-print the source), so we have to gate
                 // the `span_delayed_bug` call as follows:
                 if sess.opts.pretty.map_or(true, |pp| pp.needs_analysis()) {
-                    diagnostic.span_delayed_bug(item.span(), "unrecognized representation hint");
+                    dcx.span_delayed_bug(item.span(), "unrecognized representation hint");
                 }
             }
         }
@@ -1149,7 +1162,7 @@ fn allow_unstable<'a>(
     let list = attrs
         .filter_map(move |attr| {
             attr.meta_item_list().or_else(|| {
-                sess.emit_err(session_diagnostics::ExpectsFeatureList {
+                sess.dcx().emit_err(session_diagnostics::ExpectsFeatureList {
                     span: attr.span,
                     name: symbol.to_ident_string(),
                 });
@@ -1161,7 +1174,7 @@ fn allow_unstable<'a>(
     list.into_iter().filter_map(move |it| {
         let name = it.ident().map(|ident| ident.name);
         if name.is_none() {
-            sess.emit_err(session_diagnostics::ExpectsFeatures {
+            sess.dcx().emit_err(session_diagnostics::ExpectsFeatures {
                 span: it.span(),
                 name: symbol.to_ident_string(),
             });
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index e527a91eb6f20..900b789101961 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -1,10 +1,12 @@
-use rustc_errors::{
-    struct_span_err, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, MultiSpan,
-};
+use rustc_errors::{struct_span_err, DiagCtxt, DiagnosticBuilder};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
 
 impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
+    pub fn dcx(&self) -> &'tcx DiagCtxt {
+        self.infcx.dcx()
+    }
+
     pub(crate) fn cannot_move_when_borrowed(
         &self,
         span: Span,
@@ -13,7 +15,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         borrow_place: &str,
         value_place: &str,
     ) -> DiagnosticBuilder<'tcx> {
-        self.infcx.tcx.sess.create_err(crate::session_diagnostics::MoveBorrow {
+        self.dcx().create_err(crate::session_diagnostics::MoveBorrow {
             place,
             span,
             borrow_place,
@@ -30,7 +32,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         borrow_desc: &str,
     ) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             span,
             E0503,
             "cannot use {} because it was mutably borrowed",
@@ -53,7 +55,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
     ) -> DiagnosticBuilder<'tcx> {
         let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             new_loan_span,
             E0499,
             "cannot borrow {}{} as mutable more than once at a time",
@@ -99,7 +101,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         old_load_end_span: Option<Span>,
     ) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             new_loan_span,
             E0524,
             "two closures require unique access to {} at the same time",
@@ -132,7 +134,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         previous_end_span: Option<Span>,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             new_loan_span,
             E0500,
             "closure requires unique access to {} but {} is already borrowed{}",
@@ -164,7 +166,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         second_borrow_desc: &str,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             new_loan_span,
             E0501,
             "cannot borrow {}{} as {} because previous closure requires unique access",
@@ -197,7 +199,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
     ) -> DiagnosticBuilder<'cx> {
         let via = |msg: &str| if msg.is_empty() { "".to_string() } else { format!(" (via {msg})") };
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             span,
             E0502,
             "cannot borrow {}{} as {} because {} is also borrowed as {}{}",
@@ -237,7 +239,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         desc: &str,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             span,
             E0506,
             "cannot assign to {} because it is borrowed",
@@ -256,11 +258,11 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         is_arg: bool,
     ) -> DiagnosticBuilder<'cx> {
         let msg = if is_arg { "to immutable argument" } else { "twice to immutable variable" };
-        struct_span_err!(self, span, E0384, "cannot assign {} {}", msg, desc)
+        struct_span_err!(self.dcx(), span, E0384, "cannot assign {} {}", msg, desc)
     }
 
     pub(crate) fn cannot_assign(&self, span: Span, desc: &str) -> DiagnosticBuilder<'tcx> {
-        struct_span_err!(self, span, E0594, "cannot assign to {}", desc)
+        struct_span_err!(self.dcx(), span, E0594, "cannot assign to {}", desc)
     }
 
     pub(crate) fn cannot_move_out_of(
@@ -268,7 +270,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         move_from_span: Span,
         move_from_desc: &str,
     ) -> DiagnosticBuilder<'cx> {
-        struct_span_err!(self, move_from_span, E0507, "cannot move out of {}", move_from_desc)
+        struct_span_err!(self.dcx(), move_from_span, E0507, "cannot move out of {}", move_from_desc)
     }
 
     /// Signal an error due to an attempt to move out of the interior
@@ -286,7 +288,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
             _ => span_bug!(move_from_span, "this path should not cause illegal move"),
         };
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             move_from_span,
             E0508,
             "cannot move out of type `{}`, a non-copy {}",
@@ -303,7 +305,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         container_ty: Ty<'_>,
     ) -> DiagnosticBuilder<'cx> {
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             move_from_span,
             E0509,
             "cannot move out of type `{}`, which implements the `Drop` trait",
@@ -323,7 +325,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         let moved_path = moved_path.map(|mp| format!(": `{mp}`")).unwrap_or_default();
 
         struct_span_err!(
-            self,
+            self.dcx(),
             use_span,
             E0382,
             "{} of {}moved value{}",
@@ -339,7 +341,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         path: &str,
         reason: &str,
     ) -> DiagnosticBuilder<'tcx> {
-        struct_span_err!(self, span, E0596, "cannot borrow {} as mutable{}", path, reason,)
+        struct_span_err!(self.dcx(), span, E0596, "cannot borrow {} as mutable{}", path, reason)
     }
 
     pub(crate) fn cannot_mutate_in_immutable_section(
@@ -351,7 +353,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         action: &str,
     ) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             mutate_span,
             E0510,
             "cannot {} {} in {}",
@@ -371,7 +373,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
     ) -> DiagnosticBuilder<'tcx> {
         let coroutine_kind = self.body.coroutine.as_ref().unwrap().coroutine_kind;
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             span,
             E0626,
             "borrow may still be in use when {coroutine_kind:#} yields",
@@ -385,7 +387,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         borrow_span: Span,
     ) -> DiagnosticBuilder<'tcx> {
         struct_span_err!(
-            self,
+            self.dcx(),
             borrow_span,
             E0713,
             "borrow may still be in use when destructor runs",
@@ -397,7 +399,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         span: Span,
         path: &str,
     ) -> DiagnosticBuilder<'tcx> {
-        struct_span_err!(self, span, E0597, "{} does not live long enough", path,)
+        struct_span_err!(self.dcx(), span, E0597, "{} does not live long enough", path,)
     }
 
     pub(crate) fn cannot_return_reference_to_local(
@@ -408,7 +410,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         path_desc: &str,
     ) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             span,
             E0515,
             "cannot {RETURN} {REFERENCE} {LOCAL}",
@@ -434,7 +436,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         scope: &str,
     ) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
-            self,
+            self.dcx(),
             closure_span,
             E0373,
             "{closure_kind} may outlive the current {scope}, but it borrows {borrowed_path}, \
@@ -449,25 +451,19 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
         &self,
         span: Span,
     ) -> DiagnosticBuilder<'tcx> {
-        struct_span_err!(self, span, E0712, "thread-local variable borrowed past end of function",)
+        struct_span_err!(
+            self.dcx(),
+            span,
+            E0712,
+            "thread-local variable borrowed past end of function",
+        )
     }
 
     pub(crate) fn temporary_value_borrowed_for_too_long(
         &self,
         span: Span,
     ) -> DiagnosticBuilder<'tcx> {
-        struct_span_err!(self, span, E0716, "temporary value dropped while borrowed",)
-    }
-
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub(crate) fn struct_span_err_with_code<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-        code: DiagnosticId,
-    ) -> DiagnosticBuilder<'tcx> {
-        self.infcx.tcx.sess.struct_span_err_with_code(sp, msg, code)
+        struct_span_err!(self.dcx(), span, E0716, "temporary value dropped while borrowed",)
     }
 }
 
@@ -477,7 +473,7 @@ pub(crate) fn borrowed_data_escapes_closure<'tcx>(
     escapes_from: &str,
 ) -> DiagnosticBuilder<'tcx> {
     struct_span_err!(
-        tcx.sess,
+        tcx.dcx(),
         escape_span,
         E0521,
         "borrowed data escapes outside of {}",
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index e6881316a8f5b..bb5335febbf5e 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -77,7 +77,7 @@ impl<'tcx> UniverseInfo<'tcx> {
                 // up in the existing UI tests. Consider investigating this
                 // some more.
                 mbcx.buffer_error(
-                    mbcx.infcx.tcx.sess.create_err(HigherRankedSubtypeError { span: cause.span }),
+                    mbcx.dcx().create_err(HigherRankedSubtypeError { span: cause.span }),
                 );
             }
         }
@@ -221,7 +221,7 @@ struct PredicateQuery<'tcx> {
 
 impl<'tcx> TypeOpInfo<'tcx> for PredicateQuery<'tcx> {
     fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        tcx.sess.create_err(HigherRankedLifetimeError {
+        tcx.dcx().create_err(HigherRankedLifetimeError {
             cause: Some(HigherRankedErrorCause::CouldNotProve {
                 predicate: self.canonical_query.value.value.predicate.to_string(),
             }),
@@ -258,7 +258,7 @@ where
     T: Copy + fmt::Display + TypeFoldable<TyCtxt<'tcx>> + 'tcx,
 {
     fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        tcx.sess.create_err(HigherRankedLifetimeError {
+        tcx.dcx().create_err(HigherRankedLifetimeError {
             cause: Some(HigherRankedErrorCause::CouldNotNormalize {
                 value: self.canonical_query.value.value.value.to_string(),
             }),
@@ -303,7 +303,7 @@ impl<'tcx> TypeOpInfo<'tcx> for AscribeUserTypeQuery<'tcx> {
     fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
         // and is only the fallback when the nice error fails. Consider improving this some more.
-        tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span })
+        tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span })
     }
 
     fn base_universe(&self) -> ty::UniverseIndex {
@@ -329,7 +329,7 @@ impl<'tcx> TypeOpInfo<'tcx> for crate::type_check::InstantiateOpaqueType<'tcx> {
     fn fallback_error(&self, tcx: TyCtxt<'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         // FIXME: This error message isn't great, but it doesn't show up in the existing UI tests,
         // and is only the fallback when the nice error fails. Consider improving this some more.
-        tcx.sess.create_err(HigherRankedLifetimeError { cause: None, span })
+        tcx.dcx().create_err(HigherRankedLifetimeError { cause: None, span })
     }
 
     fn base_universe(&self) -> ty::UniverseIndex {
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 1577b2896c3db..da6fffc167c72 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -551,7 +551,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         let used = desired_action.as_general_verb_in_past_tense();
         let mut err =
-            struct_span_err!(self, span, E0381, "{used} binding {desc}{isnt_initialized}");
+            struct_span_err!(self.dcx(), span, E0381, "{used} binding {desc}{isnt_initialized}");
         use_spans.var_path_only_subdiag(&mut err, desired_action);
 
         if let InitializationRequiringAction::PartialAssignment
@@ -1136,7 +1136,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             });
         } else {
             issued_spans.var_subdiag(
-                Some(self.infcx.tcx.sess.dcx()),
+                Some(self.dcx()),
                 &mut err,
                 Some(issued_borrow.kind),
                 |kind, var_span| {
@@ -1153,7 +1153,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             );
 
             borrow_spans.var_subdiag(
-                Some(self.infcx.tcx.sess.dcx()),
+                Some(self.dcx()),
                 &mut err,
                 Some(gen_borrow_kind),
                 |kind, var_span| {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index ee32136547053..65dee9d0e0098 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -124,7 +124,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                         let did = did.expect_local();
                         if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
                             diag.eager_subdiagnostic(
-                                self.infcx.tcx.sess.dcx(),
+                                self.dcx(),
                                 OnClosureNote::InvokedTwice {
                                     place_name: &ty::place_to_string_for_capture(
                                         self.infcx.tcx,
@@ -146,7 +146,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 let did = did.expect_local();
                 if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
                     diag.eager_subdiagnostic(
-                        self.infcx.tcx.sess.dcx(),
+                        self.dcx(),
                         OnClosureNote::MovedTwice {
                             place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
                             span: *span,
@@ -1150,7 +1150,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                             && self.infcx.can_eq(self.param_env, ty, self_ty)
                         {
                             err.eager_subdiagnostic(
-                                self.infcx.tcx.sess.dcx(),
+                                self.dcx(),
                                 CaptureReasonSuggest::FreshReborrow {
                                     span: move_span.shrink_to_hi(),
                                 },
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index 66275888c5056..ad66c677c78f5 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -206,7 +206,7 @@ impl OutlivesSuggestionBuilder {
         // If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
         // list of diagnostics.
         let mut diag = if suggested.len() == 1 {
-            mbcx.infcx.tcx.sess.dcx().struct_help(match suggested.last().unwrap() {
+            mbcx.dcx().struct_help(match suggested.last().unwrap() {
                 SuggestedConstraint::Outlives(a, bs) => {
                     let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
                     format!("add bound `{a}: {}`", bs.join(" + "))
@@ -222,7 +222,6 @@ impl OutlivesSuggestionBuilder {
             let mut diag = mbcx
                 .infcx
                 .tcx
-                .sess
                 .dcx()
                 .struct_help("the following changes may resolve your lifetime errors");
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index f0b773b17ba0e..8387eaed61c79 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -84,7 +84,7 @@ impl<'tcx> RegionErrors<'tcx> {
     #[track_caller]
     pub fn push(&mut self, val: impl Into<RegionErrorKind<'tcx>>) {
         let val = val.into();
-        self.1.sess.span_delayed_bug(DUMMY_SP, format!("{val:?}"));
+        self.1.sess.dcx().span_delayed_bug(DUMMY_SP, format!("{val:?}"));
         self.0.push(val);
     }
     pub fn is_empty(&self) -> bool {
@@ -327,11 +327,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                         // to report it; we could probably handle it by
                         // iterating over the universal regions and reporting
                         // an error that multiple bounds are required.
-                        let mut diag =
-                            self.infcx.tcx.sess.create_err(GenericDoesNotLiveLongEnough {
-                                kind: type_test.generic_kind.to_string(),
-                                span: type_test_span,
-                            });
+                        let mut diag = self.dcx().create_err(GenericDoesNotLiveLongEnough {
+                            kind: type_test.generic_kind.to_string(),
+                            span: type_test_span,
+                        });
 
                         // Add notes and suggestions for the case of 'static lifetime
                         // implied but not specified when a generic associated types
@@ -596,7 +595,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             },
         };
 
-        let mut diag = self.infcx.tcx.sess.create_err(err);
+        let mut diag = self.dcx().create_err(err);
 
         if let ReturnConstraint::ClosureUpvar(upvar_field) = kind {
             let def_id = match self.regioncx.universal_regions().defining_ty {
@@ -758,7 +757,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let mir_def_name = self.infcx.tcx.def_descr(self.mir_def_id().to_def_id());
 
         let err = LifetimeOutliveErr { span: *span };
-        let mut diag = self.infcx.tcx.sess.create_err(err);
+        let mut diag = self.dcx().create_err(err);
 
         // In certain scenarios, such as the one described in issue #118021,
         // we might encounter a lifetime that cannot be named.
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 78d84f468e026..73dc7a9600f1a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -620,7 +620,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
                 ) => {
                     // HIR lowering sometimes doesn't catch this in erroneous
                     // programs, so we need to use span_delayed_bug here. See #82126.
-                    self.infcx.tcx.sess.span_delayed_bug(
+                    self.dcx().span_delayed_bug(
                         hir_arg.span(),
                         format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"),
                     );
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index cf2d2ca74655b..af21847cffd1e 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2134,7 +2134,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     // dereferencing a non-Copy raw pointer *and* have `-Ztreat-err-as-bug`
                     // enabled. We don't want to ICE for that case, as other errors will have
                     // been emitted (#52262).
-                    self.infcx.tcx.sess.span_delayed_bug(
+                    self.dcx().span_delayed_bug(
                         span,
                         format!(
                             "Accessing `{place:?}` with the kind `{kind:?}` shouldn't be possible",
@@ -2428,7 +2428,7 @@ mod error {
 
         pub fn buffer_error(&mut self, t: DiagnosticBuilder<'_>) {
             if let None = self.tainted_by_errors {
-                self.tainted_by_errors = Some(self.tcx.sess.span_delayed_bug(
+                self.tainted_by_errors = Some(self.tcx.dcx().span_delayed_bug(
                     t.span.clone_ignoring_labels(),
                     "diagnostic buffered but not emitted",
                 ))
@@ -2497,8 +2497,9 @@ mod error {
             if !self.errors.buffered.is_empty() {
                 self.errors.buffered.sort_by_key(|diag| diag.sort_span);
 
+                let dcx = self.dcx();
                 for diag in self.errors.buffered.drain(..) {
-                    self.infcx.tcx.sess.dcx().emit_diagnostic(diag);
+                    dcx.emit_diagnostic(diag);
                 }
             }
 
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 6781c6a756f44..5b764495922ba 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -187,7 +187,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
 
     if !nll_errors.is_empty() {
         // Suppress unhelpful extra errors in `infer_opaque_types`.
-        infcx.set_tainted_by_errors(infcx.tcx.sess.span_delayed_bug(
+        infcx.set_tainted_by_errors(infcx.dcx().span_delayed_bug(
             body.span,
             "`compute_regions` tainted `infcx` with errors but did not emit any errors",
         ));
@@ -280,7 +280,7 @@ pub(super) fn dump_annotation<'tcx>(
 
     let def_span = tcx.def_span(body.source.def_id());
     let mut err = if let Some(closure_region_requirements) = closure_region_requirements {
-        let mut err = tcx.sess.dcx().struct_span_note(def_span, "external requirements");
+        let mut err = tcx.dcx().struct_span_note(def_span, "external requirements");
 
         regioncx.annotate(tcx, &mut err);
 
@@ -299,7 +299,7 @@ pub(super) fn dump_annotation<'tcx>(
 
         err
     } else {
-        let mut err = tcx.sess.dcx().struct_span_note(def_span, "no external requirements");
+        let mut err = tcx.dcx().struct_span_note(def_span, "no external requirements");
         regioncx.annotate(tcx, &mut err);
 
         err
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 3764e4c400865..093017ecba235 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -402,7 +402,7 @@ fn check_opaque_type_parameter_valid(
             let opaque_param = opaque_generics.param_at(i, tcx);
             let kind = opaque_param.kind.descr();
 
-            return Err(tcx.sess.emit_err(NonGenericOpaqueTypeParam {
+            return Err(tcx.dcx().emit_err(NonGenericOpaqueTypeParam {
                 ty: arg,
                 kind,
                 span,
@@ -419,7 +419,7 @@ fn check_opaque_type_parameter_valid(
                 .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
                 .collect();
             return Err(tcx
-                .sess
+                .dcx()
                 .struct_span_err(span, "non-defining opaque type use in defining scope")
                 .span_note(spans, format!("{descr} used multiple times"))
                 .emit());
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 8e141bb3864ce..f717d91c35c60 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -76,7 +76,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         for (argument_index, &normalized_input_ty) in normalized_input_tys.iter().enumerate() {
             if argument_index + 1 >= body.local_decls.len() {
                 self.tcx()
-                    .sess
+                    .dcx()
                     .span_delayed_bug(body.span, "found more normalized_input_ty than local_decls");
                 break;
             }
@@ -104,7 +104,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         // outside of a coroutine and return an `impl Trait`, so emit a span_delayed_bug
         // because we don't want to panic in an assert here if we've already got errors.
         if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
-            self.tcx().sess.span_delayed_bug(
+            self.tcx().dcx().span_delayed_bug(
                 body.span,
                 format!(
                     "Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 5247d5f69815e..8a862953fba21 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -224,7 +224,7 @@ pub(crate) fn type_check<'mir, 'tcx>(
             let mut hidden_type = infcx.resolve_vars_if_possible(decl.hidden_type);
             trace!("finalized opaque type {:?} to {:#?}", opaque_type_key, hidden_type.ty.kind());
             if hidden_type.has_non_region_infer() {
-                let reported = infcx.tcx.sess.span_delayed_bug(
+                let reported = infcx.dcx().span_delayed_bug(
                     decl.hidden_type.span,
                     format!("could not resolve {:#?}", hidden_type.ty.kind()),
                 );
@@ -268,7 +268,7 @@ fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: String) {
     // We sometimes see MIR failures (notably predicate failures) due to
     // the fact that we check rvalue sized predicates here. So use `span_delayed_bug`
     // to avoid reporting bugs in those cases.
-    tcx.sess.dcx().span_delayed_bug(span, msg);
+    tcx.dcx().span_delayed_bug(span, msg);
 }
 
 enum FieldAccessError {
@@ -1067,7 +1067,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
         );
 
         if result.is_err() {
-            self.infcx.tcx.sess.span_delayed_bug(
+            self.infcx.dcx().span_delayed_bug(
                 self.body.span,
                 "failed re-defining predefined opaques in mir typeck",
             );
@@ -1573,7 +1573,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                     sym::simd_shuffle => {
                         if !matches!(args[2], Operand::Constant(_)) {
                             self.tcx()
-                                .sess
+                                .dcx()
                                 .emit_err(SimdShuffleLastConst { span: term.source_info.span });
                         }
                     }
@@ -1752,7 +1752,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                 // While this is located in `nll::typeck` this error is not
                 // an NLL error, it's a required check to prevent creation
                 // of unsized rvalues in a call expression.
-                self.tcx().sess.emit_err(MoveUnsized { ty, span });
+                self.tcx().dcx().emit_err(MoveUnsized { ty, span });
             }
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index dffda8acc8d06..bc94e0b972b47 100644
--- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -31,7 +31,7 @@ pub fn expand(
     {
         (item, true, ecx.with_def_site_ctxt(fn_kind.sig.span))
     } else {
-        ecx.sess.dcx().emit_err(errors::AllocErrorMustBeFn { span: item.span() });
+        ecx.dcx().emit_err(errors::AllocErrorMustBeFn { span: item.span() });
         return vec![orig_item];
     };
 
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 6f1acd8e57039..b5801c1b0f168 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -422,7 +422,7 @@ fn parse_reg<'a>(
             ast::InlineAsmRegOrRegClass::Reg(symbol)
         }
         _ => {
-            return Err(p.sess.create_err(errors::ExpectedRegisterClassOrExplicitRegister {
+            return Err(p.dcx().create_err(errors::ExpectedRegisterClassOrExplicitRegister {
                 span: p.token.span,
             }));
         }
@@ -541,7 +541,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
             let err = parser.errors.remove(0);
             let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
             let msg = format!("invalid asm template string: {}", err.description);
-            let mut e = ecx.struct_span_err(err_sp, msg);
+            let mut e = ecx.dcx().struct_span_err(err_sp, msg);
             e.span_label(err_sp, err.label + " in asm template string");
             if let Some(note) = err.note {
                 e.note(note);
@@ -575,7 +575,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                                 || args.reg_args.contains(idx)
                             {
                                 let msg = format!("invalid reference to argument at index {idx}");
-                                let mut err = ecx.struct_span_err(span, msg);
+                                let mut err = ecx.dcx().struct_span_err(span, msg);
                                 err.span_label(span, "from here");
 
                                 let positional_args = args.operands.len()
@@ -625,12 +625,13 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                                 None => {
                                     let msg = format!("there is no argument named `{name}`");
                                     let span = arg.position_span;
-                                    ecx.struct_span_err(
-                                        template_span
-                                            .from_inner(InnerSpan::new(span.start, span.end)),
-                                        msg,
-                                    )
-                                    .emit();
+                                    ecx.dcx()
+                                        .struct_span_err(
+                                            template_span
+                                                .from_inner(InnerSpan::new(span.start, span.end)),
+                                            msg,
+                                        )
+                                        .emit();
                                     None
                                 }
                             }
@@ -645,7 +646,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
                             .ty_span
                             .map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
                             .unwrap_or(template_sp);
-                        ecx.emit_err(errors::AsmModifierInvalid { span });
+                        ecx.dcx().emit_err(errors::AsmModifierInvalid { span });
                         modifier = None;
                     }
 
@@ -692,7 +693,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
         0 => {}
         1 => {
             let (sp, msg) = unused_operands.into_iter().next().unwrap();
-            let mut err = ecx.struct_span_err(sp, msg);
+            let mut err = ecx.dcx().struct_span_err(sp, msg);
             err.span_label(sp, msg);
             err.help(format!(
                 "if this argument is intentionally unused, \
@@ -701,7 +702,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
             err.emit();
         }
         _ => {
-            let mut err = ecx.struct_span_err(
+            let mut err = ecx.dcx().struct_span_err(
                 unused_operands.iter().map(|&(sp, _)| sp).collect::<Vec<Span>>(),
                 "multiple unused asm arguments",
             );
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 7abfcc8c50cc9..8fa3fe5b3e6cf 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -115,7 +115,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
     let mut parser = cx.new_parser_from_tts(stream);
 
     if parser.token == token::Eof {
-        return Err(cx.create_err(errors::AssertRequiresBoolean { span: sp }));
+        return Err(cx.dcx().create_err(errors::AssertRequiresBoolean { span: sp }));
     }
 
     let cond_expr = parser.parse_expr()?;
@@ -128,7 +128,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
     //
     // Emit an error about semicolon and suggest removing it.
     if parser.token == token::Semi {
-        cx.emit_err(errors::AssertRequiresExpression { span: sp, token: parser.token.span });
+        cx.dcx().emit_err(errors::AssertRequiresExpression { span: sp, token: parser.token.span });
         parser.bump();
     }
 
@@ -141,7 +141,7 @@ fn parse_assert<'a>(cx: &mut ExtCtxt<'a>, sp: Span, stream: TokenStream) -> PRes
     let custom_message =
         if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token.kind {
             let comma = parser.prev_token.span.shrink_to_hi();
-            cx.emit_err(errors::AssertMissingComma { span: parser.token.span, comma });
+            cx.dcx().emit_err(errors::AssertMissingComma { span: parser.token.span, comma });
 
             parse_custom_message(&mut parser)
         } else if parser.eat(&token::Comma) {
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index 31cac51845faa..48be680b619f7 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -39,7 +39,7 @@ fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<
     let mut p = cx.new_parser_from_tts(tts);
 
     if p.token == token::Eof {
-        return Err(cx.create_err(errors::RequiresCfgPattern { span }));
+        return Err(cx.dcx().create_err(errors::RequiresCfgPattern { span }));
     }
 
     let cfg = p.parse_meta_item()?;
@@ -47,7 +47,7 @@ fn parse_cfg<'a>(cx: &mut ExtCtxt<'a>, span: Span, tts: TokenStream) -> PResult<
     let _ = p.eat(&token::Comma);
 
     if !p.eat(&token::Eof) {
-        return Err(cx.create_err(errors::OneCfgPattern { span }));
+        return Err(cx.dcx().create_err(errors::OneCfgPattern { span }));
     }
 
     Ok(cfg)
diff --git a/compiler/rustc_builtin_macros/src/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
index 64be8da590281..ceb5f86107845 100644
--- a/compiler/rustc_builtin_macros/src/cfg_accessible.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_accessible.rs
@@ -15,18 +15,18 @@ fn validate_input<'a>(ecx: &mut ExtCtxt<'_>, mi: &'a ast::MetaItem) -> Option<&'
     match mi.meta_item_list() {
         None => {}
         Some([]) => {
-            ecx.emit_err(UnspecifiedPath(mi.span));
+            ecx.dcx().emit_err(UnspecifiedPath(mi.span));
         }
         Some([_, .., l]) => {
-            ecx.emit_err(MultiplePaths(l.span()));
+            ecx.dcx().emit_err(MultiplePaths(l.span()));
         }
         Some([nmi]) => match nmi.meta_item() {
             None => {
-                ecx.emit_err(LiteralPath(nmi.span()));
+                ecx.dcx().emit_err(LiteralPath(nmi.span()));
             }
             Some(mi) => {
                 if !mi.is_word() {
-                    ecx.emit_err(HasArguments(mi.span));
+                    ecx.dcx().emit_err(HasArguments(mi.span));
                 }
                 return Some(&mi.path);
             }
@@ -61,7 +61,7 @@ impl MultiItemModifier for Expander {
             Ok(true) => ExpandResult::Ready(vec![item]),
             Ok(false) => ExpandResult::Ready(Vec::new()),
             Err(Indeterminate) if ecx.force_mode => {
-                ecx.emit_err(errors::CfgAccessibleIndeterminate { span });
+                ecx.dcx().emit_err(errors::CfgAccessibleIndeterminate { span });
                 ExpandResult::Ready(vec![item])
             }
             Err(Indeterminate) => ExpandResult::Retry(item),
diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs
index 5efc5a4e3eea3..f157575da79bc 100644
--- a/compiler/rustc_builtin_macros/src/compile_error.rs
+++ b/compiler/rustc_builtin_macros/src/compile_error.rs
@@ -18,7 +18,7 @@ pub fn expand_compile_error<'cx>(
         reason = "diagnostic message is specified by user"
     )]
     #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")]
-    cx.span_err(sp, var.to_string());
+    cx.dcx().span_err(sp, var.to_string());
 
     DummyResult::any(sp)
 }
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index 6b8330bfdaf92..dade29593af13 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -33,11 +33,11 @@ pub fn expand_concat(
                     accumulator.push_str(&b.to_string());
                 }
                 Ok(ast::LitKind::CStr(..)) => {
-                    cx.emit_err(errors::ConcatCStrLit { span: e.span });
+                    cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span });
                     has_errors = true;
                 }
                 Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
-                    cx.emit_err(errors::ConcatBytestr { span: e.span });
+                    cx.dcx().emit_err(errors::ConcatBytestr { span: e.span });
                     has_errors = true;
                 }
                 Ok(ast::LitKind::Err) => {
@@ -63,7 +63,7 @@ pub fn expand_concat(
                 }
             }
             ast::ExprKind::IncludedBytes(..) => {
-                cx.emit_err(errors::ConcatBytestr { span: e.span });
+                cx.dcx().emit_err(errors::ConcatBytestr { span: e.span });
             }
             ast::ExprKind::Err => {
                 has_errors = true;
@@ -75,7 +75,7 @@ pub fn expand_concat(
     }
 
     if !missing_literal.is_empty() {
-        cx.emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
+        cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal });
         return DummyResult::any(sp);
     } else if has_errors {
         return DummyResult::any(sp);
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index 96e9584c20955..4f7c0266343ca 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -17,16 +17,17 @@ fn invalid_type_err(
         ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob,
     };
     let snippet = cx.sess.source_map().span_to_snippet(span).ok();
+    let dcx = cx.dcx();
     match ast::LitKind::from_token_lit(token_lit) {
         Ok(ast::LitKind::CStr(_, _)) => {
             // Avoid ambiguity in handling of terminal `NUL` by refusing to
             // concatenate C string literals as bytes.
-            cx.emit_err(errors::ConcatCStrLit { span: span });
+            dcx.emit_err(errors::ConcatCStrLit { span: span });
         }
         Ok(ast::LitKind::Char(_)) => {
             let sugg =
                 snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
-            cx.sess.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg });
+            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg });
         }
         Ok(ast::LitKind::Str(_, _)) => {
             // suggestion would be invalid if we are nested
@@ -35,29 +36,29 @@ fn invalid_type_err(
             } else {
                 None
             };
-            cx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg });
+            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg });
         }
         Ok(ast::LitKind::Float(_, _)) => {
-            cx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None });
+            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None });
         }
         Ok(ast::LitKind::Bool(_)) => {
-            cx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None });
+            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None });
         }
         Ok(ast::LitKind::Err) => {}
         Ok(ast::LitKind::Int(_, _)) if !is_nested => {
             let sugg =
                 snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet });
-            cx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg });
+            dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg });
         }
         Ok(ast::LitKind::Int(
             val,
             ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8),
         )) => {
             assert!(val > u8::MAX.into()); // must be an error
-            cx.emit_err(ConcatBytesOob { span });
+            dcx.emit_err(ConcatBytesOob { span });
         }
         Ok(ast::LitKind::Int(_, _)) => {
-            cx.emit_err(ConcatBytesNonU8 { span });
+            dcx.emit_err(ConcatBytesNonU8 { span });
         }
         Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(),
         Err(err) => {
@@ -72,10 +73,11 @@ fn handle_array_element(
     missing_literals: &mut Vec<rustc_span::Span>,
     expr: &P<rustc_ast::Expr>,
 ) -> Option<u8> {
+    let dcx = cx.dcx();
     match expr.kind {
         ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => {
             if !*has_errors {
-                cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
+                dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
             }
             *has_errors = true;
             None
@@ -89,7 +91,7 @@ fn handle_array_element(
             Ok(ast::LitKind::Byte(val)) => Some(val),
             Ok(ast::LitKind::ByteStr(..)) => {
                 if !*has_errors {
-                    cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true });
+                    dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true });
                 }
                 *has_errors = true;
                 None
@@ -104,7 +106,7 @@ fn handle_array_element(
         },
         ast::ExprKind::IncludedBytes(..) => {
             if !*has_errors {
-                cx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
+                dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false });
             }
             *has_errors = true;
             None
@@ -151,7 +153,7 @@ pub fn expand_concat_bytes(
                         }
                     }
                 } else {
-                    cx.emit_err(errors::ConcatBytesBadRepeat { span: count.value.span });
+                    cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span });
                 }
             }
             &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
@@ -180,7 +182,7 @@ pub fn expand_concat_bytes(
         }
     }
     if !missing_literals.is_empty() {
-        cx.emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals });
+        cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals });
         return base::MacEager::expr(DummyResult::raw_expr(sp, true));
     } else if has_errors {
         return base::MacEager::expr(DummyResult::raw_expr(sp, true));
diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs
index ee56d45c9c826..17fd3901cc6bc 100644
--- a/compiler/rustc_builtin_macros/src/concat_idents.rs
+++ b/compiler/rustc_builtin_macros/src/concat_idents.rs
@@ -14,7 +14,7 @@ pub fn expand_concat_idents<'cx>(
     tts: TokenStream,
 ) -> Box<dyn base::MacResult + 'cx> {
     if tts.is_empty() {
-        cx.emit_err(errors::ConcatIdentsMissingArgs { span: sp });
+        cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp });
         return DummyResult::any(sp);
     }
 
@@ -24,7 +24,7 @@ pub fn expand_concat_idents<'cx>(
             match e {
                 TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
                 _ => {
-                    cx.emit_err(errors::ConcatIdentsMissingComma { span: sp });
+                    cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp });
                     return DummyResult::any(sp);
                 }
             }
@@ -36,7 +36,7 @@ pub fn expand_concat_idents<'cx>(
                 }
             }
 
-            cx.emit_err(errors::ConcatIdentsIdentArgs { span: sp });
+            cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp });
             return DummyResult::any(sp);
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/derive.rs b/compiler/rustc_builtin_macros/src/derive.rs
index 5a77c3276e2a8..7388e133c53e2 100644
--- a/compiler/rustc_builtin_macros/src/derive.rs
+++ b/compiler/rustc_builtin_macros/src/derive.rs
@@ -120,7 +120,7 @@ fn report_bad_target(
     let bad_target =
         !matches!(item_kind, Some(ItemKind::Struct(..) | ItemKind::Enum(..) | ItemKind::Union(..)));
     if bad_target {
-        return Err(sess.emit_err(errors::BadDeriveTarget { span, item: item.span() }));
+        return Err(sess.dcx().emit_err(errors::BadDeriveTarget { span, item: item.span() }));
     }
     Ok(())
 }
@@ -134,7 +134,7 @@ fn report_unexpected_meta_item_lit(sess: &Session, lit: &ast::MetaItemLit) {
         }
         _ => errors::BadDeriveLitHelp::Other,
     };
-    sess.emit_err(errors::BadDeriveLit { span: lit.span, help });
+    sess.dcx().emit_err(errors::BadDeriveLit { span: lit.span, help });
 }
 
 fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
@@ -143,10 +143,10 @@ fn report_path_args(sess: &Session, meta: &ast::MetaItem) {
     match meta.kind {
         MetaItemKind::Word => {}
         MetaItemKind::List(..) => {
-            sess.emit_err(errors::DerivePathArgsList { span });
+            sess.dcx().emit_err(errors::DerivePathArgsList { span });
         }
         MetaItemKind::NameValue(..) => {
-            sess.emit_err(errors::DerivePathArgsValue { span });
+            sess.dcx().emit_err(errors::DerivePathArgsValue { span });
         }
     }
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index 467fa5a2b15e8..7bf19f6116686 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -62,10 +62,10 @@ pub fn expand_deriving_clone(
                     cs_clone_simple("Clone", c, s, sub, true)
                 }));
             }
-            _ => cx.span_bug(span, "`#[derive(Clone)]` on wrong item kind"),
+            _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on wrong item kind"),
         },
 
-        _ => cx.span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
+        _ => cx.dcx().span_bug(span, "`#[derive(Clone)]` on trait item or impl item"),
     }
 
     let trait_def = TraitDef {
@@ -144,7 +144,7 @@ fn cs_clone_simple(
                     process_variant(&variant.data);
                 }
             }
-            _ => cx.span_bug(
+            _ => cx.dcx().span_bug(
                 trait_span,
                 format!("unexpected substructure in simple `derive({name})`"),
             ),
@@ -180,10 +180,10 @@ fn cs_clone(
             vdata = &variant.data;
         }
         EnumTag(..) | AllFieldlessEnum(..) => {
-            cx.span_bug(trait_span, format!("enum tags in `derive({name})`",))
+            cx.dcx().span_bug(trait_span, format!("enum tags in `derive({name})`",))
         }
         StaticEnum(..) | StaticStruct(..) => {
-            cx.span_bug(trait_span, format!("associated function in `derive({name})`"))
+            cx.dcx().span_bug(trait_span, format!("associated function in `derive({name})`"))
         }
     }
 
@@ -193,7 +193,7 @@ fn cs_clone(
                 .iter()
                 .map(|field| {
                     let Some(ident) = field.name else {
-                        cx.span_bug(
+                        cx.dcx().span_bug(
                             trait_span,
                             format!("unnamed field in normal struct in `derive({name})`",),
                         );
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
index 8a6d219379fca..14ae999427dff 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs
@@ -99,7 +99,7 @@ fn cs_total_eq_assert(
                 process_variant(&variant.data);
             }
         }
-        _ => cx.span_bug(trait_span, "unexpected substructure in `derive(Eq)`"),
+        _ => cx.dcx().span_bug(trait_span, "unexpected substructure in `derive(Eq)`"),
     }
     BlockOrExpr::new_stmts(stmts)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
index ea81cee78b716..0923acfeeddb8 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs
@@ -61,7 +61,7 @@ pub fn cs_cmp(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>) -> Bl
         |cx, fold| match fold {
             CsFold::Single(field) => {
                 let [other_expr] = &field.other_selflike_exprs[..] else {
-                    cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
+                    cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
                 };
                 let args = thin_vec![field.self_expr.clone(), other_expr.clone()];
                 cx.expr_call_global(field.span, cmp_path.clone(), args)
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index a170468b4139a..006110cd4b1f6 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -26,7 +26,8 @@ pub fn expand_deriving_partial_eq(
             |cx, fold| match fold {
                 CsFold::Single(field) => {
                     let [other_expr] = &field.other_selflike_exprs[..] else {
-                        cx.span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
+                        cx.dcx()
+                            .span_bug(field.span, "not exactly 2 arguments in `derive(PartialEq)`");
                     };
 
                     // We received arguments of type `&T`. Convert them to type `T` by stripping
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
index 7f5589210d41b..6eccd67f8af19 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs
@@ -95,7 +95,7 @@ fn cs_partial_cmp(
         |cx, fold| match fold {
             CsFold::Single(field) => {
                 let [other_expr] = &field.other_selflike_exprs[..] else {
-                    cx.span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
+                    cx.dcx().span_bug(field.span, "not exactly 2 arguments in `derive(Ord)`");
                 };
                 let args = thin_vec![field.self_expr.clone(), other_expr.clone()];
                 cx.expr_call_global(field.span, partial_cmp_path.clone(), args)
diff --git a/compiler/rustc_builtin_macros/src/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs
index 50ea862886157..b11a1b6cda154 100644
--- a/compiler/rustc_builtin_macros/src/deriving/debug.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs
@@ -55,7 +55,7 @@ fn show_substructure(cx: &mut ExtCtxt<'_>, span: Span, substr: &Substructure<'_>
         EnumMatching(_, _, v, fields) => (v.ident, &v.data, fields),
         AllFieldlessEnum(enum_def) => return show_fieldless_enum(cx, span, enum_def, substr),
         EnumTag(..) | StaticStruct(..) | StaticEnum(..) => {
-            cx.span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
+            cx.dcx().span_bug(span, "nonsensical .fields in `#[derive(Debug)]`")
         }
     };
 
diff --git a/compiler/rustc_builtin_macros/src/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
index bcf11cb4ce9d4..97d6b82de98c6 100644
--- a/compiler/rustc_builtin_macros/src/deriving/decodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/decodable.rs
@@ -177,7 +177,7 @@ fn decodable_substructure(
                 ],
             )
         }
-        _ => cx.bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
+        _ => cx.dcx().bug("expected StaticEnum or StaticStruct in derive(Decodable)"),
     };
     BlockOrExpr::new_expr(expr)
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs
index 43874a242f26a..d5a42566e1912 100644
--- a/compiler/rustc_builtin_macros/src/deriving/default.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/default.rs
@@ -41,7 +41,7 @@ pub fn expand_deriving_default(
                         default_struct_substructure(cx, trait_span, substr, fields)
                     }
                     StaticEnum(enum_def, _) => default_enum_substructure(cx, trait_span, enum_def),
-                    _ => cx.span_bug(trait_span, "method in `derive(Default)`"),
+                    _ => cx.dcx().span_bug(trait_span, "method in `derive(Default)`"),
                 }
             })),
         }],
@@ -120,7 +120,7 @@ fn extract_default_variant<'a>(
             let suggs = possible_defaults
                 .map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident })
                 .collect();
-            cx.emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
+            cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs });
 
             return Err(());
         }
@@ -140,7 +140,7 @@ fn extract_default_variant<'a>(
                         .then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident })
                 })
                 .collect();
-            cx.emit_err(errors::MultipleDefaults {
+            cx.dcx().emit_err(errors::MultipleDefaults {
                 span: trait_span,
                 first: first.span,
                 additional: rest.iter().map(|v| v.span).collect(),
@@ -151,12 +151,12 @@ fn extract_default_variant<'a>(
     };
 
     if !matches!(variant.data, VariantData::Unit(..)) {
-        cx.emit_err(errors::NonUnitDefault { span: variant.ident.span });
+        cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span });
         return Err(());
     }
 
     if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) {
-        cx.emit_err(errors::NonExhaustiveDefault {
+        cx.dcx().emit_err(errors::NonExhaustiveDefault {
             span: variant.ident.span,
             non_exhaustive: non_exhaustive_attr.span,
         });
@@ -176,14 +176,14 @@ fn validate_default_attribute(
 
     let attr = match attrs.as_slice() {
         [attr] => attr,
-        [] => cx.bug(
+        [] => cx.dcx().bug(
             "this method must only be called with a variant that has a `#[default]` attribute",
         ),
         [first, rest @ ..] => {
             let sugg = errors::MultipleDefaultAttrsSugg {
                 spans: rest.iter().map(|attr| attr.span).collect(),
             };
-            cx.emit_err(errors::MultipleDefaultAttrs {
+            cx.dcx().emit_err(errors::MultipleDefaultAttrs {
                 span: default_variant.ident.span,
                 first: first.span,
                 first_rest: rest[0].span,
@@ -196,7 +196,7 @@ fn validate_default_attribute(
         }
     };
     if !attr.is_word() {
-        cx.emit_err(errors::DefaultHasArg { span: attr.span });
+        cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span });
 
         return Err(());
     }
@@ -210,7 +210,7 @@ struct DetectNonVariantDefaultAttr<'a, 'b> {
 impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonVariantDefaultAttr<'a, 'b> {
     fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) {
         if attr.has_name(kw::Default) {
-            self.cx.emit_err(errors::NonUnitDefault { span: attr.span });
+            self.cx.dcx().emit_err(errors::NonUnitDefault { span: attr.span });
         }
 
         rustc_ast::visit::walk_attribute(self, attr);
diff --git a/compiler/rustc_builtin_macros/src/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
index 2dc20c324972b..14d93a8cc23c2 100644
--- a/compiler/rustc_builtin_macros/src/deriving/encodable.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/encodable.rs
@@ -296,6 +296,6 @@ fn encodable_substructure(
             BlockOrExpr::new_mixed(thin_vec![me], Some(expr))
         }
 
-        _ => cx.bug("expected Struct or EnumMatching in derive(Encodable)"),
+        _ => cx.dcx().bug("expected Struct or EnumMatching in derive(Encodable)"),
     }
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 841cac7814998..6eeb028728c9d 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -430,7 +430,7 @@ fn find_type_parameters(
         }
 
         fn visit_mac_call(&mut self, mac: &ast::MacCall) {
-            self.cx.emit_err(errors::DeriveMacroCall { span: mac.span() });
+            self.cx.dcx().emit_err(errors::DeriveMacroCall { span: mac.span() });
         }
     }
 
@@ -503,7 +503,7 @@ impl<'a> TraitDef<'a> {
                                 is_packed,
                             )
                         } else {
-                            cx.emit_err(errors::DeriveUnion { span: mitem.span });
+                            cx.dcx().emit_err(errors::DeriveUnion { span: mitem.span });
                             return;
                         }
                     }
@@ -974,7 +974,7 @@ impl<'a> MethodDef<'a> {
             match ty {
                 // Selflike (`&Self`) arguments only occur in non-static methods.
                 Ref(box Self_, _) if !self.is_static() => selflike_args.push(arg_expr),
-                Self_ => cx.span_bug(span, "`Self` in non-return position"),
+                Self_ => cx.dcx().span_bug(span, "`Self` in non-return position"),
                 _ => nonselflike_args.push(arg_expr),
             }
         }
@@ -1441,9 +1441,9 @@ impl<'a> TraitDef<'a> {
 
         let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..));
         match (just_spans.is_empty(), named_idents.is_empty()) {
-            (false, false) => {
-                cx.span_bug(self.span, "a struct with named and unnamed fields in generic `derive`")
-            }
+            (false, false) => cx
+                .dcx()
+                .span_bug(self.span, "a struct with named and unnamed fields in generic `derive`"),
             // named fields
             (_, false) => Named(named_idents),
             // unnamed fields
@@ -1489,7 +1489,7 @@ impl<'a> TraitDef<'a> {
                         let field_pats = pieces_iter
                             .map(|(sp, ident, pat)| {
                                 if ident.is_none() {
-                                    cx.span_bug(
+                                    cx.dcx().span_bug(
                                         sp,
                                         "a braced struct with unnamed fields in `derive`",
                                     );
@@ -1707,7 +1707,9 @@ where
                 tag_check_expr
             }
         }
-        StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
-        AllFieldlessEnum(..) => cx.span_bug(trait_span, "fieldless enum in `derive`"),
+        StaticEnum(..) | StaticStruct(..) => {
+            cx.dcx().span_bug(trait_span, "static function in `derive`")
+        }
+        AllFieldlessEnum(..) => cx.dcx().span_bug(trait_span, "fieldless enum in `derive`"),
     }
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
index 1a45c3279f751..603cefdd38629 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs
@@ -138,8 +138,8 @@ impl Ty {
                 cx.path_all(span, false, vec![self_ty], params)
             }
             Path(p) => p.to_path(cx, span, self_ty, generics),
-            Ref(..) => cx.span_bug(span, "ref in a path in generic `derive`"),
-            Unit => cx.span_bug(span, "unit in a path in generic `derive`"),
+            Ref(..) => cx.dcx().span_bug(span, "ref in a path in generic `derive`"),
+            Unit => cx.dcx().span_bug(span, "unit in a path in generic `derive`"),
         }
     }
 }
diff --git a/compiler/rustc_builtin_macros/src/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs
index 101401f9c85b7..dd6149cf61496 100644
--- a/compiler/rustc_builtin_macros/src/deriving/hash.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/hash.rs
@@ -52,7 +52,7 @@ fn hash_substructure(
     substr: &Substructure<'_>,
 ) -> BlockOrExpr {
     let [state_expr] = substr.nonselflike_args else {
-        cx.span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
+        cx.dcx().span_bug(trait_span, "incorrect number of arguments in `derive(Hash)`");
     };
     let call_hash = |span, expr| {
         let hash_path = {
@@ -75,7 +75,7 @@ fn hash_substructure(
             let stmts = thin_vec![call_hash(tag_field.span, tag_field.self_expr.clone())];
             (stmts, match_expr.clone())
         }
-        _ => cx.span_bug(trait_span, "impossible substructure in `derive(Hash)`"),
+        _ => cx.dcx().span_bug(trait_span, "impossible substructure in `derive(Hash)`"),
     };
 
     BlockOrExpr::new_mixed(stmts, match_expr)
diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs
index d772642b88b26..4b3eaf7855700 100644
--- a/compiler/rustc_builtin_macros/src/env.rs
+++ b/compiler/rustc_builtin_macros/src/env.rs
@@ -66,7 +66,7 @@ pub fn expand_env<'cx>(
 ) -> Box<dyn base::MacResult + 'cx> {
     let mut exprs = match get_exprs_from_tts(cx, tts) {
         Some(exprs) if exprs.is_empty() || exprs.len() > 2 => {
-            cx.emit_err(errors::EnvTakesArgs { span: sp });
+            cx.dcx().emit_err(errors::EnvTakesArgs { span: sp });
             return DummyResult::any(sp);
         }
         None => return DummyResult::any(sp),
@@ -101,15 +101,15 @@ pub fn expand_env<'cx>(
             };
 
             if let Some(msg_from_user) = custom_msg {
-                cx.emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user });
+                cx.dcx().emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user });
             } else if is_cargo_env_var(var.as_str()) {
-                cx.emit_err(errors::EnvNotDefined::CargoEnvVar {
+                cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar {
                     span,
                     var: *symbol,
                     var_expr: var_expr.ast_deref(),
                 });
             } else {
-                cx.emit_err(errors::EnvNotDefined::CustomEnvVar {
+                cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar {
                     span,
                     var: *symbol,
                     var_expr: var_expr.ast_deref(),
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 2f23146096fb3..a668db438eb2c 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -69,7 +69,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
     let mut p = ecx.new_parser_from_tts(tts);
 
     if p.token == token::Eof {
-        return Err(ecx.create_err(errors::FormatRequiresString { span: sp }));
+        return Err(ecx.dcx().create_err(errors::FormatRequiresString { span: sp }));
     }
 
     let first_token = &p.token;
@@ -126,7 +126,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
                 p.expect(&token::Eq)?;
                 let expr = p.parse_expr()?;
                 if let Some((_, prev)) = args.by_name(ident.name) {
-                    ecx.emit_err(errors::FormatDuplicateArg {
+                    ecx.dcx().emit_err(errors::FormatDuplicateArg {
                         span: ident.span,
                         prev: prev.kind.ident().unwrap().span,
                         duplicate: ident.span,
@@ -139,7 +139,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
             _ => {
                 let expr = p.parse_expr()?;
                 if !args.named_args().is_empty() {
-                    ecx.emit_err(errors::PositionalAfterNamed {
+                    ecx.dcx().emit_err(errors::PositionalAfterNamed {
                         span: expr.span,
                         args: args
                             .named_args()
@@ -293,7 +293,7 @@ fn make_format_args(
                 }
             }
         }
-        ecx.emit_err(e);
+        ecx.dcx().emit_err(e);
         return Err(());
     }
 
@@ -351,7 +351,7 @@ fn make_format_args(
                     } else {
                         // For the moment capturing variables from format strings expanded from macros is
                         // disabled (see RFC #2795)
-                        ecx.emit_err(errors::FormatNoArgNamed { span, name });
+                        ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name });
                         DummyResult::raw_expr(span, true)
                     };
                     Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr }))
@@ -529,7 +529,7 @@ fn make_format_args(
 
     // Only check for unused named argument names if there are no other errors to avoid causing
     // too much noise in output errors, such as when a named argument is entirely unused.
-    if invalid_refs.is_empty() && ecx.sess.err_count() == 0 {
+    if invalid_refs.is_empty() && ecx.dcx().err_count() == 0 {
         for &(index, span, used_as) in &numeric_refences_to_named_arg {
             let (position_sp_to_replace, position_sp_for_msg) = match used_as {
                 Placeholder(pspan) => (span, pspan),
@@ -585,7 +585,7 @@ fn invalid_placeholder_type_error(
     } else {
         vec![]
     };
-    ecx.emit_err(errors::FormatUnknownTrait { span: sp.unwrap_or(fmt_span), ty, suggs });
+    ecx.dcx().emit_err(errors::FormatUnknownTrait { span: sp.unwrap_or(fmt_span), ty, suggs });
 }
 
 fn report_missing_placeholders(
@@ -600,12 +600,12 @@ fn report_missing_placeholders(
     fmt_span: Span,
 ) {
     let mut diag = if let &[(span, named)] = &unused[..] {
-        ecx.create_err(errors::FormatUnusedArg { span, named })
+        ecx.dcx().create_err(errors::FormatUnusedArg { span, named })
     } else {
         let unused_labels =
             unused.iter().map(|&(span, named)| errors::FormatUnusedArg { span, named }).collect();
         let unused_spans = unused.iter().map(|&(span, _)| span).collect();
-        ecx.create_err(errors::FormatUnusedArgs {
+        ecx.dcx().create_err(errors::FormatUnusedArgs {
             fmt: fmt_span,
             unused: unused_spans,
             unused_labels,
@@ -776,7 +776,7 @@ fn report_redundant_format_arguments<'a>(
             None
         };
 
-        return Some(ecx.create_err(errors::FormatRedundantArgs {
+        return Some(ecx.dcx().create_err(errors::FormatRedundantArgs {
             n: args_spans.len(),
             span: MultiSpan::from(args_spans),
             note: multispan,
@@ -876,7 +876,7 @@ fn report_invalid_references(
         } else {
             MultiSpan::from_spans(spans)
         };
-        e = ecx.create_err(errors::FormatPositionalMismatch {
+        e = ecx.dcx().create_err(errors::FormatPositionalMismatch {
             span,
             n: num_placeholders,
             desc: num_args_desc,
@@ -942,7 +942,7 @@ fn report_invalid_references(
                 head = indexes.into_iter().map(|i| i.to_string()).collect::<Vec<_>>().join(", ")
             )
         };
-        e = ecx.struct_span_err(
+        e = ecx.dcx().struct_span_err(
             span,
             format!("invalid reference to positional {arg_list} ({num_args_desc})"),
         );
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 00c7907cdb49e..099defd511b5b 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -34,7 +34,7 @@ pub fn expand(
     {
         (item, true, ecx.with_def_site_ctxt(ty.span))
     } else {
-        ecx.sess.dcx().emit_err(errors::AllocMustStatics { span: item.span() });
+        ecx.dcx().emit_err(errors::AllocMustStatics { span: item.span() });
         return vec![orig_item];
     };
 
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 37808854a56f8..30f80bb87dd15 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -155,7 +155,7 @@ pub fn expand_include<'cx>(
                         if self.p.token != token::Eof {
                             let token = pprust::token_to_string(&self.p.token);
                             let msg = format!("expected item, found `{token}`");
-                            self.p.struct_span_err(self.p.token.span, msg).emit();
+                            self.p.dcx().struct_span_err(self.p.token.span, msg).emit();
                         }
 
                         break;
@@ -193,12 +193,12 @@ pub fn expand_include_str(
                 base::MacEager::expr(cx.expr_str(sp, interned_src))
             }
             Err(_) => {
-                cx.span_err(sp, format!("{} wasn't a utf-8 file", file.display()));
+                cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display()));
                 DummyResult::any(sp)
             }
         },
         Err(e) => {
-            cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
+            cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
             DummyResult::any(sp)
         }
     }
@@ -226,7 +226,7 @@ pub fn expand_include_bytes(
             base::MacEager::expr(expr)
         }
         Err(e) => {
-            cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
+            cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));
             DummyResult::any(sp)
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index d760cea59a712..2af46f175d7d8 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -43,7 +43,7 @@ pub fn expand_test_case(
             }
         }
         _ => {
-            ecx.emit_err(errors::TestCaseNonItem { span: anno_item.span() });
+            ecx.dcx().emit_err(errors::TestCaseNonItem { span: anno_item.span() });
             return vec![];
         }
     };
@@ -389,7 +389,7 @@ pub fn expand_test_or_bench(
 }
 
 fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) {
-    let dcx = cx.sess.dcx();
+    let dcx = cx.dcx();
     let msg = "the `#[test]` attribute may only be used on a non-associated function";
     let level = match item.map(|i| &i.kind) {
         // These were a warning before #92959 and need to continue being that to avoid breaking
@@ -465,8 +465,6 @@ fn should_ignore_message(i: &ast::Item) -> Option<Symbol> {
 fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
     match attr::find_by_name(&i.attrs, sym::should_panic) {
         Some(attr) => {
-            let dcx = cx.sess.dcx();
-
             match attr.meta_item_list() {
                 // Handle #[should_panic(expected = "foo")]
                 Some(list) => {
@@ -476,17 +474,18 @@ fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
                         .and_then(|mi| mi.meta_item())
                         .and_then(|mi| mi.value_str());
                     if list.len() != 1 || msg.is_none() {
-                        dcx.struct_span_warn(
-                            attr.span,
-                            "argument must be of the form: \
+                        cx.dcx()
+                            .struct_span_warn(
+                                attr.span,
+                                "argument must be of the form: \
                              `expected = \"error message\"`",
-                        )
-                        .note(
-                            "errors in this attribute were erroneously \
+                            )
+                            .note(
+                                "errors in this attribute were erroneously \
                                 allowed and will become a hard error in a \
                                 future release",
-                        )
-                        .emit();
+                            )
+                            .emit();
                         ShouldPanic::Yes(None)
                     } else {
                         ShouldPanic::Yes(msg)
@@ -534,7 +533,7 @@ fn check_test_signature(
     f: &ast::Fn,
 ) -> Result<(), ErrorGuaranteed> {
     let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
-    let dcx = cx.sess.dcx();
+    let dcx = cx.dcx();
 
     if let ast::Unsafe::Yes(span) = f.sig.header.unsafety {
         return Err(dcx.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
@@ -600,7 +599,7 @@ fn check_bench_signature(
     // N.B., inadequate check, but we're running
     // well before resolve, can't get too deep.
     if f.sig.decl.inputs.len() != 1 {
-        return Err(cx.sess.dcx().emit_err(errors::BenchSig { span: i.span }));
+        return Err(cx.dcx().emit_err(errors::BenchSig { span: i.span }));
     }
     Ok(())
 }
diff --git a/compiler/rustc_builtin_macros/src/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs
index af1a392acc5e5..e076aa6da73d3 100644
--- a/compiler/rustc_builtin_macros/src/trace_macros.rs
+++ b/compiler/rustc_builtin_macros/src/trace_macros.rs
@@ -21,7 +21,7 @@ pub fn expand_trace_macros(
     };
     err |= cursor.next().is_some();
     if err {
-        cx.emit_err(errors::TraceMacros { span: sp });
+        cx.dcx().emit_err(errors::TraceMacros { span: sp });
     } else {
         cx.set_trace_macros(value);
     }
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 2c194f6d6d3ad..795c8daec6a34 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -47,12 +47,12 @@ pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: Call
         }
 
         Conv::X86Intr | Conv::RiscvInterrupt { .. } => {
-            sess.fatal(format!("interrupt call conv {c:?} not yet implemented"))
+            sess.dcx().fatal(format!("interrupt call conv {c:?} not yet implemented"))
         }
 
-        Conv::ArmAapcs => sess.fatal("aapcs call conv not yet implemented"),
+        Conv::ArmAapcs => sess.dcx().fatal("aapcs call conv not yet implemented"),
         Conv::CCmseNonSecureCall => {
-            sess.fatal("C-cmse-nonsecure-call call conv is not yet implemented");
+            sess.dcx().fatal("C-cmse-nonsecure-call call conv is not yet implemented");
         }
 
         Conv::Msp430Intr
@@ -88,10 +88,10 @@ pub(crate) fn import_function<'tcx>(
     let sig = get_function_sig(tcx, module.target_config().default_call_conv, inst);
     match module.declare_function(name, Linkage::Import, &sig) {
         Ok(func_id) => func_id,
-        Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(format!(
+        Err(ModuleError::IncompatibleDeclaration(_)) => tcx.dcx().fatal(format!(
             "attempt to declare `{name}` as function, but it was already declared as static"
         )),
-        Err(ModuleError::IncompatibleSignature(_, prev_sig, new_sig)) => tcx.sess.fatal(format!(
+        Err(ModuleError::IncompatibleSignature(_, prev_sig, new_sig)) => tcx.dcx().fatal(format!(
             "attempt to declare `{name}` with signature {new_sig:?}, \
              but it was already declared with signature {prev_sig:?}"
         )),
@@ -181,7 +181,7 @@ fn make_local_place<'tcx>(
     is_ssa: bool,
 ) -> CPlace<'tcx> {
     if layout.is_unsized() {
-        fx.tcx.sess.span_fatal(
+        fx.tcx.dcx().span_fatal(
             fx.mir.local_decls[local].source_info.span,
             "unsized locals are not yet supported",
         );
@@ -226,7 +226,7 @@ pub(crate) fn codegen_fn_prelude<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, start_
 
     // FIXME implement variadics in cranelift
     if fn_abi.c_variadic {
-        fx.tcx.sess.span_fatal(
+        fx.tcx.dcx().span_fatal(
             fx.mir.span,
             "Defining variadic functions is not yet supported by Cranelift",
         );
@@ -543,7 +543,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
         // FIXME find a cleaner way to support varargs
         if fn_sig.c_variadic() {
             if !matches!(fn_sig.abi(), Abi::C { .. }) {
-                fx.tcx.sess.span_fatal(
+                fx.tcx.dcx().span_fatal(
                     source_info.span,
                     format!("Variadic call for non-C abi {:?}", fn_sig.abi()),
                 );
@@ -555,7 +555,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
                     let ty = fx.bcx.func.dfg.value_type(arg);
                     if !ty.is_int() {
                         // FIXME set %al to upperbound on float args once floats are supported
-                        fx.tcx.sess.span_fatal(
+                        fx.tcx.dcx().span_fatal(
                             source_info.span,
                             format!("Non int ty {:?} for variadic call", ty),
                         );
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 8d3be19839e9a..881c0c0b56b6f 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -236,13 +236,13 @@ pub(crate) fn verify_func(
         match cranelift_codegen::verify_function(&func, &flags) {
             Ok(_) => {}
             Err(err) => {
-                tcx.sess.err(format!("{:?}", err));
+                tcx.dcx().err(format!("{:?}", err));
                 let pretty_error = cranelift_codegen::print_errors::pretty_verifier_error(
                     &func,
                     Some(Box::new(writer)),
                     err,
                 );
-                tcx.sess.fatal(format!("cranelift verify error:\n{}", pretty_error));
+                tcx.dcx().fatal(format!("cranelift verify error:\n{}", pretty_error));
             }
         }
     });
@@ -450,7 +450,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
                 unwind: _,
             } => {
                 if options.contains(InlineAsmOptions::MAY_UNWIND) {
-                    fx.tcx.sess.span_fatal(
+                    fx.tcx.dcx().span_fatal(
                         source_info.span,
                         "cranelift doesn't support unwinding from inline assembly.",
                     );
@@ -812,7 +812,7 @@ fn codegen_stmt<'tcx>(
         | StatementKind::PlaceMention(..)
         | StatementKind::AscribeUserType(..) => {}
 
-        StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
+        StatementKind::Coverage { .. } => fx.tcx.dcx().fatal("-Zcoverage is unimplemented"),
         StatementKind::Intrinsic(ref intrinsic) => match &**intrinsic {
             // We ignore `assume` intrinsics, they are only useful for optimizations
             NonDivergingIntrinsic::Assume(_) => {}
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index bd19a7ed0592e..1e37825b54896 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -465,9 +465,12 @@ impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
         if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
-            self.0.sess.span_fatal(span, err.to_string())
+            self.0.sess.dcx().span_fatal(span, err.to_string())
         } else {
-            self.0.sess.span_fatal(span, format!("failed to get layout for `{}`: {}", ty, err))
+            self.0
+                .sess
+                .dcx()
+                .span_fatal(span, format!("failed to get layout for `{}`: {}", ty, err))
         }
     }
 }
@@ -483,7 +486,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
         fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
         if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
-            self.0.sess.emit_fatal(Spanned { span, node: err })
+            self.0.sess.dcx().emit_fatal(Spanned { span, node: err })
         } else {
             match fn_abi_request {
                 FnAbiRequest::OfFnPtr { sig, extra_args } => {
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index 9ffa006e59b69..b6de688130c79 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -263,7 +263,7 @@ fn data_id_for_static(
             attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
         ) {
             Ok(data_id) => data_id,
-            Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(format!(
+            Err(ModuleError::IncompatibleDeclaration(_)) => tcx.dcx().fatal(format!(
                 "attempt to declare `{symbol_name}` as static, but it was already declared as function"
             )),
             Err(err) => Err::<_, _>(err).unwrap(),
@@ -311,7 +311,7 @@ fn data_id_for_static(
         attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
     ) {
         Ok(data_id) => data_id,
-        Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(format!(
+        Err(ModuleError::IncompatibleDeclaration(_)) => tcx.dcx().fatal(format!(
             "attempt to declare `{symbol_name}` as static, but it was already declared as function"
         )),
         Err(err) => Err::<_, _>(err).unwrap(),
@@ -360,7 +360,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                 if let Some(names) = section_name.split_once(',') {
                     names
                 } else {
-                    tcx.sess.fatal(format!(
+                    tcx.dcx().fatal(format!(
                         "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma",
                         section_name
                     ));
@@ -406,7 +406,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
                 GlobalAlloc::Static(def_id) => {
                     if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
                     {
-                        tcx.sess.fatal(format!(
+                        tcx.dcx().fatal(format!(
                             "Allocation {:?} contains reference to TLS value {:?}",
                             alloc_id, def_id
                         ));
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index b3ab533df3dcb..e77b0cd0721b2 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -69,7 +69,7 @@ impl OngoingCodegen {
 
             let module_codegen_result = match module_codegen_result {
                 Ok(module_codegen_result) => module_codegen_result,
-                Err(err) => sess.fatal(err),
+                Err(err) => sess.dcx().fatal(err),
             };
             let ModuleCodegenResult { module_regular, module_global_asm, existing_work_product } =
                 module_codegen_result;
@@ -108,7 +108,7 @@ impl OngoingCodegen {
 
         self.concurrency_limiter.finished();
 
-        sess.abort_if_errors();
+        sess.dcx().abort_if_errors();
 
         (
             CodegenResults {
@@ -422,7 +422,7 @@ pub(crate) fn run_aot(
                                     backend_config.clone(),
                                     global_asm_config.clone(),
                                     cgu.name(),
-                                    concurrency_limiter.acquire(tcx.sess.dcx()),
+                                    concurrency_limiter.acquire(tcx.dcx()),
                                 ),
                                 module_codegen,
                                 Some(rustc_middle::dep_graph::hash_result),
@@ -455,7 +455,7 @@ pub(crate) fn run_aot(
             "allocator_shim".to_owned(),
         ) {
             Ok(allocator_module) => Some(allocator_module),
-            Err(err) => tcx.sess.fatal(err),
+            Err(err) => tcx.dcx().fatal(err),
         }
     } else {
         None
@@ -478,7 +478,7 @@ pub(crate) fn run_aot(
             let obj = create_compressed_metadata_file(tcx.sess, &metadata, &symbol_name);
 
             if let Err(err) = std::fs::write(&tmp_file, obj) {
-                tcx.sess.fatal(format!("error writing metadata object file: {}", err));
+                tcx.dcx().fatal(format!("error writing metadata object file: {}", err));
             }
 
             (metadata_cgu_name, tmp_file)
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 6ee65d12c73e9..7905ec8402dfd 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -94,11 +94,11 @@ fn create_jit_module(
 
 pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
     if !tcx.sess.opts.output_types.should_codegen() {
-        tcx.sess.fatal("JIT mode doesn't work with `cargo check`");
+        tcx.dcx().fatal("JIT mode doesn't work with `cargo check`");
     }
 
     if !tcx.crate_types().contains(&rustc_session::config::CrateType::Executable) {
-        tcx.sess.fatal("can't jit non-executable crate");
+        tcx.dcx().fatal("can't jit non-executable crate");
     }
 
     let (mut jit_module, mut cx) = create_jit_module(
@@ -141,17 +141,17 @@ pub(crate) fn run_jit(tcx: TyCtxt<'_>, backend_config: BackendConfig) -> ! {
                 }
                 MonoItem::GlobalAsm(item_id) => {
                     let item = tcx.hir().item(item_id);
-                    tcx.sess.span_fatal(item.span, "Global asm is not supported in JIT mode");
+                    tcx.dcx().span_fatal(item.span, "Global asm is not supported in JIT mode");
                 }
             }
         }
     });
 
     if !cx.global_asm.is_empty() {
-        tcx.sess.fatal("Inline asm is not supported in JIT mode");
+        tcx.dcx().fatal("Inline asm is not supported in JIT mode");
     }
 
-    tcx.sess.abort_if_errors();
+    tcx.dcx().abort_if_errors();
 
     jit_module.finalize_definitions().unwrap();
     unsafe { cx.unwind_context.register_jit(&jit_module) };
@@ -338,7 +338,7 @@ fn dep_symbol_lookup_fn(
             .collect::<Box<[_]>>(),
     );
 
-    sess.abort_if_errors();
+    sess.dcx().abort_if_errors();
 
     Box::new(move |sym_name| {
         for dylib in &*imported_dylibs {
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index b14007f4e5232..af99239d81593 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -47,7 +47,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
                         }
                         InlineAsmOperand::SymFn { anon_const } => {
                             if cfg!(not(feature = "inline_asm_sym")) {
-                                tcx.sess.span_err(
+                                tcx.dcx().span_err(
                                     item.span,
                                     "asm! and global_asm! sym operands are not yet supported",
                                 );
@@ -65,7 +65,7 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
                         }
                         InlineAsmOperand::SymStatic { path: _, def_id } => {
                             if cfg!(not(feature = "inline_asm_sym")) {
-                                tcx.sess.span_err(
+                                tcx.dcx().span_err(
                                     item.span,
                                     "asm! and global_asm! sym operands are not yet supported",
                                 );
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 73f4bc7c15111..6b9cec39d7020 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -84,7 +84,7 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
             InlineAsmOperand::SymFn { ref value } => {
                 if cfg!(not(feature = "inline_asm_sym")) {
                     fx.tcx
-                        .sess
+                        .dcx()
                         .span_err(span, "asm! and global_asm! sym operands are not yet supported");
                 }
 
@@ -455,7 +455,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
             }
             _ => self
                 .tcx
-                .sess
+                .dcx()
                 .fatal(format!("Unsupported binary format for inline asm: {binary_format:?}")),
         }
 
@@ -563,7 +563,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
             BinaryFormat::Macho | BinaryFormat::Coff => {}
             _ => self
                 .tcx
-                .sess
+                .dcx()
                 .fatal(format!("Unsupported binary format for inline asm: {binary_format:?}")),
         }
 
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
index dbd5db87511df..a38a728c926d8 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
@@ -68,7 +68,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
 
         _ => {
             fx.tcx
-                .sess
+                .dcx()
                 .warn(format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));
             crate::trap::trap_unimplemented(fx, intrinsic);
             return;
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
index e1e514dca44f3..c8f9c3997a63f 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
@@ -309,7 +309,7 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>(
         }
         */
         _ => {
-            fx.tcx.sess.warn(format!(
+            fx.tcx.dcx().warn(format!(
                 "unsupported AArch64 llvm intrinsic {}; replacing with trap",
                 intrinsic
             ));
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index 99bb5c4eae2d8..81114cbf40d83 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -960,7 +960,9 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             {
                 imm8
             } else {
-                fx.tcx.sess.span_fatal(span, "Index argument for `_mm_cmpestri` is not a constant");
+                fx.tcx
+                    .dcx()
+                    .span_fatal(span, "Index argument for `_mm_cmpestri` is not a constant");
             };
 
             let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8));
@@ -1011,7 +1013,9 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             {
                 imm8
             } else {
-                fx.tcx.sess.span_fatal(span, "Index argument for `_mm_cmpestrm` is not a constant");
+                fx.tcx
+                    .dcx()
+                    .span_fatal(span, "Index argument for `_mm_cmpestrm` is not a constant");
             };
 
             let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8));
@@ -1056,7 +1060,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             {
                 imm8
             } else {
-                fx.tcx.sess.span_fatal(
+                fx.tcx.dcx().span_fatal(
                     span,
                     "Index argument for `_mm_clmulepi64_si128` is not a constant",
                 );
@@ -1093,7 +1097,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
             {
                 imm8
             } else {
-                fx.tcx.sess.span_fatal(
+                fx.tcx.dcx().span_fatal(
                     span,
                     "Index argument for `_mm_aeskeygenassist_si128` is not a constant",
                 );
@@ -1361,7 +1365,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
 
         _ => {
             fx.tcx
-                .sess
+                .dcx()
                 .warn(format!("unsupported x86 llvm intrinsic {}; replacing with trap", intrinsic));
             crate::trap::trap_unimplemented(fx, intrinsic);
             return;
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 68126f1242426..15249402a63e7 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -37,7 +37,7 @@ fn report_atomic_type_validation_error<'tcx>(
     span: Span,
     ty: Ty<'tcx>,
 ) {
-    fx.tcx.sess.span_err(
+    fx.tcx.dcx().span_err(
         span,
         format!(
             "`{}` intrinsic: expected basic integer or raw pointer type, found `{:?}`",
@@ -785,7 +785,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                         return;
                     } else {
                         fx.tcx
-                            .sess
+                            .dcx()
                             .span_fatal(source_info.span, "128bit atomics not yet supported");
                     }
                 }
@@ -816,7 +816,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
                         return;
                     } else {
                         fx.tcx
-                            .sess
+                            .dcx()
                             .span_fatal(source_info.span, "128bit atomics not yet supported");
                     }
                 }
@@ -1245,7 +1245,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
 
         // FIXME implement variadics in cranelift
         sym::va_copy | sym::va_arg | sym::va_end => {
-            fx.tcx.sess.span_fatal(
+            fx.tcx.dcx().span_fatal(
                 source_info.span,
                 "Defining variadic functions is not yet supported by Cranelift",
             );
@@ -1253,7 +1253,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
 
         _ => {
             fx.tcx
-                .sess
+                .dcx()
                 .span_fatal(source_info.span, format!("unsupported intrinsic {}", intrinsic));
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index fe4f073f79933..16a550f45b839 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -12,7 +12,7 @@ fn report_simd_type_validation_error(
     span: Span,
     ty: Ty<'_>,
 ) {
-    fx.tcx.sess.span_err(span, format!("invalid monomorphization of `{}` intrinsic: expected SIMD input type, found non-SIMD `{}`", intrinsic, ty));
+    fx.tcx.dcx().span_err(span, format!("invalid monomorphization of `{}` intrinsic: expected SIMD input type, found non-SIMD `{}`", intrinsic, ty));
     // Prevent verifier error
     fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
 }
@@ -192,7 +192,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                     .try_into()
                     .unwrap(),
                 _ => {
-                    fx.tcx.sess.span_err(
+                    fx.tcx.dcx().span_err(
                         span,
                         format!("simd_shuffle index must be an array of `u32`, got `{}`", idx_ty),
                     );
@@ -278,7 +278,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             {
                 idx_const
             } else {
-                fx.tcx.sess.span_fatal(span, "Index argument for `simd_insert` is not a constant");
+                fx.tcx.dcx().span_fatal(span, "Index argument for `simd_insert` is not a constant");
             };
 
             let idx: u32 = idx_const
@@ -286,7 +286,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 .unwrap_or_else(|_| panic!("kind not scalar: {:?}", idx_const));
             let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx);
             if u64::from(idx) >= lane_count {
-                fx.tcx.sess.span_fatal(
+                fx.tcx.dcx().span_fatal(
                     fx.mir.span,
                     format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count),
                 );
@@ -316,7 +316,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             {
                 idx_const
             } else {
-                fx.tcx.sess.span_warn(span, "Index argument for `simd_extract` is not a constant");
+                fx.tcx.dcx().span_warn(span, "Index argument for `simd_extract` is not a constant");
                 let trap_block = fx.bcx.create_block();
                 let true_ = fx.bcx.ins().iconst(types::I8, 1);
                 let ret_block = fx.get_block(target);
@@ -334,7 +334,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                 .unwrap_or_else(|_| panic!("kind not scalar: {:?}", idx_const));
             let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx);
             if u64::from(idx) >= lane_count {
-                fx.tcx.sess.span_fatal(
+                fx.tcx.dcx().span_fatal(
                     fx.mir.span,
                     format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count),
                 );
@@ -859,7 +859,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
             match lane_ty.kind() {
                 ty::Int(_) | ty::Uint(_) => {}
                 _ => {
-                    fx.tcx.sess.span_fatal(
+                    fx.tcx.dcx().span_fatal(
                         span,
                         format!(
                             "invalid monomorphization of `simd_bitmask` intrinsic: \
@@ -899,7 +899,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
                         && len.try_eval_target_usize(fx.tcx, ty::ParamEnv::reveal_all())
                             == Some(expected_bytes) => {}
                 _ => {
-                    fx.tcx.sess.span_fatal(
+                    fx.tcx.dcx().span_fatal(
                         span,
                         format!(
                             "invalid monomorphization of `simd_bitmask` intrinsic: \
@@ -1086,7 +1086,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
         }
 
         _ => {
-            fx.tcx.sess.span_err(span, format!("Unknown SIMD intrinsic {}", intrinsic));
+            fx.tcx.dcx().span_err(span, format!("Unknown SIMD intrinsic {}", intrinsic));
             // Prevent verifier error
             fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
             return;
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index d0ce209be4446..b482f0dd2f0ab 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -177,13 +177,15 @@ impl CodegenBackend for CraneliftCodegenBackend {
         use rustc_session::config::Lto;
         match sess.lto() {
             Lto::No | Lto::ThinLocal => {}
-            Lto::Thin | Lto::Fat => sess.warn("LTO is not supported. You may get a linker error."),
+            Lto::Thin | Lto::Fat => {
+                sess.dcx().warn("LTO is not supported. You may get a linker error.")
+            }
         }
 
         let mut config = self.config.borrow_mut();
         if config.is_none() {
             let new_config = BackendConfig::from_opts(&sess.opts.cg.llvm_args)
-                .unwrap_or_else(|err| sess.fatal(err));
+                .unwrap_or_else(|err| sess.dcx().fatal(err));
             *config = Some(new_config);
         }
     }
@@ -202,7 +204,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
         metadata: EncodedMetadata,
         need_metadata_module: bool,
     ) -> Box<dyn Any> {
-        tcx.sess.abort_if_errors();
+        tcx.dcx().abort_if_errors();
         let config = self.config.borrow().clone().unwrap();
         match config.codegen_mode {
             CodegenMode::Aot => driver::aot::run_aot(tcx, config, metadata, need_metadata_module),
@@ -211,7 +213,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
                 driver::jit::run_jit(tcx, config);
 
                 #[cfg(not(feature = "jit"))]
-                tcx.sess.fatal("jit support was disabled when compiling rustc_codegen_cranelift");
+                tcx.dcx().fatal("jit support was disabled when compiling rustc_codegen_cranelift");
             }
         }
     }
@@ -243,7 +245,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
 fn target_triple(sess: &Session) -> target_lexicon::Triple {
     match sess.target.llvm_target.parse() {
         Ok(triple) => triple,
-        Err(err) => sess.fatal(format!("target not recognized: {}", err)),
+        Err(err) => sess.dcx().fatal(format!("target not recognized: {}", err)),
     }
 }
 
@@ -310,17 +312,18 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn isa::Tar
         Some(value) => {
             let mut builder =
                 cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| {
-                    sess.fatal(format!("can't compile for {}: {}", target_triple, err));
+                    sess.dcx().fatal(format!("can't compile for {}: {}", target_triple, err));
                 });
             if let Err(_) = builder.enable(value) {
-                sess.fatal("the specified target cpu isn't currently supported by Cranelift.");
+                sess.dcx()
+                    .fatal("the specified target cpu isn't currently supported by Cranelift.");
             }
             builder
         }
         None => {
             let mut builder =
                 cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| {
-                    sess.fatal(format!("can't compile for {}: {}", target_triple, err));
+                    sess.dcx().fatal(format!("can't compile for {}: {}", target_triple, err));
                 });
             if target_triple.architecture == target_lexicon::Architecture::X86_64 {
                 // Don't use "haswell" as the default, as it implies `has_lzcnt`.
@@ -333,7 +336,7 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn isa::Tar
 
     match isa_builder.finish(flags) {
         Ok(target_isa) => target_isa,
-        Err(err) => sess.fatal(format!("failed to build TargetIsa: {}", err)),
+        Err(err) => sess.dcx().fatal(format!("failed to build TargetIsa: {}", err)),
     }
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index b5efe44d8b3c8..6535c3a367b87 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -74,7 +74,7 @@ pub(crate) fn maybe_create_entry_wrapper(
         let cmain_func_id = match m.declare_function(entry_name, Linkage::Export, &cmain_sig) {
             Ok(func_id) => func_id,
             Err(err) => {
-                tcx.sess
+                tcx.dcx()
                     .fatal(format!("entry symbol `{entry_name}` declared multiple times: {err}"));
             }
         };
@@ -171,7 +171,7 @@ pub(crate) fn maybe_create_entry_wrapper(
         }
 
         if let Err(err) = m.define_function(cmain_func_id, &mut ctx) {
-            tcx.sess.fatal(format!("entry symbol `{entry_name}` defined multiple times: {err}"));
+            tcx.dcx().fatal(format!("entry symbol `{entry_name}` defined multiple times: {err}"));
         }
 
         unwind_context.add_function(cmain_func_id, &ctx, m.isa());
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 567a5669d4969..838c73fa21365 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -397,7 +397,7 @@ impl<'tcx> CPlace<'tcx> {
 
         if layout.size.bytes() >= u64::from(u32::MAX - 16) {
             fx.tcx
-                .sess
+                .dcx()
                 .fatal(format!("values of type {} are too big to store on the stack", layout.ty));
         }
 
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index f3a9ca77a67b1..ddd67a994c942 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -109,7 +109,7 @@ enum ConstraintOrRegister {
 impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
     fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) {
         if options.contains(InlineAsmOptions::MAY_UNWIND) {
-            self.sess()
+            self.sess().dcx()
                 .create_err(UnwindingInlineAsm { span: span[0] })
                 .emit();
             return;
diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs
index 6159971cfaa8d..9f361d3688695 100644
--- a/compiler/rustc_codegen_gcc/src/attributes.rs
+++ b/compiler/rustc_codegen_gcc/src/attributes.rs
@@ -80,7 +80,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
         let span = cx.tcx
             .get_attr(instance.def_id(), sym::target_feature)
             .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
-        cx.tcx.sess.create_err(TiedTargetFeatures {
+        cx.tcx.dcx().create_err(TiedTargetFeatures {
             features: features.join(", "),
             span,
         })
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
index f06416b9bb5fe..70d8db02247ce 100644
--- a/compiler/rustc_codegen_gcc/src/consts.rs
+++ b/compiler/rustc_codegen_gcc/src/consts.rs
@@ -24,7 +24,7 @@ fn set_global_alignment<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, gv: LValue<'gcc>
         match Align::from_bits(min) {
             Ok(min) => align = align.max(min),
             Err(err) => {
-                cx.sess().emit_err(InvalidMinimumAlignment { err: err.to_string() });
+                cx.sess().dcx().emit_err(InvalidMinimumAlignment { err: err.to_string() });
             }
         }
     }
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
index ab9c703db37da..053f759329fb1 100644
--- a/compiler/rustc_codegen_gcc/src/context.rs
+++ b/compiler/rustc_codegen_gcc/src/context.rs
@@ -500,9 +500,9 @@ impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
         if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
-            self.sess().emit_fatal(respan(span, err.into_diagnostic()))
+            self.tcx.dcx().emit_fatal(respan(span, err.into_diagnostic()))
         } else {
-            self.tcx.sess.emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
+            self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
         }
     }
 }
@@ -518,7 +518,7 @@ impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
         fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
         if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
-            self.sess().emit_fatal(respan(span, err))
+            self.tcx.dcx().emit_fatal(respan(span, err))
         } else {
             match fn_abi_request {
                 FnAbiRequest::OfFnPtr { sig, extra_args } => {
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 2aa84f26797c3..df917d527ced8 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -52,7 +52,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
                 Some(c @ ('+' | '-')) => c,
                 Some(_) => {
                     if diagnostics {
-                        sess.emit_warning(UnknownCTargetFeaturePrefix { feature: s });
+                        sess.dcx().emit_warning(UnknownCTargetFeaturePrefix { feature: s });
                     }
                     return None;
                 }
@@ -79,7 +79,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
                     else {
                         UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
                     };
-                sess.emit_warning(unknown_feature);
+                sess.dcx().emit_warning(unknown_feature);
             }
 
             if diagnostics {
@@ -114,7 +114,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
 
     if diagnostics {
         if let Some(f) = check_tied_features(sess, &featsmap) {
-            sess.emit_err(TargetFeatureDisableOrEnable {
+            sess.dcx().emit_err(TargetFeatureDisableOrEnable {
                 features: f,
                 span: None,
                 missing_features: None,
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index ba1cae03f3e41..85b891fce3e42 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -262,7 +262,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
                                 _ => bug!(),
                             },
                             None => {
-                                tcx.sess.emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
+                                tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
                                 return;
                             }
                         }
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
index 85d3e7234a0e6..9fa978cd2ef7a 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
@@ -34,7 +34,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     // macros for error handling:
     macro_rules! return_error {
         ($err:expr) => {{
-            bx.sess().emit_err($err);
+            bx.tcx.dcx().emit_err($err);
             return Err(());
         }};
     }
@@ -390,7 +390,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(
     ) -> Result<RValue<'gcc>, ()> {
         macro_rules! return_error {
             ($err:expr) => {{
-                bx.sess().emit_err($err);
+                bx.tcx.dcx().emit_err($err);
                 return Err(());
             }};
         }
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 1f3f909d8b4f0..f69f850c1d4a1 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -191,7 +191,7 @@ impl CodegenBackend for GccCodegenBackend {
         #[cfg(feature="master")]
         gccjit::set_global_personality_function_name(b"rust_eh_personality\0");
         if sess.lto() == Lto::Thin {
-            sess.emit_warning(LTONotSupported {});
+            sess.dcx().emit_warning(LTONotSupported {});
         }
 
         #[cfg(not(feature="master"))]
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index 481741bb1277a..3cc33b8343403 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -82,7 +82,7 @@ pub fn sanitize_attrs<'ll>(
         let mte_feature =
             features.iter().map(|s| &s[..]).rfind(|n| ["+mte", "-mte"].contains(&&n[..]));
         if let None | Some("-mte") = mte_feature {
-            cx.tcx.sess.emit_err(SanitizerMemtagRequiresMte);
+            cx.tcx.dcx().emit_err(SanitizerMemtagRequiresMte);
         }
 
         attrs.push(llvm::AttributeKind::SanitizeMemTag.create_attr(cx.llcx));
@@ -444,7 +444,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
             .next()
             .map_or_else(|| cx.tcx.def_span(instance.def_id()), |a| a.span);
         cx.tcx
-            .sess
+            .dcx()
             .create_err(TargetFeatureDisableOrEnable {
                 features: f,
                 span: Some(span),
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index cf47c94a81ff8..67bc86e4c9026 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -99,7 +99,7 @@ impl<'a> ArchiveBuilder<'a> for LlvmArchiveBuilder<'a> {
     fn build(mut self: Box<Self>, output: &Path) -> bool {
         match self.build_with_llvm(output) {
             Ok(any_members) => any_members,
-            Err(e) => self.sess.emit_fatal(ArchiveBuildFailure { error: e }),
+            Err(e) => self.sess.dcx().emit_fatal(ArchiveBuildFailure { error: e }),
         }
     }
 }
@@ -175,7 +175,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
             match std::fs::write(&def_file_path, def_file_content) {
                 Ok(_) => {}
                 Err(e) => {
-                    sess.emit_fatal(ErrorWritingDEFFile { error: e });
+                    sess.dcx().emit_fatal(ErrorWritingDEFFile { error: e });
                 }
             };
 
@@ -217,14 +217,14 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
 
             match dlltool_cmd.output() {
                 Err(e) => {
-                    sess.emit_fatal(ErrorCallingDllTool {
+                    sess.dcx().emit_fatal(ErrorCallingDllTool {
                         dlltool_path: dlltool.to_string_lossy(),
                         error: e,
                     });
                 }
                 // dlltool returns '0' on failure, so check for error output instead.
                 Ok(output) if !output.stderr.is_empty() => {
-                    sess.emit_fatal(DlltoolFailImportLibrary {
+                    sess.dcx().emit_fatal(DlltoolFailImportLibrary {
                         dlltool_path: dlltool.to_string_lossy(),
                         dlltool_args: dlltool_cmd
                             .get_args()
@@ -282,7 +282,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
             };
 
             if result == crate::llvm::LLVMRustResult::Failure {
-                sess.emit_fatal(ErrorCreatingImportLibrary {
+                sess.dcx().emit_fatal(ErrorCreatingImportLibrary {
                     lib_name,
                     error: llvm::last_error().unwrap_or("unknown LLVM error".to_string()),
                 });
@@ -354,7 +354,7 @@ impl<'a> LlvmArchiveBuilder<'a> {
         let kind = kind
             .parse::<ArchiveKind>()
             .map_err(|_| kind)
-            .unwrap_or_else(|kind| self.sess.emit_fatal(UnknownArchiveKind { kind }));
+            .unwrap_or_else(|kind| self.sess.dcx().emit_fatal(UnknownArchiveKind { kind }));
 
         let mut additions = mem::take(&mut self.additions);
         let mut strings = Vec::new();
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 75f99f964d0a9..c607533a08ed0 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -126,7 +126,7 @@ pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTargetMach
         tcx.backend_optimization_level(()),
         tcx.global_backend_features(()),
     )(config)
-    .unwrap_or_else(|err| llvm_err(tcx.sess.dcx(), err).raise())
+    .unwrap_or_else(|err| llvm_err(tcx.dcx(), err).raise())
 }
 
 pub fn to_llvm_opt_settings(
@@ -245,12 +245,12 @@ pub fn target_machine_factory(
     match sess.opts.debuginfo_compression {
         rustc_session::config::DebugInfoCompression::Zlib => {
             if !unsafe { LLVMRustLLVMHasZlibCompressionForDebugSymbols() } {
-                sess.emit_warning(UnknownCompression { algorithm: "zlib" });
+                sess.dcx().emit_warning(UnknownCompression { algorithm: "zlib" });
             }
         }
         rustc_session::config::DebugInfoCompression::Zstd => {
             if !unsafe { LLVMRustLLVMHasZstdCompressionForDebugSymbols() } {
-                sess.emit_warning(UnknownCompression { algorithm: "zstd" });
+                sess.dcx().emit_warning(UnknownCompression { algorithm: "zstd" });
             }
         }
         rustc_session::config::DebugInfoCompression::None => {}
diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs
index 77e893c815fc4..ec2fb2c6e546b 100644
--- a/compiler/rustc_codegen_llvm/src/consts.rs
+++ b/compiler/rustc_codegen_llvm/src/consts.rs
@@ -131,10 +131,10 @@ fn set_global_alignment<'ll>(cx: &CodegenCx<'ll, '_>, gv: &'ll Value, mut align:
             Ok(min) => align = align.max(min),
             Err(err) => match err {
                 AlignFromBytesError::NotPowerOfTwo(align) => {
-                    cx.sess().emit_err(InvalidMinimumAlignmentNotPowerOfTwo { align });
+                    cx.sess().dcx().emit_err(InvalidMinimumAlignmentNotPowerOfTwo { align });
                 }
                 AlignFromBytesError::TooLarge(align) => {
-                    cx.sess().emit_err(InvalidMinimumAlignmentTooLarge { align });
+                    cx.sess().dcx().emit_err(InvalidMinimumAlignmentTooLarge { align });
                 }
             },
         }
@@ -169,7 +169,7 @@ fn check_and_apply_linkage<'ll, 'tcx>(
             let mut real_name = "_rust_extern_with_linkage_".to_string();
             real_name.push_str(sym);
             let g2 = cx.define_global(&real_name, llty).unwrap_or_else(|| {
-                cx.sess().emit_fatal(SymbolAlreadyDefined {
+                cx.sess().dcx().emit_fatal(SymbolAlreadyDefined {
                     span: cx.tcx.def_span(def_id),
                     symbol_name: sym,
                 })
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index 3053c4e0daaa9..1d1b6e6148dd2 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -1014,9 +1014,9 @@ impl<'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
     #[inline]
     fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
         if let LayoutError::SizeOverflow(_) | LayoutError::ReferencesError(_) = err {
-            self.sess().emit_fatal(Spanned { span, node: err.into_diagnostic() })
+            self.tcx.dcx().emit_fatal(Spanned { span, node: err.into_diagnostic() })
         } else {
-            self.tcx.sess.emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
+            self.tcx.dcx().emit_fatal(ssa_errors::FailedToGetLayout { span, ty, err })
         }
     }
 }
@@ -1032,7 +1032,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'_, 'tcx> {
         fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
         if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
-            self.sess().emit_fatal(Spanned { span, node: err })
+            self.tcx.dcx().emit_fatal(Spanned { span, node: err })
         } else {
             match fn_abi_request {
                 FnAbiRequest::OfFnPtr { sig, extra_args } => {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 58e68a6490798..6043a8ebded88 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -285,7 +285,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
                         _ => bug!(),
                     },
                     None => {
-                        tcx.sess.emit_err(InvalidMonomorphization::BasicIntegerType {
+                        tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
                             span,
                             name,
                             ty,
@@ -921,7 +921,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
 ) -> Result<&'ll Value, ()> {
     macro_rules! return_error {
         ($diag: expr) => {{
-            bx.sess().emit_err($diag);
+            bx.sess().dcx().emit_err($diag);
             return Err(());
         }};
     }
@@ -1059,7 +1059,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
             .map(|(arg_idx, val)| {
                 let idx = val.unwrap_leaf().try_to_i32().unwrap();
                 if idx >= i32::try_from(total_len).unwrap() {
-                    bx.sess().emit_err(InvalidMonomorphization::ShuffleIndexOutOfBounds {
+                    bx.sess().dcx().emit_err(InvalidMonomorphization::ShuffleIndexOutOfBounds {
                         span,
                         name,
                         arg_idx: arg_idx as u64,
@@ -1118,20 +1118,24 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
                 let val = bx.const_get_elt(vector, i as u64);
                 match bx.const_to_opt_u128(val, true) {
                     None => {
-                        bx.sess().emit_err(InvalidMonomorphization::ShuffleIndexNotConstant {
-                            span,
-                            name,
-                            arg_idx,
-                        });
+                        bx.sess().dcx().emit_err(
+                            InvalidMonomorphization::ShuffleIndexNotConstant {
+                                span,
+                                name,
+                                arg_idx,
+                            },
+                        );
                         None
                     }
                     Some(idx) if idx >= total_len => {
-                        bx.sess().emit_err(InvalidMonomorphization::ShuffleIndexOutOfBounds {
-                            span,
-                            name,
-                            arg_idx,
-                            total_len,
-                        });
+                        bx.sess().dcx().emit_err(
+                            InvalidMonomorphization::ShuffleIndexOutOfBounds {
+                                span,
+                                name,
+                                arg_idx,
+                                total_len,
+                            },
+                        );
                         None
                     }
                     Some(idx) => Some(bx.const_i32(idx as i32)),
@@ -1276,7 +1280,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
     ) -> Result<&'ll Value, ()> {
         macro_rules! return_error {
             ($diag: expr) => {{
-                bx.sess().emit_err($diag);
+                bx.sess().dcx().emit_err($diag);
                 return Err(());
             }};
         }
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 08519723eba4f..03b79a143cc31 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -529,7 +529,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
                 Some(c @ ('+' | '-')) => c,
                 Some(_) => {
                     if diagnostics {
-                        sess.emit_warning(UnknownCTargetFeaturePrefix { feature: s });
+                        sess.dcx().emit_warning(UnknownCTargetFeaturePrefix { feature: s });
                     }
                     return None;
                 }
@@ -557,12 +557,12 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
                     } else {
                         UnknownCTargetFeature { feature, rust_feature: PossibleFeature::None }
                     };
-                    sess.emit_warning(unknown_feature);
+                    sess.dcx().emit_warning(unknown_feature);
                 } else if feature_state
                     .is_some_and(|(_name, feature_gate)| !feature_gate.is_stable())
                 {
                     // An unstable feature. Warn about using it.
-                    sess.emit_warning(UnstableCTargetFeature { feature });
+                    sess.dcx().emit_warning(UnstableCTargetFeature { feature });
                 }
             }
 
@@ -598,7 +598,7 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
     features.extend(feats);
 
     if diagnostics && let Some(f) = check_tied_features(sess, &featsmap) {
-        sess.emit_err(TargetFeatureDisableOrEnable {
+        sess.dcx().emit_err(TargetFeatureDisableOrEnable {
             features: f,
             span: None,
             missing_features: None,
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index 01e823396646c..f796ce0990f12 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -26,6 +26,7 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
 
         let g = self.define_global(symbol_name, llty).unwrap_or_else(|| {
             self.sess()
+                .dcx()
                 .emit_fatal(SymbolAlreadyDefined { span: self.tcx.def_span(def_id), symbol_name })
         });
 
diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
index a5bd10ecb34b5..094a61d6e0df3 100644
--- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
+++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs
@@ -88,7 +88,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
                 sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
                 other => {
                     self.tcx
-                        .sess
+                        .dcx()
                         .emit_fatal(errors::UnknownReuseKind { span: attr.span, kind: other });
                 }
             }
@@ -97,7 +97,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
         };
 
         if !self.tcx.sess.opts.unstable_opts.query_dep_graph {
-            self.tcx.sess.emit_fatal(errors::MissingQueryDepGraph { span: attr.span });
+            self.tcx.dcx().emit_fatal(errors::MissingQueryDepGraph { span: attr.span });
         }
 
         if !self.check_config(attr) {
@@ -109,7 +109,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
         let crate_name = self.tcx.crate_name(LOCAL_CRATE).to_string();
 
         if !user_path.starts_with(&crate_name) {
-            self.tcx.sess.emit_fatal(errors::MalformedCguName {
+            self.tcx.dcx().emit_fatal(errors::MalformedCguName {
                 span: attr.span,
                 user_path,
                 crate_name,
@@ -139,7 +139,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
         if !self.available_cgus.contains(&cgu_name) {
             let cgu_names: Vec<&str> =
                 self.available_cgus.items().map(|cgu| cgu.as_str()).into_sorted_stable_ord();
-            self.tcx.sess.emit_err(errors::NoModuleNamed {
+            self.tcx.dcx().emit_err(errors::NoModuleNamed {
                 span: attr.span,
                 user_path,
                 cgu_name,
@@ -162,7 +162,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
                 if let Some(value) = item.value_str() {
                     return value;
                 } else {
-                    self.tcx.sess.emit_fatal(errors::FieldAssociatedValueExpected {
+                    self.tcx.dcx().emit_fatal(errors::FieldAssociatedValueExpected {
                         span: item.span(),
                         name,
                     });
@@ -170,7 +170,7 @@ impl<'tcx> AssertModuleSource<'tcx> {
             }
         }
 
-        self.tcx.sess.emit_fatal(errors::NoField { span: attr.span, name });
+        self.tcx.dcx().emit_fatal(errors::NoField { span: attr.span, name });
     }
 
     /// Scan for a `cfg="foo"` attribute and check whether we have a
@@ -278,7 +278,7 @@ impl CguReuseTracker {
 
                     if error {
                         let at_least = if at_least { 1 } else { 0 };
-                        sess.emit_err(errors::IncorrectCguReuseType {
+                        sess.dcx().emit_err(errors::IncorrectCguReuseType {
                             span: *error_span,
                             cgu_user_name,
                             actual_reuse,
@@ -287,7 +287,7 @@ impl CguReuseTracker {
                         });
                     }
                 } else {
-                    sess.emit_fatal(errors::CguNotRecorded { cgu_user_name, cgu_name });
+                    sess.dcx().emit_fatal(errors::CguNotRecorded { cgu_user_name, cgu_name });
                 }
             }
         }
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 4dc28adf336d4..8d7ad24b44698 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -220,7 +220,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
         let sess = self.sess;
         match self.build_inner(output) {
             Ok(any_members) => any_members,
-            Err(e) => sess.emit_fatal(ArchiveBuildFailure { error: e }),
+            Err(e) => sess.dcx().emit_fatal(ArchiveBuildFailure { error: e }),
         }
     }
 }
@@ -234,7 +234,7 @@ impl<'a> ArArchiveBuilder<'a> {
             "coff" => ArchiveKind::Coff,
             "aix_big" => ArchiveKind::AixBig,
             kind => {
-                self.sess.emit_fatal(UnknownArchiveKind { kind });
+                self.sess.dcx().emit_fatal(UnknownArchiveKind { kind });
             }
         };
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index b32865a0518ba..4ff497f2fdd3f 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -98,7 +98,7 @@ pub fn link_binary<'a>(
             let tmpdir = TempFileBuilder::new()
                 .prefix("rustc")
                 .tempdir()
-                .unwrap_or_else(|error| sess.emit_fatal(errors::CreateTempDir { error }));
+                .unwrap_or_else(|error| sess.dcx().emit_fatal(errors::CreateTempDir { error }));
             let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps);
             let output = out_filename(
                 sess,
@@ -161,11 +161,11 @@ pub fn link_binary<'a>(
 
             if output.is_stdout() {
                 if output.is_tty() {
-                    sess.emit_err(errors::BinaryOutputToTty {
+                    sess.dcx().emit_err(errors::BinaryOutputToTty {
                         shorthand: OutputType::Exe.shorthand(),
                     });
                 } else if let Err(e) = copy_to_stdout(&out_filename) {
-                    sess.emit_err(errors::CopyPath::new(&out_filename, output.as_path(), e));
+                    sess.dcx().emit_err(errors::CopyPath::new(&out_filename, output.as_path(), e));
                 }
                 tempfiles_for_stdout_output.push(out_filename);
             }
@@ -380,8 +380,8 @@ fn link_rlib<'a>(
             && let Some(filename) = lib.filename
         {
             let path = find_native_static_library(filename.as_str(), true, &lib_search_paths, sess);
-            let src =
-                read(path).map_err(|e| sess.emit_fatal(errors::ReadFileError { message: e }))?;
+            let src = read(path)
+                .map_err(|e| sess.dcx().emit_fatal(errors::ReadFileError { message: e }))?;
             let (data, _) = create_wrapper_file(sess, b".bundled_lib".to_vec(), &src);
             let wrapper_file = emit_wrapper_file(sess, &data, tmpdir, filename.as_str());
             packed_bundled_libs.push(wrapper_file);
@@ -393,7 +393,7 @@ fn link_rlib<'a>(
                 sess,
             );
             ab.add_archive(&path, Box::new(|_| false)).unwrap_or_else(|error| {
-                sess.emit_fatal(errors::AddNativeLibrary { library_path: path, error })
+                sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: path, error })
             });
         }
     }
@@ -410,7 +410,7 @@ fn link_rlib<'a>(
         );
 
         ab.add_archive(&output_path, Box::new(|_| false)).unwrap_or_else(|error| {
-            sess.emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
+            sess.dcx().emit_fatal(errors::AddNativeLibrary { library_path: output_path, error });
         });
     }
 
@@ -475,7 +475,7 @@ fn collate_raw_dylibs<'a, 'b>(
                     // FIXME: when we add support for ordinals, figure out if we need to do anything
                     // if we have two DllImport values with the same name but different ordinals.
                     if import.calling_convention != old_import.calling_convention {
-                        sess.emit_err(errors::MultipleExternalFuncDecl {
+                        sess.dcx().emit_err(errors::MultipleExternalFuncDecl {
                             span: import.span,
                             function: import.name,
                             library_name: &name,
@@ -558,7 +558,7 @@ fn link_staticlib<'a>(
 
             archive_builder_builder
                 .extract_bundled_libs(path, tempdir.as_ref(), &relevant_libs)
-                .unwrap_or_else(|e| sess.emit_fatal(e));
+                .unwrap_or_else(|e| sess.dcx().emit_fatal(e));
             for filename in relevant_libs {
                 let joined = tempdir.as_ref().join(filename.as_str());
                 let path = joined.as_path();
@@ -570,7 +570,7 @@ fn link_staticlib<'a>(
         },
     );
     if let Err(e) = res {
-        sess.emit_fatal(e);
+        sess.dcx().emit_fatal(e);
     }
 
     ab.build(out_filename);
@@ -596,9 +596,9 @@ fn link_staticlib<'a>(
             all_rust_dylibs.push(&**path);
         } else {
             if used_crate_source.rmeta.is_some() {
-                sess.emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name });
+                sess.dcx().emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name });
             } else {
-                sess.emit_fatal(errors::LinkRlibError::NotFound { crate_name });
+                sess.dcx().emit_fatal(errors::LinkRlibError::NotFound { crate_name });
             }
         }
     }
@@ -715,8 +715,8 @@ fn link_dwarf_object<'a>(
     }) {
         Ok(()) => {}
         Err(e) => {
-            sess.emit_err(errors::ThorinErrorWrapper(e));
-            sess.abort_if_errors();
+            sess.dcx().emit_err(errors::ThorinErrorWrapper(e));
+            sess.dcx().abort_if_errors();
         }
     }
 }
@@ -765,7 +765,7 @@ fn link_natively<'a>(
     }
 
     // May have not found libraries in the right formats.
-    sess.abort_if_errors();
+    sess.dcx().abort_if_errors();
 
     // Invoke the system linker
     info!("{:?}", &cmd);
@@ -955,22 +955,22 @@ fn link_natively<'a>(
                         )
                         .is_some();
 
-                        sess.emit_note(errors::LinkExeUnexpectedError);
+                        sess.dcx().emit_note(errors::LinkExeUnexpectedError);
                         if is_vs_installed && has_linker {
                             // the linker is broken
-                            sess.emit_note(errors::RepairVSBuildTools);
-                            sess.emit_note(errors::MissingCppBuildToolComponent);
+                            sess.dcx().emit_note(errors::RepairVSBuildTools);
+                            sess.dcx().emit_note(errors::MissingCppBuildToolComponent);
                         } else if is_vs_installed {
                             // the linker is not installed
-                            sess.emit_note(errors::SelectCppBuildToolWorkload);
+                            sess.dcx().emit_note(errors::SelectCppBuildToolWorkload);
                         } else {
                             // visual studio is not installed
-                            sess.emit_note(errors::VisualStudioNotInstalled);
+                            sess.dcx().emit_note(errors::VisualStudioNotInstalled);
                         }
                     }
                 }
 
-                sess.abort_if_errors();
+                sess.dcx().abort_if_errors();
             }
             info!("linker stderr:\n{}", escape_string(&prog.stderr));
             info!("linker stdout:\n{}", escape_string(&prog.stdout));
@@ -979,9 +979,9 @@ fn link_natively<'a>(
             let linker_not_found = e.kind() == io::ErrorKind::NotFound;
 
             if linker_not_found {
-                sess.emit_err(errors::LinkerNotFound { linker_path, error: e });
+                sess.dcx().emit_err(errors::LinkerNotFound { linker_path, error: e });
             } else {
-                sess.emit_err(errors::UnableToExeLinker {
+                sess.dcx().emit_err(errors::UnableToExeLinker {
                     linker_path,
                     error: e,
                     command_formatted: format!("{:?}", &cmd),
@@ -989,11 +989,11 @@ fn link_natively<'a>(
             }
 
             if sess.target.is_like_msvc && linker_not_found {
-                sess.emit_note(errors::MsvcMissingLinker);
-                sess.emit_note(errors::CheckInstalledVisualStudio);
-                sess.emit_note(errors::InsufficientVSCodeProduct);
+                sess.dcx().emit_note(errors::MsvcMissingLinker);
+                sess.dcx().emit_note(errors::CheckInstalledVisualStudio);
+                sess.dcx().emit_note(errors::InsufficientVSCodeProduct);
             }
-            sess.abort_if_errors();
+            sess.dcx().abort_if_errors();
         }
     }
 
@@ -1016,13 +1016,13 @@ fn link_natively<'a>(
                     if !prog.status.success() {
                         let mut output = prog.stderr.clone();
                         output.extend_from_slice(&prog.stdout);
-                        sess.emit_warning(errors::ProcessingDymutilFailed {
+                        sess.dcx().emit_warning(errors::ProcessingDymutilFailed {
                             status: prog.status,
                             output: escape_string(&output),
                         });
                     }
                 }
-                Err(error) => sess.emit_fatal(errors::UnableToRunDsymutil { error }),
+                Err(error) => sess.dcx().emit_fatal(errors::UnableToRunDsymutil { error }),
             }
         }
 
@@ -1091,14 +1091,14 @@ fn strip_symbols_with_external_utility<'a>(
             if !prog.status.success() {
                 let mut output = prog.stderr.clone();
                 output.extend_from_slice(&prog.stdout);
-                sess.emit_warning(errors::StrippingDebugInfoFailed {
+                sess.dcx().emit_warning(errors::StrippingDebugInfoFailed {
                     util,
                     status: prog.status,
                     output: escape_string(&output),
                 });
             }
         }
-        Err(error) => sess.emit_fatal(errors::UnableToRun { util, error }),
+        Err(error) => sess.dcx().emit_fatal(errors::UnableToRun { util, error }),
     }
 }
 
@@ -1311,7 +1311,7 @@ pub fn linker_and_flavor(sess: &Session) -> (PathBuf, LinkerFlavor) {
             )),
             (Some(linker), None) => {
                 let stem = linker.file_stem().and_then(|stem| stem.to_str()).unwrap_or_else(|| {
-                    sess.emit_fatal(errors::LinkerFileStem);
+                    sess.dcx().emit_fatal(errors::LinkerFileStem);
                 });
                 let flavor = sess.target.linker_flavor.with_linker_hints(stem);
                 Some((linker, flavor))
@@ -1456,15 +1456,15 @@ fn print_native_static_libs(
         OutFileName::Real(path) => {
             out.overwrite(&lib_args.join(" "), sess);
             if !lib_args.is_empty() {
-                sess.emit_note(errors::StaticLibraryNativeArtifactsToFile { path });
+                sess.dcx().emit_note(errors::StaticLibraryNativeArtifactsToFile { path });
             }
         }
         OutFileName::Stdout => {
             if !lib_args.is_empty() {
-                sess.emit_note(errors::StaticLibraryNativeArtifacts);
+                sess.dcx().emit_note(errors::StaticLibraryNativeArtifacts);
                 // Prefix for greppability
                 // Note: This must not be translated as tools are allowed to depend on this exact string.
-                sess.note(format!("native-static-libs: {}", &lib_args.join(" ")));
+                sess.dcx().note(format!("native-static-libs: {}", &lib_args.join(" ")));
             }
         }
     }
@@ -1703,7 +1703,7 @@ fn self_contained_components(sess: &Session, crate_type: CrateType) -> LinkSelfC
             // Emit an error if the user requested self-contained mode on the CLI but the target
             // explicitly refuses it.
             if sess.target.link_self_contained.is_disabled() {
-                sess.emit_err(errors::UnsupportedLinkSelfContained);
+                sess.dcx().emit_err(errors::UnsupportedLinkSelfContained);
             }
             self_contained
         } else {
@@ -1790,14 +1790,14 @@ fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_ty
     match (crate_type, &sess.target.link_script) {
         (CrateType::Cdylib | CrateType::Executable, Some(script)) => {
             if !sess.target.linker_flavor.is_gnu() {
-                sess.emit_fatal(errors::LinkScriptUnavailable);
+                sess.dcx().emit_fatal(errors::LinkScriptUnavailable);
             }
 
             let file_name = ["rustc", &sess.target.llvm_target, "linkfile.ld"].join("-");
 
             let path = tmpdir.join(file_name);
             if let Err(error) = fs::write(&path, script.as_ref()) {
-                sess.emit_fatal(errors::LinkScriptWriteFailure { path, error });
+                sess.dcx().emit_fatal(errors::LinkScriptWriteFailure { path, error });
             }
 
             cmd.arg("--script");
@@ -1921,7 +1921,7 @@ fn add_linked_symbol_object(
     let path = tmpdir.join("symbols.o");
     let result = std::fs::write(&path, file.write().unwrap());
     if let Err(error) = result {
-        sess.emit_fatal(errors::FailedToWrite { path, error });
+        sess.dcx().emit_fatal(errors::FailedToWrite { path, error });
     }
     cmd.add_object(&path);
 }
@@ -2390,7 +2390,7 @@ fn collect_natvis_visualizers(
                 visualizer_paths.push(visualizer_out_file);
             }
             Err(error) => {
-                sess.emit_warning(errors::UnableToWriteDebuggerVisualizer {
+                sess.dcx().emit_warning(errors::UnableToWriteDebuggerVisualizer {
                     path: visualizer_out_file,
                     error,
                 });
@@ -2425,7 +2425,7 @@ fn add_native_libs_from_crate(
         let rlib = &codegen_results.crate_info.used_crate_source[&cnum].rlib.as_ref().unwrap().0;
         archive_builder_builder
             .extract_bundled_libs(rlib, tmpdir, bundled_libs)
-            .unwrap_or_else(|e| sess.emit_fatal(e));
+            .unwrap_or_else(|e| sess.dcx().emit_fatal(e));
     }
 
     let native_libs = match cnum {
@@ -2798,7 +2798,7 @@ fn add_static_crate<'a>(
                 false
             }),
         ) {
-            sess.emit_fatal(errors::RlibArchiveBuildFailure { error });
+            sess.dcx().emit_fatal(errors::RlibArchiveBuildFailure { error });
         }
         if archive.build(&dst) {
             link_upstream(&dst);
@@ -2872,14 +2872,14 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) {
         ("arm", "watchos") => "watchos",
         (_, "macos") => "macosx",
         _ => {
-            sess.emit_err(errors::UnsupportedArch { arch, os });
+            sess.dcx().emit_err(errors::UnsupportedArch { arch, os });
             return;
         }
     };
     let sdk_root = match get_apple_sdk_root(sdk_name) {
         Ok(s) => s,
         Err(e) => {
-            sess.emit_err(e);
+            sess.dcx().emit_err(e);
             return;
         }
     };
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index eeb57d4d0f4d8..695aeb0b2fb77 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -446,11 +446,11 @@ impl<'a> Linker for GccLinker<'a> {
                 // FIXME(81490): ld64 doesn't support these flags but macOS 11
                 // has -needed-l{} / -needed_library {}
                 // but we have no way to detect that here.
-                self.sess.emit_warning(errors::Ld64UnimplementedModifier);
+                self.sess.dcx().emit_warning(errors::Ld64UnimplementedModifier);
             } else if self.is_gnu && !self.sess.target.is_like_windows {
                 self.linker_arg("--no-as-needed");
             } else {
-                self.sess.emit_warning(errors::LinkerUnsupportedModifier);
+                self.sess.dcx().emit_warning(errors::LinkerUnsupportedModifier);
             }
         }
         self.hint_dynamic();
@@ -504,7 +504,7 @@ impl<'a> Linker for GccLinker<'a> {
             // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
             // flag but we have no way to detect that here.
             // self.cmd.arg("-needed_framework").arg(framework);
-            self.sess.emit_warning(errors::Ld64UnimplementedModifier);
+            self.sess.dcx().emit_warning(errors::Ld64UnimplementedModifier);
         }
         self.cmd.arg("-framework").arg(framework);
     }
@@ -693,7 +693,7 @@ impl<'a> Linker for GccLinker<'a> {
                 }
             };
             if let Err(error) = res {
-                self.sess.emit_fatal(errors::LibDefWriteFailure { error });
+                self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
             }
         } else if is_windows {
             let res: io::Result<()> = try {
@@ -708,7 +708,7 @@ impl<'a> Linker for GccLinker<'a> {
                 }
             };
             if let Err(error) = res {
-                self.sess.emit_fatal(errors::LibDefWriteFailure { error });
+                self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
             }
         } else {
             // Write an LD version script
@@ -725,7 +725,7 @@ impl<'a> Linker for GccLinker<'a> {
                 writeln!(f, "\n  local:\n    *;\n}};")?;
             };
             if let Err(error) = res {
-                self.sess.emit_fatal(errors::VersionScriptWriteFailure { error });
+                self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error });
             }
         }
 
@@ -950,7 +950,7 @@ impl<'a> Linker for MsvcLinker<'a> {
                                 }
                             }
                             Err(error) => {
-                                self.sess.emit_warning(errors::NoNatvisDirectory { error });
+                                self.sess.dcx().emit_warning(errors::NoNatvisDirectory { error });
                             }
                         }
                     }
@@ -1005,7 +1005,7 @@ impl<'a> Linker for MsvcLinker<'a> {
             }
         };
         if let Err(error) = res {
-            self.sess.emit_fatal(errors::LibDefWriteFailure { error });
+            self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
         }
         let mut arg = OsString::from("/DEF:");
         arg.push(path);
@@ -1501,7 +1501,7 @@ impl<'a> Linker for L4Bender<'a> {
 
     fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
         // ToDo, not implemented, copy from GCC
-        self.sess.emit_warning(errors::L4BenderExportingSymbolsUnimplemented);
+        self.sess.dcx().emit_warning(errors::L4BenderExportingSymbolsUnimplemented);
         return;
     }
 
@@ -1688,7 +1688,7 @@ impl<'a> Linker for AixLinker<'a> {
             }
         };
         if let Err(e) = res {
-            self.sess.fatal(format!("failed to write export file: {e}"));
+            self.sess.dcx().fatal(format!("failed to write export file: {e}"));
         }
         self.cmd.arg(format!("-bE:{}", path.to_str().unwrap()));
     }
@@ -1995,7 +1995,7 @@ impl<'a> Linker for BpfLinker<'a> {
             }
         };
         if let Err(error) = res {
-            self.sess.emit_fatal(errors::SymbolFileWriteFailure { error });
+            self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error });
         } else {
             self.cmd.arg("--export-symbols").arg(&path);
         }
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 53ae085a72160..5a8db7bbf2d67 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -534,12 +534,12 @@ fn produce_final_output_artifacts(
     let copy_gracefully = |from: &Path, to: &OutFileName| match to {
         OutFileName::Stdout => {
             if let Err(e) = copy_to_stdout(from) {
-                sess.emit_err(errors::CopyPath::new(from, to.as_path(), e));
+                sess.dcx().emit_err(errors::CopyPath::new(from, to.as_path(), e));
             }
         }
         OutFileName::Real(path) => {
             if let Err(e) = fs::copy(from, path) {
-                sess.emit_err(errors::CopyPath::new(from, path, e));
+                sess.dcx().emit_err(errors::CopyPath::new(from, path, e));
             }
         }
     };
@@ -552,7 +552,8 @@ fn produce_final_output_artifacts(
             let path = crate_output.temp_path(output_type, module_name);
             let output = crate_output.path(output_type);
             if !output_type.is_text_output() && output.is_tty() {
-                sess.emit_err(errors::BinaryOutputToTty { shorthand: output_type.shorthand() });
+                sess.dcx()
+                    .emit_err(errors::BinaryOutputToTty { shorthand: output_type.shorthand() });
             } else {
                 copy_gracefully(&path, &output);
             }
@@ -572,11 +573,11 @@ fn produce_final_output_artifacts(
             if crate_output.outputs.contains_key(&output_type) {
                 // 2) Multiple codegen units, with `--emit foo=some_name`. We have
                 //    no good solution for this case, so warn the user.
-                sess.emit_warning(errors::IgnoringEmitPath { extension });
+                sess.dcx().emit_warning(errors::IgnoringEmitPath { extension });
             } else if crate_output.single_output_file.is_some() {
                 // 3) Multiple codegen units, with `-o some_name`. We have
                 //    no good solution for this case, so warn the user.
-                sess.emit_warning(errors::IgnoringOutput { extension });
+                sess.dcx().emit_warning(errors::IgnoringOutput { extension });
             } else {
                 // 4) Multiple codegen units, but no explicit name. We
                 //    just leave the `foo.0.x` files in place.
@@ -1079,7 +1080,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
         let result = fs::create_dir_all(dir).and_then(|_| dir.canonicalize());
         match result {
             Ok(dir) => Some(dir),
-            Err(error) => sess.emit_fatal(ErrorCreatingRemarkDir { error }),
+            Err(error) => sess.dcx().emit_fatal(ErrorCreatingRemarkDir { error }),
         }
     } else {
         None
@@ -1882,10 +1883,10 @@ impl SharedEmitterMain {
                     err.emit();
                 }
                 Ok(SharedEmitterMessage::AbortIfErrors) => {
-                    sess.abort_if_errors();
+                    sess.dcx().abort_if_errors();
                 }
                 Ok(SharedEmitterMessage::Fatal(msg)) => {
-                    sess.fatal(msg);
+                    sess.dcx().fatal(msg);
                 }
                 Err(_) => {
                     break;
@@ -1938,7 +1939,7 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
         let compiled_modules = sess.time("join_worker_thread", || match self.coordinator.join() {
             Ok(Ok(compiled_modules)) => compiled_modules,
             Ok(Err(())) => {
-                sess.abort_if_errors();
+                sess.dcx().abort_if_errors();
                 panic!("expected abort due to worker thread errors")
             }
             Err(_) => {
@@ -1946,7 +1947,7 @@ impl<B: ExtraBackendMethods> OngoingCodegen<B> {
             }
         });
 
-        sess.abort_if_errors();
+        sess.dcx().abort_if_errors();
 
         let work_products =
             copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess, &compiled_modules);
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index b87f4b6bf8907..9d1729c4b542d 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -448,8 +448,9 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
         let Some(llfn) = cx.declare_c_main(llfty) else {
             // FIXME: We should be smart and show a better diagnostic here.
             let span = cx.tcx().def_span(rust_main_def_id);
-            cx.sess().emit_err(errors::MultipleMainFunctions { span });
-            cx.sess().abort_if_errors();
+            let dcx = cx.tcx().dcx();
+            dcx.emit_err(errors::MultipleMainFunctions { span });
+            dcx.abort_if_errors();
             bug!();
         };
 
@@ -620,7 +621,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
                 &exported_symbols::metadata_symbol_name(tcx),
             );
             if let Err(error) = std::fs::write(&file_name, data) {
-                tcx.sess.emit_fatal(errors::MetadataObjectFileWrite { error });
+                tcx.dcx().emit_fatal(errors::MetadataObjectFileWrite { error });
             }
             CompiledModule {
                 name: metadata_cgu_name,
@@ -752,7 +753,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
                 // This will unwind if there are errors, which triggers our `AbortCodegenOnDrop`
                 // guard. Unfortunately, just skipping the `submit_codegened_module_to_llvm` makes
                 // compilation hang on post-monomorphization errors.
-                tcx.sess.abort_if_errors();
+                tcx.dcx().abort_if_errors();
 
                 submit_codegened_module_to_llvm(
                     &backend,
@@ -819,7 +820,7 @@ impl CrateInfo {
         let subsystem = attr::first_attr_value_str_by_name(crate_attrs, sym::windows_subsystem);
         let windows_subsystem = subsystem.map(|subsystem| {
             if subsystem != sym::windows && subsystem != sym::console {
-                tcx.sess.emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
+                tcx.dcx().emit_fatal(errors::InvalidWindowsSubsystem { subsystem });
             }
             subsystem.to_string()
         });
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index e529956b1baf6..f5f2416abb6dc 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -44,7 +44,7 @@ fn linkage_by_name(tcx: TyCtxt<'_>, def_id: LocalDefId, name: &str) -> Linkage {
         "private" => Private,
         "weak" => WeakAny,
         "weak_odr" => WeakODR,
-        _ => tcx.sess.span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
+        _ => tcx.dcx().span_fatal(tcx.def_span(def_id), "invalid linkage specified"),
     }
 }
 
@@ -90,7 +90,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             if let Fn | AssocFn | Variant | Ctor(..) = def_kind {
                 Some(tcx.fn_sig(did))
             } else {
-                tcx.sess
+                tcx.dcx()
                     .span_delayed_bug(attr.span, "this attribute can only be applied to functions");
                 None
             }
@@ -119,7 +119,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                 if tcx.opt_item_name(did.to_def_id()).is_some() {
                     codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE
                 } else {
-                    tcx.sess
+                    tcx.dcx()
                         .struct_span_err(
                             attr.span,
                             format!(
@@ -142,7 +142,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         // coverage on a smaller scope within an excluded larger scope.
                     }
                     Some(_) | None => {
-                        tcx.sess.emit_err(ExpectedCoverageSymbol { span: attr.span });
+                        tcx.dcx().emit_err(ExpectedCoverageSymbol { span: attr.span });
                     }
                 }
             }
@@ -177,7 +177,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
                     }
                     Some(_) => {
-                        tcx.sess.emit_err(ExpectedUsedSymbol { span: attr.span });
+                        tcx.dcx().emit_err(ExpectedUsedSymbol { span: attr.span });
                     }
                     None => {
                         // Unfortunately, unconditionally using `llvm.used` causes
@@ -217,7 +217,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     && !matches!(fn_sig.skip_binder().abi(), abi::Abi::C { .. })
                 {
                     struct_span_err!(
-                        tcx.sess,
+                        tcx.dcx(),
                         attr.span,
                         E0776,
                         "`#[cmse_nonsecure_entry]` requires C ABI"
@@ -225,7 +225,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     .emit();
                 }
                 if !tcx.sess.target.llvm_target.contains("thumbv8m") {
-                    struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
+                    struct_span_err!(tcx.dcx(), attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension")
                     .emit();
                 }
                 codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY
@@ -239,7 +239,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     && fn_sig.skip_binder().abi() != abi::Abi::Rust
                 {
                     struct_span_err!(
-                        tcx.sess,
+                        tcx.dcx(),
                         attr.span,
                         E0737,
                         "`#[track_caller]` requires Rust ABI"
@@ -266,7 +266,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         // `#[export_name = ...]` will be converted to a null-terminated string,
                         // so it may not contain any null characters.
                         struct_span_err!(
-                            tcx.sess,
+                            tcx.dcx(),
                             attr.span,
                             E0648,
                             "`export_name` may not contain null characters"
@@ -336,7 +336,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                 if let Some(val) = attr.value_str() {
                     if val.as_str().bytes().any(|b| b == 0) {
                         let msg = format!("illegal null byte in link_section value: `{}`", &val);
-                        tcx.sess.span_err(attr.span, msg);
+                        tcx.dcx().span_err(attr.span, msg);
                     } else {
                         codegen_fn_attrs.link_section = Some(val);
                     }
@@ -370,7 +370,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                                 codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS
                             }
                             _ => {
-                                tcx.sess.emit_err(errors::InvalidNoSanitize { span: item.span() });
+                                tcx.dcx().emit_err(errors::InvalidNoSanitize { span: item.span() });
                             }
                         }
                     }
@@ -386,7 +386,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                                 [sym::arm, sym::a32] | [sym::arm, sym::t32] => {
                                     if !tcx.sess.target.has_thumb_interworking {
                                         struct_span_err!(
-                                            tcx.sess.dcx(),
+                                            tcx.dcx(),
                                             attr.span,
                                             E0779,
                                             "target does not support `#[instruction_set]`"
@@ -403,7 +403,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                                 }
                                 _ => {
                                     struct_span_err!(
-                                        tcx.sess.dcx(),
+                                        tcx.dcx(),
                                         attr.span,
                                         E0779,
                                         "invalid instruction set specified",
@@ -415,7 +415,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         }
                         [] => {
                             struct_span_err!(
-                                tcx.sess.dcx(),
+                                tcx.dcx(),
                                 attr.span,
                                 E0778,
                                 "`#[instruction_set]` requires an argument"
@@ -425,7 +425,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                         }
                         _ => {
                             struct_span_err!(
-                                tcx.sess.dcx(),
+                                tcx.dcx(),
                                 attr.span,
                                 E0779,
                                 "cannot specify more than one instruction set"
@@ -443,7 +443,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
                     rustc_attr::parse_alignment(&literal.kind)
                         .map_err(|msg| {
                             struct_span_err!(
-                                tcx.sess.dcx(),
+                                tcx.dcx(),
                                 attr.span,
                                 E0589,
                                 "invalid `repr(align)` attribute: {}",
@@ -469,15 +469,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
             Some(MetaItemKind::List(ref items)) => {
                 inline_span = Some(attr.span);
                 if items.len() != 1 {
-                    struct_span_err!(tcx.sess.dcx(), attr.span, E0534, "expected one argument")
-                        .emit();
+                    struct_span_err!(tcx.dcx(), attr.span, E0534, "expected one argument").emit();
                     InlineAttr::None
                 } else if list_contains_name(items, sym::always) {
                     InlineAttr::Always
                 } else if list_contains_name(items, sym::never) {
                     InlineAttr::Never
                 } else {
-                    struct_span_err!(tcx.sess.dcx(), items[0].span(), E0535, "invalid argument")
+                    struct_span_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument")
                         .help("valid inline arguments are `always` and `never`")
                         .emit();
 
@@ -493,7 +492,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
         if !attr.has_name(sym::optimize) {
             return ia;
         }
-        let err = |sp, s| struct_span_err!(tcx.sess.dcx(), sp, E0722, "{}", s).emit();
+        let err = |sp, s| struct_span_err!(tcx.dcx(), sp, E0722, "{}", s).emit();
         match attr.meta_kind() {
             Some(MetaItemKind::Word) => {
                 err(attr.span, "expected one argument");
@@ -550,7 +549,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
     if !codegen_fn_attrs.target_features.is_empty() {
         if codegen_fn_attrs.inline == InlineAttr::Always {
             if let Some(span) = inline_span {
-                tcx.sess.span_err(
+                tcx.dcx().span_err(
                     span,
                     "cannot use `#[inline(always)]` with \
                      `#[target_feature]`",
@@ -637,7 +636,7 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
     let sole_meta_list = match meta_item_list {
         Some([item]) => item.lit(),
         Some(_) => {
-            tcx.sess.emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span });
+            tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span });
             return None;
         }
         _ => None,
@@ -661,14 +660,14 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
             Some(*ordinal as u16)
         } else {
             let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
-            tcx.sess
+            tcx.dcx()
                 .struct_span_err(attr.span, msg)
                 .note("the value may not exceed `u16::MAX`")
                 .emit();
             None
         }
     } else {
-        tcx.sess.emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span });
+        tcx.dcx().emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span });
         None
     }
 }
@@ -683,9 +682,9 @@ fn check_link_name_xor_ordinal(
     }
     let msg = "cannot use `#[link_name]` with `#[link_ordinal]`";
     if let Some(span) = inline_span {
-        tcx.sess.span_err(span, msg);
+        tcx.dcx().span_err(span, msg);
     } else {
-        tcx.sess.err(msg);
+        tcx.dcx().err(msg);
     }
 }
 
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 2ecc5ad4fe42c..1b01fe0365462 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -93,7 +93,7 @@ fn push_debuginfo_type_name<'tcx>(
                     Err(e) => {
                         // Computing the layout can still fail here, e.g. if the target architecture
                         // cannot represent the type. See https://github.com/rust-lang/rust/issues/94961.
-                        tcx.sess.emit_fatal(e.into_diagnostic());
+                        tcx.dcx().emit_fatal(e.into_diagnostic());
                     }
                 }
             } else {
diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs
index 558f64fffc263..d532bd9042676 100644
--- a/compiler/rustc_codegen_ssa/src/mir/constant.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs
@@ -94,7 +94,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 bx.const_struct(&values, false)
             })
             .unwrap_or_else(|| {
-                bx.tcx().sess.emit_err(errors::ShuffleIndicesEvaluation { span: constant.span });
+                bx.tcx().dcx().emit_err(errors::ShuffleIndicesEvaluation { span: constant.span });
                 // We've errored, so we don't have to produce working code.
                 let llty = bx.backend_type(bx.layout_of(ty));
                 bx.const_undef(llty)
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index a5bffc33d393c..533803ea7ff2b 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -220,7 +220,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         }
                     }
                     None => {
-                        bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType {
+                        bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
                             span,
                             name,
                             ty,
@@ -240,7 +240,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                         _ => bug!(),
                     },
                     None => {
-                        bx.tcx().sess.emit_err(InvalidMonomorphization::BasicFloatType {
+                        bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicFloatType {
                             span,
                             name,
                             ty: arg_tys[0],
@@ -252,14 +252,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
 
             sym::float_to_int_unchecked => {
                 if float_type_width(arg_tys[0]).is_none() {
-                    bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked {
+                    bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked {
                         span,
                         ty: arg_tys[0],
                     });
                     return;
                 }
                 let Some((_width, signed)) = int_type_width_signed(ret_ty, bx.tcx()) else {
-                    bx.tcx().sess.emit_err(InvalidMonomorphization::FloatToIntUnchecked {
+                    bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked {
                         span,
                         ty: ret_ty,
                     });
@@ -297,7 +297,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 use crate::common::{AtomicRmwBinOp, SynchronizationScope};
 
                 let Some((instruction, ordering)) = atomic.split_once('_') else {
-                    bx.sess().emit_fatal(errors::MissingMemoryOrdering);
+                    bx.sess().dcx().emit_fatal(errors::MissingMemoryOrdering);
                 };
 
                 let parse_ordering = |bx: &Bx, s| match s {
@@ -307,11 +307,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     "release" => Release,
                     "acqrel" => AcquireRelease,
                     "seqcst" => SequentiallyConsistent,
-                    _ => bx.sess().emit_fatal(errors::UnknownAtomicOrdering),
+                    _ => bx.sess().dcx().emit_fatal(errors::UnknownAtomicOrdering),
                 };
 
                 let invalid_monomorphization = |ty| {
-                    bx.tcx().sess.emit_err(InvalidMonomorphization::BasicIntegerType {
+                    bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
                         span,
                         name,
                         ty,
@@ -321,7 +321,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 match instruction {
                     "cxchg" | "cxchgweak" => {
                         let Some((success, failure)) = ordering.split_once('_') else {
-                            bx.sess().emit_fatal(errors::AtomicCompareExchange);
+                            bx.sess().dcx().emit_fatal(errors::AtomicCompareExchange);
                         };
                         let ty = fn_args.type_at(0);
                         if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_unsafe_ptr() {
@@ -437,7 +437,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                             "min" => AtomicRmwBinOp::AtomicMin,
                             "umax" => AtomicRmwBinOp::AtomicUMax,
                             "umin" => AtomicRmwBinOp::AtomicUMin,
-                            _ => bx.sess().emit_fatal(errors::UnknownAtomicOperation),
+                            _ => bx.sess().dcx().emit_fatal(errors::UnknownAtomicOperation),
                         };
 
                         let ty = fn_args.type_at(0);
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 0b9b08c6a24b4..031fcc0adb180 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -25,7 +25,7 @@ pub fn from_target_feature(
     let bad_item = |span| {
         let msg = "malformed `target_feature` attribute input";
         let code = "enable = \"..\"";
-        tcx.sess
+        tcx.dcx()
             .struct_span_err(span, msg)
             .span_suggestion(span, "must be of the form", code, Applicability::HasPlaceholders)
             .emit();
@@ -48,7 +48,7 @@ pub fn from_target_feature(
         target_features.extend(value.as_str().split(',').filter_map(|feature| {
             let Some(feature_gate) = supported_target_features.get(feature) else {
                 let msg = format!("the feature named `{feature}` is not valid for this target");
-                let mut err = tcx.sess.struct_span_err(item.span(), msg);
+                let mut err = tcx.dcx().struct_span_err(item.span(), msg);
                 err.span_label(item.span(), format!("`{feature}` is not valid for this target"));
                 if let Some(stripped) = feature.strip_prefix('+') {
                     let valid = supported_target_features.contains_key(stripped);
@@ -121,7 +121,7 @@ pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_s
     if let DefKind::AssocFn = tcx.def_kind(id) {
         let parent_id = tcx.local_parent(id);
         if let DefKind::Trait | DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) {
-            tcx.sess.emit_err(errors::TargetFeatureSafeTrait {
+            tcx.dcx().emit_err(errors::TargetFeatureSafeTrait {
                 span: attr_span,
                 def: tcx.def_span(id),
             });
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 2cafbb9331d1d..ef39d13d78ab4 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -151,10 +151,10 @@ where
             let (our_span, frames) = get_span_and_frames();
             let span = span.unwrap_or(our_span);
             let err = mk(span, frames);
-            let mut err = tcx.sess.create_err(err);
+            let mut err = tcx.dcx().create_err(err);
 
             let msg = error.diagnostic_message();
-            error.add_args(tcx.sess.dcx(), &mut err);
+            error.add_args(tcx.dcx(), &mut err);
 
             // Use *our* span to label the interp error
             err.span_label(our_span, msg);
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 9aaf6c510d509..7fb5f10c6ca75 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -391,7 +391,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
                 if ecx.tcx.is_ctfe_mir_available(def) {
                     Ok(ecx.tcx.mir_for_ctfe(def))
                 } else if ecx.tcx.def_kind(def) == DefKind::AssocConst {
-                    let guar = ecx.tcx.sess.span_delayed_bug(
+                    let guar = ecx.tcx.dcx().span_delayed_bug(
                         rustc_span::DUMMY_SP,
                         "This is likely a const item that is missing from its impl",
                     );
@@ -621,7 +621,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
                 if is_error {
                     let guard = ecx
                         .tcx
-                        .sess
+                        .dcx()
                         .span_delayed_bug(span, "The deny lint should have already errored");
                     throw_inval!(AlreadyReported(guard.into()));
                 }
@@ -630,7 +630,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
                 // current number of evaluated terminators is a power of 2. The latter gives us a cheap
                 // way to implement exponential backoff.
                 let span = ecx.cur_span();
-                ecx.tcx.sess.emit_warning(LongRunningWarn { span, item_span: ecx.tcx.span });
+                ecx.tcx.dcx().emit_warning(LongRunningWarn { span, item_span: ecx.tcx.span });
             }
         }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index f6942366cbd2e..29cbb7f07e87a 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -61,7 +61,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
             match err {
                 ValTreeCreationError::NodesOverflow => {
                     let span = tcx.hir().span_if_local(did);
-                    tcx.sess.emit_err(MaxNumNodesInConstErr { span, global_const_id });
+                    tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
 
                     Ok(None)
                 }
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index eb9bf52676aa5..110ff87e27ef3 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -439,8 +439,8 @@ pub trait ReportErrorExt {
         Self: Sized,
     {
         ty::tls::with(move |tcx| {
-            let mut builder = tcx.sess.struct_allow(DiagnosticMessage::Str(String::new().into()));
-            let dcx = tcx.sess.dcx();
+            let dcx = tcx.dcx();
+            let mut builder = dcx.struct_allow(DiagnosticMessage::Str(String::new().into()));
             let message = self.diagnostic_message();
             self.add_args(dcx, &mut builder);
             let s = dcx.eagerly_translate_to_string(message, builder.args());
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index af8e5e7d15139..e6370adb983a7 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -473,9 +473,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         backtrace.print_backtrace();
         // FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
         // label and arguments from the InterpError.
-        let dcx = self.tcx.sess.dcx();
+        let dcx = self.tcx.dcx();
         #[allow(rustc::untranslatable_diagnostic)]
-        let mut diag = self.tcx.sess.struct_allow("");
+        let mut diag = dcx.struct_allow("");
         let msg = e.diagnostic_message();
         e.add_args(dcx, &mut diag);
         let s = dcx.eagerly_translate_to_string(msg, diag.args());
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index 7931789e4363b..202819ee6338f 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -96,7 +96,7 @@ fn intern_shallow<'rt, 'mir, 'tcx, M: CompileTimeMachine<'mir, 'tcx, const_eval:
         // in the value the dangling reference lies.
         // The `span_delayed_bug` ensures that we don't forget such a check in validation.
         if tcx.try_get_global_alloc(alloc_id).is_none() {
-            tcx.sess.span_delayed_bug(ecx.tcx.span, "tried to intern dangling pointer");
+            tcx.dcx().span_delayed_bug(ecx.tcx.span, "tried to intern dangling pointer");
         }
         // treat dangling pointers like other statics
         // just to stop trying to recurse into them
@@ -185,7 +185,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx, const_eval::Memory
                 } else {
                     // Validation will error (with a better message) on an invalid vtable pointer.
                     // Let validation show the error message, but make sure it *does* error.
-                    tcx.sess
+                    tcx.dcx()
                         .span_delayed_bug(tcx.span, "vtables pointers cannot be integer pointers");
                 }
             }
@@ -375,7 +375,7 @@ pub fn intern_const_alloc_recursive<
         match res {
             Ok(()) => {}
             Err(error) => {
-                ecx.tcx.sess.span_delayed_bug(
+                ecx.tcx.dcx().span_delayed_bug(
                     ecx.tcx.span,
                     format!(
                         "error during interning should later cause validation failure: {}",
@@ -424,7 +424,7 @@ pub fn intern_const_alloc_recursive<
                 // something that cannot be promoted, which in constants means values that have
                 // drop glue, such as the example above.
                 InternKind::Constant => {
-                    ecx.tcx.sess.emit_err(UnsupportedUntypedPointer { span: ecx.tcx.span });
+                    ecx.tcx.dcx().emit_err(UnsupportedUntypedPointer { span: ecx.tcx.span });
                     // For better errors later, mark the allocation as immutable.
                     alloc.mutability = Mutability::Not;
                 }
@@ -440,7 +440,7 @@ pub fn intern_const_alloc_recursive<
         } else if ecx.memory.dead_alloc_map.contains_key(&alloc_id) {
             // Codegen does not like dangling pointers, and generally `tcx` assumes that
             // all allocations referenced anywhere actually exist. So, make sure we error here.
-            let reported = ecx.tcx.sess.emit_err(DanglingPtrInFinal { span: ecx.tcx.span });
+            let reported = ecx.tcx.dcx().emit_err(DanglingPtrInFinal { span: ecx.tcx.span });
             return Err(reported);
         } else if ecx.tcx.try_get_global_alloc(alloc_id).is_none() {
             // We have hit an `AllocId` that is neither in local or global memory and isn't
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index bf7adf8f44cd7..c1ab62ac0b86e 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -244,7 +244,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
         // `async` functions cannot be `const fn`. This is checked during AST lowering, so there's
         // no need to emit duplicate errors here.
         if self.ccx.is_async() || body.coroutine.is_some() {
-            tcx.sess.span_delayed_bug(body.span, "`async` functions cannot be `const fn`");
+            tcx.dcx().span_delayed_bug(body.span, "`async` functions cannot be `const fn`");
             return;
         }
 
@@ -276,10 +276,10 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
         let secondary_errors = mem::take(&mut self.secondary_errors);
         if self.error_emitted.is_none() {
             for error in secondary_errors {
-                self.tcx.sess.dcx().emit_diagnostic(error);
+                self.tcx.dcx().emit_diagnostic(error);
             }
         } else {
-            assert!(self.tcx.sess.has_errors().is_some());
+            assert!(self.tcx.dcx().has_errors().is_some());
         }
     }
 
@@ -354,7 +354,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
     fn check_static(&mut self, def_id: DefId, span: Span) {
         if self.tcx.is_thread_local_static(def_id) {
             self.tcx
-                .sess
+                .dcx()
                 .span_delayed_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`");
         }
         self.check_op_spanned(ops::StaticAccess, span)
@@ -994,5 +994,5 @@ fn is_int_bool_or_char(ty: Ty<'_>) -> bool {
 fn emit_unstable_in_stable_error(ccx: &ConstCx<'_, '_>, span: Span, gate: Symbol) {
     let attr_span = ccx.tcx.def_span(ccx.def_id()).shrink_to_lo();
 
-    ccx.tcx.sess.emit_err(UnstableInStable { gate: gate.to_string(), span, attr_span });
+    ccx.dcx().emit_err(UnstableInStable { gate: gate.to_string(), span, attr_span });
 }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index 4f7e165c575f8..fbc95072802f9 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -5,6 +5,7 @@
 //! it finds operations that are invalid in a certain context.
 
 use rustc_attr as attr;
+use rustc_errors::DiagCtxt;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::mir;
@@ -44,6 +45,10 @@ impl<'mir, 'tcx> ConstCx<'mir, 'tcx> {
         ConstCx { body, tcx, param_env, const_kind }
     }
 
+    pub(crate) fn dcx(&self) -> &'tcx DiagCtxt {
+        self.tcx.dcx()
+    }
+
     pub fn def_id(&self) -> LocalDefId {
         self.body.source.def_id().expect_local()
     }
@@ -112,7 +117,7 @@ pub fn is_const_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
         None if is_parent_const_stable_trait(tcx, def_id) => {
             // Remove this when `#![feature(const_trait_impl)]` is stabilized,
             // returning `true` unconditionally.
-            tcx.sess.span_delayed_bug(
+            tcx.dcx().span_delayed_bug(
                 tcx.def_span(def_id),
                 "trait implementations cannot be const stable yet",
             );
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index 532cd9c261fd3..02952872a9385 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -77,7 +77,7 @@ impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
 pub struct FnCallIndirect;
 impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        ccx.tcx.sess.create_err(errors::UnallowedFnPointerCall { span, kind: ccx.const_kind() })
+        ccx.dcx().create_err(errors::UnallowedFnPointerCall { span, kind: ccx.const_kind() })
     }
 }
 
@@ -148,7 +148,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
             CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
                 macro_rules! error {
                     ($err:ident) => {
-                        tcx.sess.create_err(errors::$err {
+                        tcx.dcx().create_err(errors::$err {
                             span,
                             ty: self_ty,
                             kind: ccx.const_kind(),
@@ -192,7 +192,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                     _ => None,
                 };
 
-                let mut err = tcx.sess.create_err(errors::NonConstClosure {
+                let mut err = tcx.dcx().create_err(errors::NonConstClosure {
                     span,
                     kind: ccx.const_kind(),
                     note,
@@ -203,7 +203,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
             }
             CallKind::Operator { trait_id, self_ty, .. } => {
                 let mut err = if let CallSource::MatchCmp = call_source {
-                    tcx.sess.create_err(errors::NonConstMatchEq {
+                    tcx.dcx().create_err(errors::NonConstMatchEq {
                         span,
                         kind: ccx.const_kind(),
                         ty: self_ty,
@@ -248,7 +248,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                             _ => {}
                         }
                     }
-                    tcx.sess.create_err(errors::NonConstOperator {
+                    tcx.dcx().create_err(errors::NonConstOperator {
                         span,
                         kind: ccx.const_kind(),
                         sugg,
@@ -266,7 +266,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                     None
                 };
 
-                let mut err = tcx.sess.create_err(errors::NonConstDerefCoercion {
+                let mut err = tcx.dcx().create_err(errors::NonConstDerefCoercion {
                     span,
                     ty: self_ty,
                     kind: ccx.const_kind(),
@@ -277,11 +277,10 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
                 diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span)));
                 err
             }
-            _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => ccx
-                .tcx
-                .sess
-                .create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() }),
-            _ => ccx.tcx.sess.create_err(errors::NonConstFnCall {
+            _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => {
+                ccx.dcx().create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() })
+            }
+            _ => ccx.dcx().create_err(errors::NonConstFnCall {
                 span,
                 def_path_str: ccx.tcx.def_path_str_with_args(callee, args),
                 kind: ccx.const_kind(),
@@ -319,8 +318,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
         let FnCallUnstable(def_id, feature) = *self;
 
         let mut err = ccx
-            .tcx
-            .sess
+            .dcx()
             .create_err(errors::UnstableConstFn { span, def_path: ccx.tcx.def_path_str(def_id) });
 
         if ccx.is_const_stable_const_fn() {
@@ -362,7 +360,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
                 sym::const_async_blocks,
             )
         } else {
-            ccx.tcx.sess.create_err(errors::UnallowedOpInConstContext { span, msg })
+            ccx.dcx().create_err(errors::UnallowedOpInConstContext { span, msg })
         }
     }
 }
@@ -371,7 +369,7 @@ impl<'tcx> NonConstOp<'tcx> for Coroutine {
 pub struct HeapAllocation;
 impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        ccx.tcx.sess.create_err(errors::UnallowedHeapAllocations {
+        ccx.dcx().create_err(errors::UnallowedHeapAllocations {
             span,
             kind: ccx.const_kind(),
             teach: ccx.tcx.sess.teach(&error_code!(E0010)).then_some(()),
@@ -383,7 +381,7 @@ impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
 pub struct InlineAsm;
 impl<'tcx> NonConstOp<'tcx> for InlineAsm {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        ccx.tcx.sess.create_err(errors::UnallowedInlineAsm { span, kind: ccx.const_kind() })
+        ccx.dcx().create_err(errors::UnallowedInlineAsm { span, kind: ccx.const_kind() })
     }
 }
 
@@ -394,7 +392,7 @@ pub struct LiveDrop<'tcx> {
 }
 impl<'tcx> NonConstOp<'tcx> for LiveDrop<'tcx> {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        ccx.tcx.sess.create_err(errors::LiveDrop {
+        ccx.dcx().create_err(errors::LiveDrop {
             span,
             dropped_ty: self.dropped_ty,
             kind: ccx.const_kind(),
@@ -432,14 +430,14 @@ impl<'tcx> NonConstOp<'tcx> for CellBorrow {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         // FIXME: Maybe a more elegant solution to this if else case
         if let hir::ConstContext::Static(_) = ccx.const_kind() {
-            ccx.tcx.sess.create_err(errors::InteriorMutableDataRefer {
+            ccx.dcx().create_err(errors::InteriorMutableDataRefer {
                 span,
                 opt_help: Some(()),
                 kind: ccx.const_kind(),
                 teach: ccx.tcx.sess.teach(&error_code!(E0492)).then_some(()),
             })
         } else {
-            ccx.tcx.sess.create_err(errors::InteriorMutableDataRefer {
+            ccx.dcx().create_err(errors::InteriorMutableDataRefer {
                 span,
                 opt_help: None,
                 kind: ccx.const_kind(),
@@ -468,12 +466,12 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow {
 
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         match self.0 {
-            hir::BorrowKind::Raw => ccx.tcx.sess.create_err(errors::UnallowedMutableRefsRaw {
+            hir::BorrowKind::Raw => ccx.dcx().create_err(errors::UnallowedMutableRefsRaw {
                 span,
                 kind: ccx.const_kind(),
                 teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()),
             }),
-            hir::BorrowKind::Ref => ccx.tcx.sess.create_err(errors::UnallowedMutableRefs {
+            hir::BorrowKind::Ref => ccx.dcx().create_err(errors::UnallowedMutableRefs {
                 span,
                 kind: ccx.const_kind(),
                 teach: ccx.tcx.sess.teach(&error_code!(E0764)).then_some(()),
@@ -530,7 +528,7 @@ impl<'tcx> NonConstOp<'tcx> for MutDeref {
 pub struct PanicNonStr;
 impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        ccx.tcx.sess.create_err(errors::PanicNonStrErr { span })
+        ccx.dcx().create_err(errors::PanicNonStrErr { span })
     }
 }
 
@@ -542,7 +540,7 @@ pub struct RawPtrComparison;
 impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         // FIXME(const_trait_impl): revert to span_bug?
-        ccx.tcx.sess.create_err(errors::RawPtrComparisonErr { span })
+        ccx.dcx().create_err(errors::RawPtrComparisonErr { span })
     }
 }
 
@@ -570,7 +568,7 @@ impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
 pub struct RawPtrToIntCast;
 impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        ccx.tcx.sess.create_err(errors::RawPtrToIntErr { span })
+        ccx.dcx().create_err(errors::RawPtrToIntErr { span })
     }
 }
 
@@ -587,7 +585,7 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess {
     }
 
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        ccx.tcx.sess.create_err(errors::StaticAccessErr {
+        ccx.dcx().create_err(errors::StaticAccessErr {
             span,
             kind: ccx.const_kind(),
             teach: ccx.tcx.sess.teach(&error_code!(E0013)).then_some(()),
@@ -600,7 +598,7 @@ impl<'tcx> NonConstOp<'tcx> for StaticAccess {
 pub struct ThreadLocalAccess;
 impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
-        ccx.tcx.sess.create_err(errors::NonConstOpErr { span })
+        ccx.dcx().create_err(errors::NonConstOpErr { span })
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 2f538cebaa653..68ded1d324fe8 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -119,7 +119,7 @@ impl<'a, 'tcx> CfgChecker<'a, 'tcx> {
         let span = self.body.source_info(location).span;
         // We use `span_delayed_bug` as we might see broken MIR when other errors have already
         // occurred.
-        self.tcx.sess.dcx().span_delayed_bug(
+        self.tcx.dcx().span_delayed_bug(
             span,
             format!(
                 "broken MIR in {:?} ({}) at {:?}:\n{}",
@@ -527,7 +527,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CfgChecker<'a, 'tcx> {
 
     fn visit_source_scope(&mut self, scope: SourceScope) {
         if self.body.source_scopes.get(scope).is_none() {
-            self.tcx.sess.dcx().span_delayed_bug(
+            self.tcx.dcx().span_delayed_bug(
                 self.body.span,
                 format!(
                     "broken MIR in {:?} ({}):\ninvalid source scope {:?}",
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index c277304fb221c..ca6b0afc76a9b 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -150,7 +150,7 @@ pub const DEFAULT_BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issu
 pub fn abort_on_err<T>(result: Result<T, ErrorGuaranteed>, sess: &Session) -> T {
     match result {
         Err(..) => {
-            sess.abort_if_errors();
+            sess.dcx().abort_if_errors();
             panic!("error reported but abort_if_errors didn't abort???");
         }
         Ok(x) => x,
@@ -640,20 +640,22 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) {
 
 fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
     assert!(sess.opts.unstable_opts.link_only);
+    let dcx = sess.dcx();
     if let Input::File(file) = &sess.io.input {
         let rlink_data = fs::read(file).unwrap_or_else(|err| {
-            sess.emit_fatal(RlinkUnableToRead { err });
+            dcx.emit_fatal(RlinkUnableToRead { err });
         });
         let (codegen_results, outputs) = match CodegenResults::deserialize_rlink(sess, rlink_data) {
             Ok((codegen, outputs)) => (codegen, outputs),
             Err(err) => {
                 match err {
-                    CodegenErrors::WrongFileType => sess.emit_fatal(RLinkWrongFileType),
-                    CodegenErrors::EmptyVersionNumber => sess.emit_fatal(RLinkEmptyVersionNumber),
+                    CodegenErrors::WrongFileType => dcx.emit_fatal(RLinkWrongFileType),
+                    CodegenErrors::EmptyVersionNumber => dcx.emit_fatal(RLinkEmptyVersionNumber),
                     CodegenErrors::EncodingVersionMismatch { version_array, rlink_version } => sess
+                        .dcx()
                         .emit_fatal(RLinkEncodingVersionMismatch { version_array, rlink_version }),
                     CodegenErrors::RustcVersionMismatch { rustc_version } => {
-                        sess.emit_fatal(RLinkRustcVersionMismatch {
+                        dcx.emit_fatal(RLinkRustcVersionMismatch {
                             rustc_version,
                             current_version: sess.cfg_version,
                         })
@@ -664,7 +666,7 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
         let result = compiler.codegen_backend.link(sess, codegen_results, &outputs);
         abort_on_err(result, sess);
     } else {
-        sess.emit_fatal(RlinkNotAFile {})
+        dcx.emit_fatal(RlinkNotAFile {})
     }
 }
 
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 4703e71523dde..ae54d343dad96 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -546,8 +546,8 @@ impl<G: EmissionGuarantee> Drop for DiagnosticBuilder<'_, G> {
 
 #[macro_export]
 macro_rules! struct_span_err {
-    ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
-        $session.struct_span_err_with_code(
+    ($dcx:expr, $span:expr, $code:ident, $($message:tt)*) => ({
+        $dcx.struct_span_err_with_code(
             $span,
             format!($($message)*),
             $crate::error_code!($code),
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 7a1faac04d3a7..e436591fdd99b 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -980,10 +980,22 @@ impl DiagCtxt {
         self.struct_span_bug(span, msg).emit()
     }
 
-    /// For documentation on this, see `Session::span_delayed_bug`.
+    /// Ensures that compilation cannot succeed.
+    ///
+    /// If this function has been called but no errors have been emitted and
+    /// compilation succeeds, it will cause an internal compiler error (ICE).
+    ///
+    /// This can be used in code paths that should never run on successful compilations.
+    /// For example, it can be used to create an [`ErrorGuaranteed`]
+    /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission
+    /// directly).
+    ///
+    /// If no span is available, use [`DUMMY_SP`].
+    ///
+    /// [`DUMMY_SP`]: rustc_span::DUMMY_SP
     ///
     /// Note: this function used to be called `delay_span_bug`. It was renamed
-    /// to match similar functions like `span_bug`, `span_err`, etc.
+    /// to match similar functions like `span_err`, `span_warn`, etc.
     #[track_caller]
     pub fn span_delayed_bug(
         &self,
@@ -1203,6 +1215,7 @@ impl DiagCtxt {
         self.inner.borrow_mut().emit_diagnostic_without_consuming(diagnostic)
     }
 
+    #[track_caller]
     pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
         self.create_err(err).emit()
     }
@@ -1212,6 +1225,7 @@ impl DiagCtxt {
         err.into_diagnostic(self, Error { lint: false })
     }
 
+    #[track_caller]
     pub fn create_warning<'a>(
         &'a self,
         warning: impl IntoDiagnostic<'a, ()>,
@@ -1219,10 +1233,12 @@ impl DiagCtxt {
         warning.into_diagnostic(self, Warning(None))
     }
 
+    #[track_caller]
     pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
         self.create_warning(warning).emit()
     }
 
+    #[track_caller]
     pub fn create_almost_fatal<'a>(
         &'a self,
         fatal: impl IntoDiagnostic<'a, FatalError>,
@@ -1230,6 +1246,7 @@ impl DiagCtxt {
         fatal.into_diagnostic(self, Fatal)
     }
 
+    #[track_caller]
     pub fn emit_almost_fatal<'a>(
         &'a self,
         fatal: impl IntoDiagnostic<'a, FatalError>,
@@ -1237,6 +1254,7 @@ impl DiagCtxt {
         self.create_almost_fatal(fatal).emit()
     }
 
+    #[track_caller]
     pub fn create_fatal<'a>(
         &'a self,
         fatal: impl IntoDiagnostic<'a, FatalAbort>,
@@ -1244,10 +1262,12 @@ impl DiagCtxt {
         fatal.into_diagnostic(self, Fatal)
     }
 
+    #[track_caller]
     pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! {
         self.create_fatal(fatal).emit()
     }
 
+    #[track_caller]
     pub fn create_bug<'a>(
         &'a self,
         bug: impl IntoDiagnostic<'a, BugAbort>,
@@ -1255,14 +1275,17 @@ impl DiagCtxt {
         bug.into_diagnostic(self, Bug)
     }
 
-    pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, BugAbort>) -> ! {
+    #[track_caller]
+    pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, diagnostic_builder::BugAbort>) -> ! {
         self.create_bug(bug).emit()
     }
 
+    #[track_caller]
     pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) {
         self.create_note(note).emit()
     }
 
+    #[track_caller]
     pub fn create_note<'a>(
         &'a self,
         note: impl IntoDiagnostic<'a, ()>,
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 1fd4d2d55dd81..8b5a22d191464 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -14,10 +14,7 @@ use rustc_ast::{self as ast, AttrVec, Attribute, HasAttrs, Item, NodeId, PatKind
 use rustc_attr::{self as attr, Deprecation, Stability};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::{self, Lrc};
-use rustc_errors::{
-    Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic,
-    MultiSpan, PResult,
-};
+use rustc_errors::{Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, PResult};
 use rustc_feature::Features;
 use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools};
@@ -800,13 +797,13 @@ impl SyntaxExtension {
         let const_stability = attr::find_const_stability(sess, attrs, span);
         let body_stability = attr::find_body_stability(sess, attrs);
         if let Some((_, sp)) = const_stability {
-            sess.emit_err(errors::MacroConstStability {
+            sess.dcx().emit_err(errors::MacroConstStability {
                 span: sp,
                 head_span: sess.source_map().guess_head_span(span),
             });
         }
         if let Some((_, sp)) = body_stability {
-            sess.emit_err(errors::MacroBodyStability {
+            sess.dcx().emit_err(errors::MacroBodyStability {
                 span: sp,
                 head_span: sess.source_map().guess_head_span(span),
             });
@@ -1058,6 +1055,10 @@ impl<'a> ExtCtxt<'a> {
         }
     }
 
+    pub fn dcx(&self) -> &'a DiagCtxt {
+        self.sess.dcx()
+    }
+
     /// Returns a `Folder` for deeply expanding all macros in an AST node.
     pub fn expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> {
         expand::MacroExpander::new(self, false)
@@ -1112,42 +1113,9 @@ impl<'a> ExtCtxt<'a> {
         self.current_expansion.id.expansion_cause()
     }
 
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_span_err<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'a> {
-        self.sess.dcx().struct_span_err(sp, msg)
-    }
-
-    #[track_caller]
-    pub fn create_err(&self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> {
-        self.sess.create_err(err)
-    }
-
-    #[track_caller]
-    pub fn emit_err(&self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
-        self.sess.emit_err(err)
-    }
-
-    /// Emit `msg` attached to `sp`, without immediately stopping
-    /// compilation.
-    ///
-    /// Compilation will be stopped in the near future (at the end of
-    /// the macro expansion phase).
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
-        self.sess.dcx().span_err(sp, msg);
-    }
-    pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.sess.dcx().span_bug(sp, msg);
-    }
     pub fn trace_macros_diag(&mut self) {
         for (span, notes) in self.expansions.iter() {
-            let mut db = self.sess.parse_sess.create_note(errors::TraceMacro { span: *span });
+            let mut db = self.dcx().create_note(errors::TraceMacro { span: *span });
             for note in notes {
                 db.note(note.clone());
             }
@@ -1156,10 +1124,6 @@ impl<'a> ExtCtxt<'a> {
         // Fixme: does this result in errors?
         self.expansions.clear();
     }
-    #[rustc_lint_diagnostics]
-    pub fn bug(&self, msg: &'static str) -> ! {
-        self.sess.dcx().bug(msg);
-    }
     pub fn trace_macros(&self) -> bool {
         self.ecfg.trace_mac
     }
@@ -1236,7 +1200,7 @@ pub fn expr_to_spanned_string<'a>(
         ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) {
             Ok(ast::LitKind::Str(s, style)) => return Ok((s, style, expr.span)),
             Ok(ast::LitKind::ByteStr(..)) => {
-                let mut err = cx.struct_span_err(expr.span, err_msg);
+                let mut err = cx.dcx().struct_span_err(expr.span, err_msg);
                 let span = expr.span.shrink_to_lo();
                 err.span_suggestion(
                     span.with_hi(span.lo() + BytePos(1)),
@@ -1251,10 +1215,10 @@ pub fn expr_to_spanned_string<'a>(
                 report_lit_error(&cx.sess.parse_sess, err, token_lit, expr.span);
                 None
             }
-            _ => Some((cx.struct_span_err(expr.span, err_msg), false)),
+            _ => Some((cx.dcx().struct_span_err(expr.span, err_msg), false)),
         },
         ast::ExprKind::Err => None,
-        _ => Some((cx.struct_span_err(expr.span, err_msg), false)),
+        _ => Some((cx.dcx().struct_span_err(expr.span, err_msg), false)),
     })
 }
 
@@ -1282,7 +1246,7 @@ pub fn expr_to_string(
 /// (this should be done as rarely as possible).
 pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str) {
     if !tts.is_empty() {
-        cx.emit_err(errors::TakesNoArguments { span, name });
+        cx.dcx().emit_err(errors::TakesNoArguments { span, name });
     }
 }
 
@@ -1310,14 +1274,14 @@ pub fn get_single_str_from_tts(
 ) -> Option<Symbol> {
     let mut p = cx.new_parser_from_tts(tts);
     if p.token == token::Eof {
-        cx.emit_err(errors::OnlyOneArgument { span, name });
+        cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
         return None;
     }
     let ret = parse_expr(&mut p)?;
     let _ = p.eat(&token::Comma);
 
     if p.token != token::Eof {
-        cx.emit_err(errors::OnlyOneArgument { span, name });
+        cx.dcx().emit_err(errors::OnlyOneArgument { span, name });
     }
     expr_to_string(cx, ret, "argument must be a string literal").map(|(s, _)| s)
 }
@@ -1339,7 +1303,7 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, tts: TokenStream) -> Option<Vec<
             continue;
         }
         if p.token != token::Eof {
-            cx.emit_err(errors::ExpectedCommaInList { span: p.token.span });
+            cx.dcx().emit_err(errors::ExpectedCommaInList { span: p.token.span });
             return None;
         }
     }
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 0b56dbb2c1904..2283a3bfc7606 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -51,7 +51,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
             let name = match mi.ident() {
                 Some(ident) if mi.is_word() => ident.name,
                 Some(ident) => {
-                    sess.emit_err(MalformedFeatureAttribute {
+                    sess.dcx().emit_err(MalformedFeatureAttribute {
                         span: mi.span(),
                         help: MalformedFeatureAttributeHelp::Suggestion {
                             span: mi.span(),
@@ -61,7 +61,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
                     continue;
                 }
                 None => {
-                    sess.emit_err(MalformedFeatureAttribute {
+                    sess.dcx().emit_err(MalformedFeatureAttribute {
                         span: mi.span(),
                         help: MalformedFeatureAttributeHelp::Label { span: mi.span() },
                     });
@@ -71,7 +71,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
 
             // If the declared feature has been removed, issue an error.
             if let Some(f) = REMOVED_FEATURES.iter().find(|f| name == f.feature.name) {
-                sess.emit_err(FeatureRemoved {
+                sess.dcx().emit_err(FeatureRemoved {
                     span: mi.span(),
                     reason: f.reason.map(|reason| FeatureRemovedReason { reason }),
                 });
@@ -90,7 +90,7 @@ pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -
             // issue an error.
             if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() {
                 if allowed.iter().all(|f| name.as_str() != f) {
-                    sess.emit_err(FeatureNotAllowed { span: mi.span(), name });
+                    sess.dcx().emit_err(FeatureNotAllowed { span: mi.span(), name });
                     continue;
                 }
             }
@@ -415,7 +415,7 @@ impl<'a> StripUnconfigured<'a> {
         // N.B., this is intentionally not part of the visit_expr() function
         //     in order for filter_map_expr() to be able to avoid this check
         if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
-            self.sess.emit_err(RemoveExprNotSupported { span: attr.span });
+            self.sess.dcx().emit_err(RemoveExprNotSupported { span: attr.span });
         }
 
         self.process_cfg_attrs(expr);
@@ -427,21 +427,21 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta
     let span = meta_item.span;
     match meta_item.meta_item_list() {
         None => {
-            sess.emit_err(InvalidCfg::NotFollowedByParens { span });
+            sess.dcx().emit_err(InvalidCfg::NotFollowedByParens { span });
             None
         }
         Some([]) => {
-            sess.emit_err(InvalidCfg::NoPredicate { span });
+            sess.dcx().emit_err(InvalidCfg::NoPredicate { span });
             None
         }
         Some([_, .., l]) => {
-            sess.emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
+            sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
             None
         }
         Some([single]) => match single.meta_item() {
             Some(meta_item) => Some(meta_item),
             None => {
-                sess.emit_err(InvalidCfg::PredicateLiteral { span: single.span() });
+                sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() });
                 None
             }
         },
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index da727ddb208f6..676f9f17976cf 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -435,7 +435,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 invocations = mem::take(&mut undetermined_invocations);
                 force = !mem::replace(&mut progress, false);
                 if force && self.monotonic {
-                    self.cx.sess.span_delayed_bug(
+                    self.cx.dcx().span_delayed_bug(
                         invocations.last().unwrap().0.span(),
                         "expansion entered force mode without producing any errors",
                     );
@@ -513,7 +513,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 }
                 ExpandResult::Retry(invoc) => {
                     if force {
-                        self.cx.span_bug(
+                        self.cx.dcx().span_bug(
                             invoc.span(),
                             "expansion entered force mode but is still stuck",
                         );
@@ -611,7 +611,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             limit => limit * 2,
         };
 
-        self.cx.emit_err(RecursionLimitReached {
+        self.cx.dcx().emit_err(RecursionLimitReached {
             span: expn_data.call_site,
             descr: expn_data.kind.descr(),
             suggested_limit,
@@ -624,7 +624,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
     /// A macro's expansion does not fit in this fragment kind.
     /// For example, a non-type macro in a type position.
     fn error_wrong_fragment_kind(&mut self, kind: AstFragmentKind, mac: &ast::MacCall, span: Span) {
-        self.cx.emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path });
+        self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path });
 
         self.cx.trace_macros_diag();
     }
@@ -702,7 +702,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                     };
                     let attr_item = attr.unwrap_normal_item();
                     if let AttrArgs::Eq(..) = attr_item.args {
-                        self.cx.emit_err(UnsupportedKeyValue { span });
+                        self.cx.dcx().emit_err(UnsupportedKeyValue { span });
                     }
                     let inner_tokens = attr_item.args.inner_tokens();
                     let Ok(tok_result) = expander.expand(self.cx, span, inner_tokens, tokens)
@@ -729,7 +729,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                                 AstFragmentKind::Expr | AstFragmentKind::MethodReceiverExpr
                             ) && items.is_empty()
                             {
-                                self.cx.emit_err(RemoveExprNotSupported { span });
+                                self.cx.dcx().emit_err(RemoveExprNotSupported { span });
                                 fragment_kind.dummy(span)
                             } else {
                                 fragment_kind.expect_from_annotatables(items)
@@ -957,7 +957,7 @@ pub fn ensure_complete_parse<'a>(
 
         let expands_to_match_arm = kind_name == "pattern" && parser.token == token::FatArrow;
 
-        parser.sess.emit_err(IncompleteParse {
+        parser.dcx().emit_err(IncompleteParse {
             span: def_site_span,
             token,
             label_span: span,
@@ -1050,7 +1050,7 @@ trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
         _pos: usize,
         span: Span,
     ) {
-        collector.cx.emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });
+        collector.cx.dcx().emit_err(RemoveNodeNotSupported { span, descr: Self::descr() });
     }
 
     /// All of the names (items) declared by this node.
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index b6718ec8c411b..2746e888b8da2 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -34,7 +34,10 @@ pub(super) fn failed_to_match_macro<'cx>(
     if try_success_result.is_ok() {
         // Nonterminal parser recovery might turn failed matches into successful ones,
         // but for that it must have emitted an error already
-        tracker.cx.sess.span_delayed_bug(sp, "Macro matching returned a success on the second try");
+        tracker
+            .cx
+            .dcx()
+            .span_delayed_bug(sp, "Macro matching returned a success on the second try");
     }
 
     if let Some(result) = tracker.result {
@@ -49,7 +52,7 @@ pub(super) fn failed_to_match_macro<'cx>(
 
     let span = token.span.substitute_dummy(sp);
 
-    let mut err = cx.struct_span_err(span, parse_failure_msg(&token));
+    let mut err = cx.dcx().struct_span_err(span, parse_failure_msg(&token));
     err.span_label(span, label);
     if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
         err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
@@ -151,7 +154,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
             Success(_) => {
                 // Nonterminal parser recovery might turn failed matches into successful ones,
                 // but for that it must have emitted an error already
-                self.cx.sess.span_delayed_bug(
+                self.cx.dcx().span_delayed_bug(
                     self.root_span,
                     "should not collect detailed info for successful macro match",
                 );
@@ -177,7 +180,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
             }
             Error(err_sp, msg) => {
                 let span = err_sp.substitute_dummy(self.root_span);
-                self.cx.struct_span_err(span, msg.clone()).emit();
+                self.cx.dcx().struct_span_err(span, msg.clone()).emit();
                 self.result = Some(DummyResult::any(span));
             }
             ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)),
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 44f10e7d3804c..e9736d6f2c8ae 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -208,7 +208,7 @@ fn expand_macro<'cx>(
         Ok((i, named_matches)) => {
             let (rhs, rhs_span): (&mbe::Delimited, DelimSpan) = match &rhses[i] {
                 mbe::TokenTree::Delimited(span, _, delimited) => (&delimited, *span),
-                _ => cx.span_bug(sp, "malformed macro rhs"),
+                _ => cx.dcx().span_bug(sp, "malformed macro rhs"),
             };
             let arm_span = rhses[i].span();
 
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index ac5f3fb325d95..f2a9875ffd28a 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -185,7 +185,9 @@ pub(super) fn transcribe<'a>(
             seq @ mbe::TokenTree::Sequence(_, delimited) => {
                 match lockstep_iter_size(seq, interp, &repeats) {
                     LockstepIterSize::Unconstrained => {
-                        return Err(cx.create_err(NoSyntaxVarsExprRepeat { span: seq.span() }));
+                        return Err(cx
+                            .dcx()
+                            .create_err(NoSyntaxVarsExprRepeat { span: seq.span() }));
                     }
 
                     LockstepIterSize::Contradiction(msg) => {
@@ -193,7 +195,9 @@ pub(super) fn transcribe<'a>(
                         // happens when two meta-variables are used in the same repetition in a
                         // sequence, but they come from different sequence matchers and repeat
                         // different amounts.
-                        return Err(cx.create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg }));
+                        return Err(cx
+                            .dcx()
+                            .create_err(MetaVarsDifSeqMatchers { span: seq.span(), msg }));
                     }
 
                     LockstepIterSize::Constraint(len, _) => {
@@ -207,7 +211,9 @@ pub(super) fn transcribe<'a>(
                                 // FIXME: this really ought to be caught at macro definition
                                 // time... It happens when the Kleene operator in the matcher and
                                 // the body for the same meta-variable do not match.
-                                return Err(cx.create_err(MustRepeatOnce { span: sp.entire() }));
+                                return Err(cx
+                                    .dcx()
+                                    .create_err(MustRepeatOnce { span: sp.entire() }));
                             }
                         } else {
                             // 0 is the initial counter (we have done 0 repetitions so far). `len`
@@ -249,7 +255,7 @@ pub(super) fn transcribe<'a>(
                         }
                         MatchedSeq(..) => {
                             // We were unable to descend far enough. This is an error.
-                            return Err(cx.create_err(VarStillRepeating { span: sp, ident }));
+                            return Err(cx.dcx().create_err(VarStillRepeating { span: sp, ident }));
                         }
                     }
                 } else {
@@ -501,7 +507,7 @@ fn count_repetitions<'a>(
     }
 
     if let MatchedTokenTree(_) | MatchedNonterminal(_) = matched {
-        return Err(cx.create_err(CountRepetitionMisplaced { span: sp.entire() }));
+        return Err(cx.dcx().create_err(CountRepetitionMisplaced { span: sp.entire() }));
     }
 
     count(cx, depth_user, depth_max, matched, sp)
@@ -518,7 +524,7 @@ where
 {
     let span = ident.span;
     let key = MacroRulesNormalizedIdent::new(ident);
-    interp.get(&key).ok_or_else(|| cx.create_err(MetaVarExprUnrecognizedVar { span, key }))
+    interp.get(&key).ok_or_else(|| cx.dcx().create_err(MetaVarExprUnrecognizedVar { span, key }))
 }
 
 /// Used by meta-variable expressions when an user input is out of the actual declared bounds. For
@@ -540,7 +546,7 @@ fn out_of_bounds_err<'a>(
              must be less than {max}"
         )
     };
-    cx.struct_span_err(span, msg)
+    cx.dcx().struct_span_err(span, msg)
 }
 
 fn transcribe_metavar_expr<'a>(
diff --git a/compiler/rustc_expand/src/module.rs b/compiler/rustc_expand/src/module.rs
index cd59ea9092c12..60647c3350a31 100644
--- a/compiler/rustc_expand/src/module.rs
+++ b/compiler/rustc_expand/src/module.rs
@@ -260,14 +260,14 @@ impl ModError<'_> {
 
                 let modules = paths.join(" -> ");
 
-                sess.emit_err(ModuleCircular { span, modules })
+                sess.dcx().emit_err(ModuleCircular { span, modules })
             }
-            ModError::ModInBlock(ident) => sess.emit_err(ModuleInBlock {
+            ModError::ModInBlock(ident) => sess.dcx().emit_err(ModuleInBlock {
                 span,
                 name: ident.map(|name| ModuleInBlockName { span, name }),
             }),
             ModError::FileNotFound(name, default_path, secondary_path) => {
-                sess.emit_err(ModuleFileNotFound {
+                sess.dcx().emit_err(ModuleFileNotFound {
                     span,
                     name,
                     default_path: default_path.display().to_string(),
@@ -275,7 +275,7 @@ impl ModError<'_> {
                 })
             }
             ModError::MultipleCandidates(name, default_path, secondary_path) => {
-                sess.emit_err(ModuleMultipleCandidates {
+                sess.dcx().emit_err(ModuleMultipleCandidates {
                     span,
                     name,
                     default_path: default_path.display().to_string(),
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 429bfa614503a..73a7d433b5c68 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -61,7 +61,7 @@ impl base::BangProcMacro for BangProcMacro {
         let strategy = exec_strategy(ecx);
         let server = proc_macro_server::Rustc::new(ecx);
         self.client.run(&strategy, server, input, proc_macro_backtrace).map_err(|e| {
-            ecx.sess.emit_err(errors::ProcMacroPanicked {
+            ecx.dcx().emit_err(errors::ProcMacroPanicked {
                 span,
                 message: e
                     .as_str()
@@ -93,7 +93,7 @@ impl base::AttrProcMacro for AttrProcMacro {
         let server = proc_macro_server::Rustc::new(ecx);
         self.client.run(&strategy, server, annotation, annotated, proc_macro_backtrace).map_err(
             |e| {
-                let mut err = ecx.struct_span_err(span, "custom attribute panicked");
+                let mut err = ecx.dcx().struct_span_err(span, "custom attribute panicked");
                 if let Some(s) = e.as_str() {
                     err.help(format!("message: {s}"));
                 }
@@ -146,7 +146,7 @@ impl MultiItemModifier for DeriveProcMacro {
             match self.client.run(&strategy, server, input, proc_macro_backtrace) {
                 Ok(stream) => stream,
                 Err(e) => {
-                    let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
+                    let mut err = ecx.dcx().struct_span_err(span, "proc-macro derive panicked");
                     if let Some(s) = e.as_str() {
                         err.help(format!("message: {s}"));
                     }
@@ -156,7 +156,7 @@ impl MultiItemModifier for DeriveProcMacro {
             }
         };
 
-        let error_count_before = ecx.sess.dcx().err_count();
+        let error_count_before = ecx.dcx().err_count();
         let mut parser =
             rustc_parse::stream_to_parser(&ecx.sess.parse_sess, stream, Some("proc-macro derive"));
         let mut items = vec![];
@@ -179,8 +179,8 @@ impl MultiItemModifier for DeriveProcMacro {
         }
 
         // fail if there have been errors emitted
-        if ecx.sess.dcx().err_count() > error_count_before {
-            ecx.sess.emit_err(errors::ProcMacroDeriveTokens { span });
+        if ecx.dcx().err_count() > error_count_before {
+            ecx.dcx().emit_err(errors::ProcMacroDeriveTokens { span });
         }
 
         ExpandResult::Ready(items)
diff --git a/compiler/rustc_hir_analysis/src/astconv/bounds.rs b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
index 0748644cc0ab9..6e71cf16ee8b4 100644
--- a/compiler/rustc_hir_analysis/src/astconv/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/bounds.rs
@@ -48,7 +48,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
         }
 
         if unbounds.len() > 1 {
-            tcx.sess.emit_err(errors::MultipleRelaxedDefaultBounds {
+            tcx.dcx().emit_err(errors::MultipleRelaxedDefaultBounds {
                 spans: unbounds.iter().map(|ptr| ptr.span).collect(),
             });
         }
@@ -64,7 +64,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                 }
             }
             // There was a `?Trait` bound, but it was not `?Sized`; warn.
-            tcx.sess.span_warn(
+            tcx.dcx().span_warn(
                 unbound.span,
                 "relaxing a default bound only does something for `?Sized`; \
                 all other traits are not bound by default",
@@ -289,7 +289,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             .expect("missing associated item");
 
         if !assoc_item.visibility(tcx).is_accessible_from(def_scope, tcx) {
-            tcx.sess
+            tcx.dcx()
                 .struct_span_err(
                     binding.span,
                     format!("{} `{}` is private", assoc_item.kind, binding.item_name),
@@ -303,7 +303,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             dup_bindings
                 .entry(assoc_item.def_id)
                 .and_modify(|prev_span| {
-                    tcx.sess.emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
+                    tcx.dcx().emit_err(errors::ValueOfAssociatedStructAlreadySpecified {
                         span: binding.span,
                         prev_span: *prev_span,
                         item_name: binding.item_name,
@@ -332,7 +332,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                         .into(),
                         ty::GenericParamDefKind::Type { .. } => {
                             if !emitted_bad_param_err {
-                                tcx.sess.emit_err(
+                                tcx.dcx().emit_err(
                                     crate::errors::ReturnTypeNotationIllegalParam::Type {
                                         span: path_span,
                                         param_span: tcx.def_span(param.def_id),
@@ -352,7 +352,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                         }
                         ty::GenericParamDefKind::Const { .. } => {
                             if !emitted_bad_param_err {
-                                tcx.sess.emit_err(
+                                tcx.dcx().emit_err(
                                     crate::errors::ReturnTypeNotationIllegalParam::Const {
                                         span: path_span,
                                         param_span: tcx.def_span(param.def_id),
@@ -385,7 +385,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
             {
                 alias_ty
             } else {
-                return Err(self.tcx().sess.emit_err(
+                return Err(self.tcx().dcx().emit_err(
                     crate::errors::ReturnTypeNotationOnNonRpitit {
                         span: binding.span,
                         ty: tcx.liberate_late_bound_regions(assoc_item.def_id, output),
@@ -452,7 +452,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
                     late_bound_in_ty,
                     |br_name| {
                         struct_span_err!(
-                            tcx.sess,
+                            tcx.dcx(),
                             binding.span,
                             E0582,
                             "binding for associated type `{}` references {}, \
@@ -467,7 +467,7 @@ impl<'tcx> dyn AstConv<'tcx> + '_ {
 
         match binding.kind {
             ConvertedBindingKind::Equality(..) if let ty::AssocKind::Fn = assoc_kind => {
-                return Err(self.tcx().sess.emit_err(
+                return Err(self.tcx().dcx().emit_err(
                     crate::errors::ReturnTypeNotationEqualityBound { span: binding.span },
                 ));
             }
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index 13ad9a453b2bf..f17f19bb77c70 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -31,7 +31,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             return;
         }
 
-        self.tcx().sess.emit_err(MissingTypeParams {
+        self.tcx().dcx().emit_err(MissingTypeParams {
             span,
             def_span: self.tcx().def_span(def_id),
             span_snippet: self.tcx().sess.source_map().span_to_snippet(span).ok(),
@@ -94,7 +94,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         if is_impl {
             let trait_name = self.tcx().def_path_str(trait_def_id);
-            self.tcx().sess.emit_err(ManualImplementation { span, trait_name });
+            self.tcx().dcx().emit_err(ManualImplementation { span, trait_name });
         }
     }
 
@@ -141,7 +141,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         if is_dummy {
             err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span });
-            return tcx.sess.emit_err(err);
+            return tcx.dcx().emit_err(err);
         }
 
         let all_candidate_names: Vec<_> = all_candidates()
@@ -159,7 +159,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 assoc_kind: assoc_kind_str,
                 suggested_name,
             });
-            return tcx.sess.emit_err(err);
+            return tcx.dcx().emit_err(err);
         }
 
         // If we didn't find a good item in the supertraits (or couldn't get
@@ -224,10 +224,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                             assoc_kind: assoc_kind_str,
                             suggested_name,
                         });
-                        return tcx.sess.emit_err(err);
+                        return tcx.dcx().emit_err(err);
                     }
 
-                    let mut err = tcx.sess.create_err(err);
+                    let mut err = tcx.dcx().create_err(err);
                     if suggest_constraining_type_param(
                         tcx,
                         generics,
@@ -249,7 +249,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     }
                     return err.emit();
                 }
-                return tcx.sess.emit_err(err);
+                return tcx.dcx().emit_err(err);
             }
         }
 
@@ -275,7 +275,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             err.label = Some(errors::AssocItemNotFoundLabel::NotFound { span: assoc_name.span });
         }
 
-        tcx.sess.emit_err(err)
+        tcx.dcx().emit_err(err)
     }
 
     fn complain_about_assoc_kind_mismatch(
@@ -327,7 +327,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             (ident.span, None, assoc_kind, assoc_item.kind)
         };
 
-        tcx.sess.emit_err(errors::AssocKindMismatch {
+        tcx.dcx().emit_err(errors::AssocKindMismatch {
             span,
             expected: super::assoc_kind_str(expected),
             got: super::assoc_kind_str(got),
@@ -346,7 +346,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         span: Span,
     ) -> ErrorGuaranteed {
         let mut err = struct_span_err!(
-            self.tcx().sess,
+            self.tcx().dcx(),
             name.span,
             E0034,
             "multiple applicable items in scope"
@@ -445,7 +445,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             };
 
             let mut err = struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 name.span,
                 E0220,
                 "associated type `{name}` not found for `{self_ty}` in the current scope"
@@ -536,7 +536,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         bounds.sort();
         bounds.dedup();
 
-        let mut err = tcx.sess.struct_span_err(
+        let mut err = tcx.dcx().struct_span_err(
             name.span,
             format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
         );
@@ -697,7 +697,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         trait_bound_spans.sort();
         let mut err = struct_span_err!(
-            tcx.sess,
+            tcx.dcx(),
             trait_bound_spans,
             E0191,
             "the value of the associated type{} {} must be specified",
@@ -852,7 +852,7 @@ pub fn prohibit_assoc_ty_binding(
     span: Span,
     segment: Option<(&hir::PathSegment<'_>, Span)>,
 ) {
-    tcx.sess.emit_err(AssocTypeBindingNotAllowed {
+    tcx.dcx().emit_err(AssocTypeBindingNotAllowed {
         span,
         fn_trait_expansion: if let Some((segment, span)) = segment
             && segment.args().parenthesized == hir::GenericArgsParentheses::ParenSugar
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index b495b00ec7047..7d840ba7e8153 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -28,7 +28,7 @@ fn generic_arg_mismatch_err(
 ) -> ErrorGuaranteed {
     let sess = tcx.sess;
     let mut err = struct_span_err!(
-        sess,
+        tcx.dcx(),
         arg.span(),
         E0747,
         "{} provided when a {} was expected",
@@ -650,7 +650,7 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
         if position == GenericArgPosition::Value
             && args.num_lifetime_params() != param_counts.lifetimes
         {
-            let mut err = struct_span_err!(tcx.sess, span, E0794, "{}", msg);
+            let mut err = struct_span_err!(tcx.dcx(), span, E0794, "{}", msg);
             err.span_note(span_late, note);
             err.emit();
         } else {
diff --git a/compiler/rustc_hir_analysis/src/astconv/lint.rs b/compiler/rustc_hir_analysis/src/astconv/lint.rs
index 9afb04b747028..f3b93c91ae9ab 100644
--- a/compiler/rustc_hir_analysis/src/astconv/lint.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/lint.rs
@@ -97,7 +97,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let msg = "trait objects must include the `dyn` keyword";
                 let label = "add `dyn` keyword before this trait";
                 let mut diag =
-                    rustc_errors::struct_span_err!(tcx.sess, self_ty.span, E0782, "{}", msg);
+                    rustc_errors::struct_span_err!(tcx.dcx(), self_ty.span, E0782, "{}", msg);
                 if self_ty.span.can_be_used_for_suggestions() {
                     diag.multipart_suggestion_verbose(
                         label,
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index ab281ef929d22..8197fea5b298e 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -564,7 +564,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             && generics.has_self
             && !tcx.has_attr(def_id, sym::const_trait)
         {
-            let e = tcx.sess.emit_err(crate::errors::ConstBoundForNonConstTrait { span });
+            let e = tcx.dcx().emit_err(crate::errors::ConstBoundForNonConstTrait { span });
             arg_count.correct =
                 Err(GenericArgCountMismatch { reported: Some(e), invalid_args: vec![] });
         }
@@ -748,7 +748,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             // since we should have emitten an error for them earlier, and they will
             // not be well-formed!
             if polarity == ty::ImplPolarity::Negative {
-                self.tcx().sess.span_delayed_bug(
+                self.tcx().dcx().span_delayed_bug(
                     binding.span,
                     "negative trait bounds should not have bindings",
                 );
@@ -863,7 +863,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         traits: &[String],
         name: Symbol,
     ) -> ErrorGuaranteed {
-        let mut err = struct_span_err!(self.tcx().sess, span, E0223, "ambiguous associated type");
+        let mut err = struct_span_err!(self.tcx().dcx(), span, E0223, "ambiguous associated type");
         if self
             .tcx()
             .resolutions(())
@@ -1079,7 +1079,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
             let assoc_kind_str = assoc_kind_str(assoc_kind);
             let ty_param_name = &ty_param_name.to_string();
-            let mut err = tcx.sess.create_err(crate::errors::AmbiguousAssocItem {
+            let mut err = tcx.dcx().create_err(crate::errors::AmbiguousAssocItem {
                 span,
                 assoc_kind: assoc_kind_str,
                 assoc_name,
@@ -1312,7 +1312,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // trait reference.
                 let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) else {
                     // A cycle error occurred, most likely.
-                    let guar = tcx.sess.span_delayed_bug(span, "expected cycle error");
+                    let guar = tcx.dcx().span_delayed_bug(span, "expected cycle error");
                     return Err(guar);
                 };
 
@@ -1339,10 +1339,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let reported = if variant_resolution.is_some() {
                     // Variant in type position
                     let msg = format!("expected type, found variant `{assoc_ident}`");
-                    tcx.sess.span_err(span, msg)
+                    tcx.dcx().span_err(span, msg)
                 } else if qself_ty.is_enum() {
                     let mut err = struct_span_err!(
-                        tcx.sess,
+                        tcx.dcx(),
                         assoc_ident.span,
                         E0599,
                         "no variant named `{}` found for enum `{}`",
@@ -1383,7 +1383,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 } else if let ty::Alias(ty::Opaque, alias_ty) = qself_ty.kind() {
                     // `<impl Trait as OtherTrait>::Assoc` makes no sense.
                     struct_span_err!(
-                        tcx.sess,
+                        tcx.dcx(),
                         tcx.def_span(alias_ty.def_id),
                         E0667,
                         "`impl Trait` is not allowed in path parameters"
@@ -1643,7 +1643,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             let kind = tcx.def_kind_descr(kind, item);
             let msg = format!("{kind} `{name}` is private");
             let def_span = tcx.def_span(item);
-            tcx.sess
+            tcx.dcx()
                 .struct_span_err_with_code(span, msg, rustc_errors::error_code!(E0624))
                 .span_label(span, format!("private {kind}"))
                 .span_label(def_span, format!("{kind} defined here"))
@@ -1878,7 +1878,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             let last_span = *arg_spans.last().unwrap();
             let span: MultiSpan = arg_spans.into();
             let mut err = struct_span_err!(
-                self.tcx().sess,
+                self.tcx().dcx(),
                 span,
                 E0109,
                 "{kind} arguments are not allowed on {this_type}",
@@ -2199,7 +2199,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 // `AlwaysApplicable` impl needs a `T: ?Sized` bound for
                 // this to compile if we were to normalize here.
                 if forbid_generic && ty.has_param() {
-                    let mut err = tcx.sess.struct_span_err(
+                    let mut err = tcx.dcx().struct_span_err(
                         path.span,
                         "generic `Self` types are currently not permitted in anonymous constants",
                     );
@@ -2260,7 +2260,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             Res::Err => {
                 let e = self
                     .tcx()
-                    .sess
+                    .dcx()
                     .span_delayed_bug(path.span, "path with `Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
                 Ty::new_error(self.tcx(), e)
@@ -2443,7 +2443,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 } else {
                     (ty, None)
                 };
-                tcx.sess.emit_err(TypeofReservedKeywordUsed { span, ty, opt_sugg });
+                tcx.dcx().emit_err(TypeofReservedKeywordUsed { span, ty, opt_sugg });
 
                 ty
             }
@@ -2629,7 +2629,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
 
         self.validate_late_bound_regions(late_bound_in_args, late_bound_in_ret, |br_name| {
             struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 decl.output.span(),
                 E0581,
                 "return type references {}, which is not constrained by the fn input types",
@@ -2751,7 +2751,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         // error.
         let r = derived_region_bounds[0];
         if derived_region_bounds[1..].iter().any(|r1| r != *r1) {
-            tcx.sess.emit_err(AmbiguousLifetimeBound { span });
+            tcx.dcx().emit_err(AmbiguousLifetimeBound { span });
         }
         Some(r)
     }
diff --git a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
index dd5deb6f24455..a614d4abf25f7 100644
--- a/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/object_safety.rs
@@ -90,7 +90,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             let first_trait = &regular_traits[0];
             let additional_trait = &regular_traits[1];
             let mut err = struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 additional_trait.bottom().1,
                 E0225,
                 "only auto traits can be used as additional traits in a trait object"
@@ -126,7 +126,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 .find(|&trait_ref| tcx.is_trait_alias(trait_ref))
                 .map(|trait_ref| tcx.def_span(trait_ref));
             let reported =
-                tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
+                tcx.dcx().emit_err(TraitObjectDeclaredWithNoTraits { span, trait_alias_span });
             return Ty::new_error(tcx, reported);
         }
 
@@ -290,7 +290,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 if references_self {
                     let def_id = i.bottom().0.def_id();
                     let mut err = struct_span_err!(
-                        tcx.sess,
+                        tcx.dcx(),
                         i.bottom().1,
                         E0038,
                         "the {} `{}` cannot be made into an object",
@@ -326,7 +326,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                         false
                     });
                     if references_self {
-                        let guar = tcx.sess.span_delayed_bug(
+                        let guar = tcx.dcx().span_delayed_bug(
                             span,
                             "trait object projection bounds reference `Self`",
                         );
@@ -375,7 +375,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 } else {
                     self.re_infer(None, span).unwrap_or_else(|| {
                         let mut err = struct_span_err!(
-                            tcx.sess,
+                            tcx.dcx(),
                             span,
                             E0228,
                             "the lifetime bound for this object type cannot be deduced \
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index 5fc500f480762..5f5994879126b 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -249,7 +249,7 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa
         Limit(0) => Limit(2),
         limit => limit * 2,
     };
-    tcx.sess.emit_err(AutoDerefReachedRecursionLimit {
+    tcx.dcx().emit_err(AutoDerefReachedRecursionLimit {
         span,
         ty,
         suggested_limit,
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 8413a1cc0dba9..d2e96ac74df84 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -38,7 +38,7 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
         Some(true) => (),
         Some(false) => {
             struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 span,
                 E0570,
                 "`{abi}` is not a supported ABI for the current target",
@@ -59,7 +59,7 @@ pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
     // This ABI is only allowed on function pointers
     if abi == Abi::CCmseNonSecureCall {
         struct_span_err!(
-            tcx.sess,
+            tcx.dcx(),
             span,
             E0781,
             "the `\"C-cmse-nonsecure-call\"` ABI is only allowed on function pointers"
@@ -126,7 +126,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
         for field in &def.non_enum_variant().fields {
             let Ok(field_ty) = tcx.try_normalize_erasing_regions(param_env, field.ty(tcx, args))
             else {
-                tcx.sess.span_delayed_bug(span, "could not normalize field type");
+                tcx.dcx().span_delayed_bug(span, "could not normalize field type");
                 continue;
             };
 
@@ -136,7 +136,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
                     Some(Node::Field(field)) => (field.span, field.ty.span),
                     _ => unreachable!("mir field has to correspond to hir field"),
                 };
-                tcx.sess.emit_err(errors::InvalidUnionField {
+                tcx.dcx().emit_err(errors::InvalidUnionField {
                     field_span,
                     sugg: errors::InvalidUnionFieldSuggestion {
                         lo: ty_span.shrink_to_lo(),
@@ -147,7 +147,7 @@ fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> b
                 return false;
             } else if field_ty.needs_drop(tcx, param_env) {
                 // This should never happen. But we can get here e.g. in case of name resolution errors.
-                tcx.sess
+                tcx.dcx()
                     .span_delayed_bug(span, "we should never accept maybe-dropping union fields");
             }
         }
@@ -173,12 +173,12 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             if matches!(tcx.def_kind(def_id), DefKind::Static(_)
                 if tcx.def_kind(tcx.local_parent(def_id)) == DefKind::ForeignMod) =>
         {
-            tcx.sess.emit_err(errors::TooLargeStatic { span });
+            tcx.dcx().emit_err(errors::TooLargeStatic { span });
             return;
         }
         // Generic statics are rejected, but we still reach this case.
         Err(e) => {
-            tcx.sess.span_delayed_bug(span, format!("{e:?}"));
+            tcx.dcx().span_delayed_bug(span, format!("{e:?}"));
             return;
         }
     };
@@ -201,7 +201,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
     let item = tcx.hir().item(id);
     let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) = item.kind else {
-        tcx.sess.span_delayed_bug(item.span, "expected opaque item");
+        tcx.dcx().span_delayed_bug(item.span, "expected opaque item");
         return;
     };
 
@@ -310,7 +310,7 @@ fn check_opaque_meets_bounds<'tcx>(
         Ok(()) => {}
         Err(ty_err) => {
             let ty_err = ty_err.to_string(tcx);
-            return Err(tcx.sess.span_delayed_bug(
+            return Err(tcx.dcx().span_delayed_bug(
                 span,
                 format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
             ));
@@ -435,7 +435,7 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             ty::Adt(adt_def, args) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *args),
             _ => true,
         } {
-            tcx.sess.emit_err(LinkageType { span: tcx.def_span(def_id) });
+            tcx.dcx().emit_err(LinkageType { span: tcx.def_span(def_id) });
         }
     }
 }
@@ -554,7 +554,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
                                 _ => ("type or const", "types or consts", None),
                             };
                             struct_span_err!(
-                                tcx.sess,
+                                tcx.dcx(),
                                 item.span,
                                 E0044,
                                 "foreign items may not have {kinds} parameters",
@@ -652,7 +652,7 @@ pub(super) fn check_specialization_validity<'tcx>(
         if !tcx.is_impl_trait_in_trait(impl_item) {
             report_forbidden_specialization(tcx, impl_item, parent_impl);
         } else {
-            tcx.sess.span_delayed_bug(
+            tcx.dcx().span_delayed_bug(
                 DUMMY_SP,
                 format!("parent item: {parent_impl:?} not marked as default"),
             );
@@ -681,7 +681,7 @@ fn check_impl_items_against_trait<'tcx>(
             if let [first_item_ref, ..] = impl_item_refs {
                 let first_item_span = tcx.def_span(first_item_ref);
                 struct_span_err!(
-                    tcx.sess,
+                    tcx.dcx(),
                     first_item_span,
                     E0749,
                     "negative impls cannot have any items"
@@ -700,7 +700,7 @@ fn check_impl_items_against_trait<'tcx>(
             tcx.associated_item(trait_item_id)
         } else {
             // Checked in `associated_item`.
-            tcx.sess.span_delayed_bug(tcx.def_span(impl_item), "missing associated item in trait");
+            tcx.dcx().span_delayed_bug(tcx.def_span(impl_item), "missing associated item in trait");
             continue;
         };
         match ty_impl_item.kind {
@@ -795,7 +795,7 @@ fn check_impl_items_against_trait<'tcx>(
                         "return position `impl Trait` in traits",
                     )
                 };
-                tcx.sess
+                tcx.dcx()
                     .struct_span_err(tcx.def_span(def_id), msg)
                     .note(format!(
                         "specialization behaves in inconsistent and \
@@ -833,12 +833,12 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
     {
         let fields = &def.non_enum_variant().fields;
         if fields.is_empty() {
-            struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
+            struct_span_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
             return;
         }
         let e = fields[FieldIdx::from_u32(0)].ty(tcx, args);
         if !fields.iter().all(|f| f.ty(tcx, args) == e) {
-            struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous")
+            struct_span_err!(tcx.dcx(), sp, E0076, "SIMD vector should be homogeneous")
                 .span_label(sp, "SIMD elements must have the same type")
                 .emit();
             return;
@@ -851,11 +851,11 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
         };
         if let Some(len) = len {
             if len == 0 {
-                struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit();
+                struct_span_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();
                 return;
             } else if len > MAX_SIMD_LANES {
                 struct_span_err!(
-                    tcx.sess,
+                    tcx.dcx(),
                     sp,
                     E0075,
                     "SIMD vector cannot have more than {MAX_SIMD_LANES} elements",
@@ -878,7 +878,7 @@ pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {
             { /* struct([f32; 4]) is ok */ }
             _ => {
                 struct_span_err!(
-                    tcx.sess,
+                    tcx.dcx(),
                     sp,
                     E0077,
                     "SIMD vector element type should be a \
@@ -901,7 +901,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
                     && pack as u64 != repr_pack.bytes()
                 {
                     struct_span_err!(
-                        tcx.sess,
+                        tcx.dcx(),
                         sp,
                         E0634,
                         "type has conflicting packed representation hints"
@@ -912,7 +912,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
         }
         if repr.align.is_some() {
             struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 sp,
                 E0587,
                 "type has conflicting packed and align representation hints"
@@ -921,7 +921,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
         } else {
             if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) {
                 let mut err = struct_span_err!(
-                    tcx.sess,
+                    tcx.dcx(),
                     sp,
                     E0588,
                     "packed type cannot transitively contain a `#[repr(align)]` type"
@@ -1111,7 +1111,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     if def.variants().is_empty() {
         if let Some(attr) = tcx.get_attrs(def_id, sym::repr).next() {
             struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 attr.span,
                 E0084,
                 "unsupported representation for zero-variant enum"
@@ -1150,7 +1150,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 
         if disr_non_unit || (disr_units && has_non_units) {
             let mut err = struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 tcx.def_span(def_id),
                 E0732,
                 "`#[repr(inttype)]` must be specified"
@@ -1236,7 +1236,7 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
             if discrs[i].1.val == discrs[o].1.val {
                 let err = error.get_or_insert_with(|| {
                     let mut ret = struct_span_err!(
-                        tcx.sess,
+                        tcx.dcx(),
                         tcx.def_span(adt.did()),
                         E0081,
                         "discriminant value `{}` assigned more than once",
@@ -1284,7 +1284,7 @@ pub(super) fn check_type_params_are_used<'tcx>(
     if ty.references_error() {
         // If there is already another error, do not emit
         // an error for not using a type parameter.
-        assert!(tcx.sess.has_errors().is_some());
+        assert!(tcx.dcx().has_errors().is_some());
         return;
     }
 
@@ -1302,7 +1302,7 @@ pub(super) fn check_type_params_are_used<'tcx>(
             && let ty::GenericParamDefKind::Type { .. } = param.kind
         {
             let span = tcx.def_span(param.def_id);
-            struct_span_err!(tcx.sess, span, E0091, "type parameter `{}` is unused", param.name,)
+            struct_span_err!(tcx.dcx(), span, E0091, "type parameter `{}` is unused", param.name,)
                 .span_label(span, "unused type parameter")
                 .emit();
         }
@@ -1320,7 +1320,7 @@ pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalModDefId
 }
 
 fn async_opaque_type_cycle_error(tcx: TyCtxt<'_>, span: Span) -> ErrorGuaranteed {
-    struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing")
+    struct_span_err!(tcx.dcx(), span, E0733, "recursion in an `async fn` requires boxing")
         .span_label(span, "recursive `async fn`")
         .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`")
         .note(
@@ -1342,7 +1342,7 @@ fn opaque_type_cycle_error(
     opaque_def_id: LocalDefId,
     span: Span,
 ) -> ErrorGuaranteed {
-    let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type");
+    let mut err = struct_span_err!(tcx.dcx(), span, E0720, "cannot resolve opaque type");
 
     let mut label = false;
     if let Some((def_id, visitor)) = get_owner_return_paths(tcx, opaque_def_id) {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 264868fdfc7a0..dbcaa244f2915 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -429,7 +429,7 @@ fn compare_asyncness<'tcx>(
             }
             _ => {
                 return Err(tcx
-                    .sess
+                    .dcx()
                     .create_err(crate::errors::AsyncTraitImplShouldBeAsync {
                         span: tcx.def_span(impl_m.def_id),
                         method_name: trait_m.name,
@@ -626,7 +626,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
         Ok(()) => {}
         Err(terr) => {
             let mut diag = struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 cause.span(),
                 E0053,
                 "method `{}` has an incompatible return type for trait",
@@ -759,7 +759,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
                 remapped_types.insert(def_id, ty::EarlyBinder::bind(ty));
             }
             Err(err) => {
-                let reported = tcx.sess.span_delayed_bug(
+                let reported = tcx.dcx().span_delayed_bug(
                     return_span,
                     format!("could not fully resolve: {ty} => {err:?}"),
                 );
@@ -929,7 +929,7 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
                         self.return_span
                     };
                     self.tcx
-                        .sess
+                        .dcx()
                         .struct_span_err(
                             return_span,
                             "return type captures more lifetimes than trait definition",
@@ -943,7 +943,7 @@ impl<'tcx> ty::FallibleTypeFolder<TyCtxt<'tcx>> for RemapHiddenTyRegions<'tcx> {
                         .emit()
                 }
                 _ => {
-                    self.tcx.sess.span_delayed_bug(DUMMY_SP, "should've been able to remap region")
+                    self.tcx.dcx().span_delayed_bug(DUMMY_SP, "should've been able to remap region")
                 }
             };
             return Err(guar);
@@ -973,7 +973,7 @@ fn report_trait_method_mismatch<'tcx>(
         extract_spans_for_error_reporting(infcx, terr, &cause, impl_m, trait_m);
 
     let mut diag = struct_span_err!(
-        tcx.sess,
+        tcx.dcx(),
         impl_err_span,
         E0053,
         "method `{}` has an incompatible type for trait",
@@ -1134,7 +1134,7 @@ fn check_region_bounds_on_impl_item<'tcx>(
             }
         }
         let reported = tcx
-            .sess
+            .dcx()
             .create_err(LifetimesOrBoundsMismatchOnTrait {
                 span,
                 item_kind: assoc_item_kind_str(&impl_m),
@@ -1218,7 +1218,7 @@ fn compare_self_type<'tcx>(
             let self_descr = self_string(impl_m);
             let impl_m_span = tcx.def_span(impl_m.def_id);
             let mut err = struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 impl_m_span,
                 E0185,
                 "method `{}` has a `{}` declaration in the impl, but not in the trait",
@@ -1238,7 +1238,7 @@ fn compare_self_type<'tcx>(
             let self_descr = self_string(trait_m);
             let impl_m_span = tcx.def_span(impl_m.def_id);
             let mut err = struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 impl_m_span,
                 E0186,
                 "method `{}` has a `{}` declaration in the trait, but not in the impl",
@@ -1303,7 +1303,7 @@ fn compare_number_of_generics<'tcx>(
     // inheriting the generics from will also have mismatched arguments, and
     // we'll report an error for that instead. Delay a bug for safety, though.
     if trait_.is_impl_trait_in_trait() {
-        return Err(tcx.sess.span_delayed_bug(
+        return Err(tcx.dcx().span_delayed_bug(
             rustc_span::DUMMY_SP,
             "errors comparing numbers of generics of trait/impl functions were not emitted",
         ));
@@ -1371,7 +1371,7 @@ fn compare_number_of_generics<'tcx>(
             let spans = arg_spans(impl_.kind, impl_item.generics);
             let span = spans.first().copied();
 
-            let mut err = tcx.sess.struct_span_err_with_code(
+            let mut err = tcx.dcx().struct_span_err_with_code(
                 spans,
                 format!(
                     "{} `{}` has {} {kind} parameter{} but its trait \
@@ -1464,7 +1464,7 @@ fn compare_number_of_method_arguments<'tcx>(
             .unwrap_or_else(|| tcx.def_span(impl_m.def_id));
 
         let mut err = struct_span_err!(
-            tcx.sess,
+            tcx.dcx(),
             impl_span,
             E0050,
             "method `{}` has {} but the declaration in trait `{}` has {}",
@@ -1531,7 +1531,7 @@ fn compare_synthetic_generics<'tcx>(
             let impl_span = tcx.def_span(impl_def_id);
             let trait_span = tcx.def_span(trait_def_id);
             let mut err = struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 impl_span,
                 E0643,
                 "method `{}` has incompatible signature for trait",
@@ -1690,7 +1690,7 @@ fn compare_generic_param_kinds<'tcx>(
             let param_trait_span = tcx.def_span(param_trait.def_id);
 
             let mut err = struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 param_impl_span,
                 E0053,
                 "{} `{}` has an incompatible generic parameter for trait `{}`",
@@ -1837,7 +1837,7 @@ fn compare_const_predicate_entailment<'tcx>(
         cause.span = ty.span;
 
         let mut diag = struct_span_err!(
-            tcx.sess,
+            tcx.dcx(),
             cause.span,
             E0326,
             "implemented const `{}` has an incompatible type for trait",
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index 67796855ece85..71fbd983b6a6f 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -153,7 +153,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
         trait_m_sig.inputs_and_output,
     ));
     if !ocx.select_all_or_error().is_empty() {
-        tcx.sess.span_delayed_bug(
+        tcx.dcx().span_delayed_bug(
             DUMMY_SP,
             "encountered errors when checking RPITIT refinement (selection)",
         );
@@ -165,7 +165,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
     );
     let errors = infcx.resolve_regions(&outlives_env);
     if !errors.is_empty() {
-        tcx.sess.span_delayed_bug(
+        tcx.dcx().span_delayed_bug(
             DUMMY_SP,
             "encountered errors when checking RPITIT refinement (regions)",
         );
@@ -173,7 +173,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>(
     }
     // Resolve any lifetime variables that may have been introduced during normalization.
     let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else {
-        tcx.sess.span_delayed_bug(
+        tcx.dcx().span_delayed_bug(
             DUMMY_SP,
             "encountered errors when checking RPITIT refinement (resolution)",
         );
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index 58c77bb45cba3..3492499db686a 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -34,12 +34,12 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
     match tcx.impl_polarity(drop_impl_did) {
         ty::ImplPolarity::Positive => {}
         ty::ImplPolarity::Negative => {
-            return Err(tcx.sess.emit_err(errors::DropImplPolarity::Negative {
+            return Err(tcx.dcx().emit_err(errors::DropImplPolarity::Negative {
                 span: tcx.def_span(drop_impl_did),
             }));
         }
         ty::ImplPolarity::Reservation => {
-            return Err(tcx.sess.emit_err(errors::DropImplPolarity::Reservation {
+            return Err(tcx.dcx().emit_err(errors::DropImplPolarity::Reservation {
                 span: tcx.def_span(drop_impl_did),
             }));
         }
@@ -66,7 +66,7 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
             // already checked by coherence, but compilation may
             // not have been terminated.
             let span = tcx.def_span(drop_impl_did);
-            let reported = tcx.sess.span_delayed_bug(
+            let reported = tcx.dcx().span_delayed_bug(
                 span,
                 format!("should have been rejected by coherence check: {dtor_self_type}"),
             );
@@ -89,7 +89,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
     let item_span = tcx.def_span(self_type_did);
     let self_descr = tcx.def_descr(self_type_did);
     let mut err =
-        struct_span_err!(tcx.sess, drop_impl_span, E0366, "`Drop` impls cannot be specialized");
+        struct_span_err!(tcx.dcx(), drop_impl_span, E0366, "`Drop` impls cannot be specialized");
     match arg {
         ty::util::NotUniqueParam::DuplicateParam(arg) => {
             err.note(format!("`{arg}` is mentioned multiple times"))
@@ -155,7 +155,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
                 let self_descr = tcx.def_descr(adt_def_id.to_def_id());
                 guar = Some(
                     struct_span_err!(
-                        tcx.sess,
+                        tcx.dcx(),
                         error.root_obligation.cause.span,
                         E0367,
                         "`Drop` impl requires `{root_predicate}` \
@@ -187,7 +187,7 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
             };
             guar = Some(
                 struct_span_err!(
-                    tcx.sess,
+                    tcx.dcx(),
                     error.origin().span(),
                     E0367,
                     "`Drop` impl requires `{outlives}` \
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index a82853a13034d..649ac6c5aebbf 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -96,12 +96,13 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
     let main_asyncness = tcx.asyncness(main_def_id);
     if main_asyncness.is_async() {
         let asyncness_span = main_fn_asyncness_span(tcx, main_def_id);
-        tcx.sess.emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
+        tcx.dcx()
+            .emit_err(errors::MainFunctionAsync { span: main_span, asyncness: asyncness_span });
         error = true;
     }
 
     for attr in tcx.get_attrs(main_def_id, sym::track_caller) {
-        tcx.sess.emit_err(errors::TrackCallerOnMain { span: attr.span, annotated: main_span });
+        tcx.dcx().emit_err(errors::TrackCallerOnMain { span: attr.span, annotated: main_span });
         error = true;
     }
 
@@ -110,7 +111,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         && !tcx.sess.target.is_like_wasm
         && !tcx.sess.opts.actually_rustdoc
     {
-        tcx.sess.emit_err(errors::TargetFeatureOnMain { main: main_span });
+        tcx.dcx().emit_err(errors::TargetFeatureOnMain { main: main_span });
         error = true;
     }
 
@@ -125,7 +126,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
         let return_ty = main_fnsig.output();
         let return_ty_span = main_fn_return_type_span(tcx, main_def_id).unwrap_or(main_span);
         let Some(return_ty) = return_ty.no_bound_vars() else {
-            tcx.sess.emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
+            tcx.dcx().emit_err(errors::MainFunctionReturnTypeGeneric { span: return_ty_span });
             return;
         };
         let infcx = tcx.infer_ctxt().build();
@@ -180,14 +181,14 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
     let main_fn_predicates = tcx.predicates_of(main_def_id);
     if main_fn_generics.count() != 0 || !main_fnsig.bound_vars().is_empty() {
         let generics_param_span = main_fn_generics_params_span(tcx, main_def_id);
-        tcx.sess.emit_err(errors::MainFunctionGenericParameters {
+        tcx.dcx().emit_err(errors::MainFunctionGenericParameters {
             span: generics_param_span.unwrap_or(main_span),
             label_span: generics_param_span,
         });
     } else if !main_fn_predicates.predicates.is_empty() {
         // generics may bring in implicit predicates, so we skip this check if generics is present.
         let generics_where_clauses_span = main_fn_where_clauses_span(tcx, main_def_id);
-        tcx.sess.emit_err(errors::WhereClauseOnMain {
+        tcx.dcx().emit_err(errors::WhereClauseOnMain {
             span: generics_where_clauses_span.unwrap_or(main_span),
             generics_span: generics_where_clauses_span,
         });
@@ -205,25 +206,25 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                 if let hir::ItemKind::Fn(sig, generics, _) = &it.kind {
                     let mut error = false;
                     if !generics.params.is_empty() {
-                        tcx.sess.emit_err(errors::StartFunctionParameters { span: generics.span });
+                        tcx.dcx().emit_err(errors::StartFunctionParameters { span: generics.span });
                         error = true;
                     }
                     if generics.has_where_clause_predicates {
-                        tcx.sess.emit_err(errors::StartFunctionWhere {
+                        tcx.dcx().emit_err(errors::StartFunctionWhere {
                             span: generics.where_clause_span,
                         });
                         error = true;
                     }
                     if sig.header.asyncness.is_async() {
                         let span = tcx.def_span(it.owner_id);
-                        tcx.sess.emit_err(errors::StartAsync { span: span });
+                        tcx.dcx().emit_err(errors::StartAsync { span: span });
                         error = true;
                     }
 
                     let attrs = tcx.hir().attrs(start_id);
                     for attr in attrs {
                         if attr.has_name(sym::track_caller) {
-                            tcx.sess.emit_err(errors::StartTrackCaller {
+                            tcx.dcx().emit_err(errors::StartTrackCaller {
                                 span: attr.span,
                                 start: start_span,
                             });
@@ -235,7 +236,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
                             && !tcx.sess.target.is_like_wasm
                             && !tcx.sess.opts.actually_rustdoc
                         {
-                            tcx.sess.emit_err(errors::StartTargetFeature {
+                            tcx.dcx().emit_err(errors::StartTargetFeature {
                                 span: attr.span,
                                 start: start_span,
                             });
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 126bab68ae351..632af780ed85c 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -29,7 +29,7 @@ fn equate_intrinsic_type<'tcx>(
             (own_counts, generics.span)
         }
         _ => {
-            struct_span_err!(tcx.sess, it.span, E0622, "intrinsic must be a function")
+            struct_span_err!(tcx.dcx(), it.span, E0622, "intrinsic must be a function")
                 .span_label(it.span, "expected a function")
                 .emit();
             return;
@@ -38,7 +38,7 @@ fn equate_intrinsic_type<'tcx>(
 
     let gen_count_ok = |found: usize, expected: usize, descr: &str| -> bool {
         if found != expected {
-            tcx.sess.emit_err(WrongNumberOfGenericArgumentsToIntrinsic {
+            tcx.dcx().emit_err(WrongNumberOfGenericArgumentsToIntrinsic {
                 span,
                 found,
                 expected,
@@ -117,7 +117,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir
     };
 
     if has_safe_attr != is_in_list {
-        tcx.sess.struct_span_err(
+        tcx.dcx().struct_span_err(
             tcx.def_span(intrinsic_id),
             DiagnosticMessage::from(format!(
                 "intrinsic safety mismatch between list of intrinsics within the compiler and core library intrinsics for intrinsic `{}`",
@@ -176,7 +176,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             | "umin" => (1, vec![Ty::new_mut_ptr(tcx, param(0)), param(0)], param(0)),
             "fence" | "singlethreadfence" => (0, Vec::new(), Ty::new_unit(tcx)),
             op => {
-                tcx.sess.emit_err(UnrecognizedAtomicOperation { span: it.span, op });
+                tcx.dcx().emit_err(UnrecognizedAtomicOperation { span: it.span, op });
                 return;
             }
         };
@@ -460,7 +460,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             }
 
             other => {
-                tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
+                tcx.dcx().emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other });
                 return;
             }
         };
@@ -552,7 +552,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
         sym::simd_shuffle_generic => (2, 1, vec![param(0), param(0)], param(1)),
         _ => {
             let msg = format!("unrecognized platform-specific intrinsic function: `{name}`");
-            tcx.sess.struct_span_err(it.span, msg).emit();
+            tcx.dcx().struct_span_err(it.span, msg).emit();
             return;
         }
     };
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index d86ebc2c9c323..ac18e6de0bac8 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -153,7 +153,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         };
         let Some(asm_ty) = asm_ty else {
             let msg = format!("cannot use value of type `{ty}` for inline assembly");
-            let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
+            let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
             err.note(
                 "only integers, floats, SIMD vectors, pointers and function pointers \
                  can be used as arguments for inline assembly",
@@ -166,7 +166,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         // possibly fail is for SIMD types which don't #[derive(Copy)].
         if !ty.is_copy_modulo_regions(self.tcx, self.param_env) {
             let msg = "arguments for inline assembly must be copyable";
-            let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
+            let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
             err.note(format!("`{ty}` does not implement the Copy trait"));
             err.emit();
         }
@@ -183,7 +183,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         if let Some((in_expr, Some(in_asm_ty))) = tied_input {
             if in_asm_ty != asm_ty {
                 let msg = "incompatible types for asm inout argument";
-                let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg);
+                let mut err = self.tcx.dcx().struct_span_err(vec![in_expr.span, expr.span], msg);
 
                 let in_expr_ty = (self.get_operand_ty)(in_expr);
                 err.span_label(in_expr.span, format!("type `{in_expr_ty}`"));
@@ -207,7 +207,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         let supported_tys = reg_class.supported_types(asm_arch);
         let Some((_, feature)) = supported_tys.iter().find(|&&(t, _)| t == asm_ty) else {
             let msg = format!("type `{ty}` cannot be used with this register class");
-            let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
+            let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
             let supported_tys: Vec<_> = supported_tys.iter().map(|(t, _)| t.to_string()).collect();
             err.note(format!(
                 "register class `{}` supports these types: {}",
@@ -234,7 +234,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
         if let Some(feature) = feature {
             if !target_features.contains(feature) {
                 let msg = format!("`{feature}` target feature is not enabled");
-                let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
+                let mut err = self.tcx.dcx().struct_span_err(expr.span, msg);
                 err.note(format!(
                     "this is required to use type `{}` with register class `{}`",
                     ty,
@@ -287,7 +287,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
     pub fn check_asm(&self, asm: &hir::InlineAsm<'tcx>, enclosing_id: LocalDefId) {
         let target_features = self.tcx.asm_target_features(enclosing_id.to_def_id());
         let Some(asm_arch) = self.tcx.sess.asm_arch else {
-            self.tcx.sess.span_delayed_bug(DUMMY_SP, "target architecture does not support asm");
+            self.tcx.dcx().span_delayed_bug(DUMMY_SP, "target architecture does not support asm");
             return;
         };
         for (idx, (op, op_sp)) in asm.operands.iter().enumerate() {
@@ -318,7 +318,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                         op.is_clobber(),
                     ) {
                         let msg = format!("cannot use register `{}`: {}", reg.name(), msg);
-                        self.tcx.sess.struct_span_err(*op_sp, msg).emit();
+                        self.tcx.dcx().struct_span_err(*op_sp, msg).emit();
                         continue;
                     }
                 }
@@ -357,7 +357,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                                 reg_class.name(),
                                 feature
                             );
-                            self.tcx.sess.struct_span_err(*op_sp, msg).emit();
+                            self.tcx.dcx().struct_span_err(*op_sp, msg).emit();
                             // register isn't enabled, don't do more checks
                             continue;
                         }
@@ -371,7 +371,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                                     .intersperse(", ")
                                     .collect::<String>(),
                             );
-                            self.tcx.sess.struct_span_err(*op_sp, msg).emit();
+                            self.tcx.dcx().struct_span_err(*op_sp, msg).emit();
                             // register isn't enabled, don't do more checks
                             continue;
                         }
@@ -450,7 +450,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                         ty::FnDef(..) => {}
                         _ => {
                             let mut err =
-                                self.tcx.sess.struct_span_err(*op_sp, "invalid `sym` operand");
+                                self.tcx.dcx().struct_span_err(*op_sp, "invalid `sym` operand");
                             err.span_label(
                                 self.tcx.def_span(anon_const.def_id),
                                 format!("is {} `{}`", ty.kind().article(), ty),
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index e4904a0437b63..faec72cfeb644 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -144,7 +144,7 @@ fn get_owner_return_paths(
 // FIXME: Move this to a more appropriate place.
 pub fn forbid_intrinsic_abi(tcx: TyCtxt<'_>, sp: Span, abi: Abi) {
     if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi {
-        tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
+        tcx.dcx().span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block");
     }
 }
 
@@ -174,7 +174,7 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
         let msg = "statics with a custom `#[link_section]` must be a \
                         simple list of bytes on the wasm target with no \
                         extra levels of indirection such as references";
-        tcx.sess.span_err(tcx.def_span(id), msg);
+        tcx.dcx().span_err(tcx.def_span(id), msg);
     }
 }
 
@@ -187,7 +187,7 @@ fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_imp
         Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
     };
 
-    tcx.sess.emit_err(err);
+    tcx.dcx().emit_err(err);
 }
 
 fn missing_items_err(
@@ -240,7 +240,7 @@ fn missing_items_err(
         }
     }
 
-    tcx.sess.emit_err(errors::MissingTraitItem {
+    tcx.dcx().emit_err(errors::MissingTraitItem {
         span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(),
         missing_items_msg,
         missing_trait_item_label,
@@ -258,7 +258,7 @@ fn missing_items_must_implement_one_of_err(
     let missing_items_msg =
         missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
 
-    tcx.sess.emit_err(errors::MissingOneOfTraitItem {
+    tcx.dcx().emit_err(errors::MissingOneOfTraitItem {
         span: impl_span,
         note: annotation_span,
         missing_items_msg,
@@ -283,7 +283,7 @@ fn default_body_is_unstable(
         None => none_note = true,
     };
 
-    let mut err = tcx.sess.create_err(errors::MissingTraitItemUnstable {
+    let mut err = tcx.dcx().create_err(errors::MissingTraitItemUnstable {
         span: impl_span,
         some_note,
         none_note,
@@ -526,7 +526,7 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, d
         spans = start.to_vec();
         many = Some(*end);
     }
-    tcx.sess.emit_err(errors::TransparentEnumVariant {
+    tcx.dcx().emit_err(errors::TransparentEnumVariant {
         span: sp,
         spans,
         many,
@@ -545,14 +545,14 @@ fn bad_non_zero_sized_fields<'tcx>(
     sp: Span,
 ) {
     if adt.is_enum() {
-        tcx.sess.emit_err(errors::TransparentNonZeroSizedEnum {
+        tcx.dcx().emit_err(errors::TransparentNonZeroSizedEnum {
             span: sp,
             spans: field_spans.collect(),
             field_count,
             desc: adt.descr(),
         });
     } else {
-        tcx.sess.emit_err(errors::TransparentNonZeroSized {
+        tcx.dcx().emit_err(errors::TransparentNonZeroSized {
             span: sp,
             spans: field_spans.collect(),
             field_count,
@@ -616,7 +616,7 @@ pub fn check_function_signature<'tcx>(
                 cause.span = extract_span_for_error_reporting(tcx, err, &cause, local_id);
             }
             let failure_code = cause.as_failure_code_diag(err, cause.span, vec![]);
-            let mut diag = tcx.sess.create_err(failure_code);
+            let mut diag = tcx.dcx().create_err(failure_code);
             err_ctxt.note_type_err(
                 &mut diag,
                 &cause,
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index cc34dbfd9b981..580d4bd5b0209 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -115,7 +115,7 @@ where
     let errors = wfcx.select_all_or_error();
     if !errors.is_empty() {
         let err = infcx.err_ctxt().report_fulfillment_errors(errors);
-        if tcx.sess.err_count() > 0 {
+        if tcx.dcx().err_count() > 0 {
             return Err(err);
         } else {
             // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs
@@ -198,7 +198,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
             if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
                 let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
                 let mut err =
-                    tcx.sess.struct_span_err(sp, "impls of auto traits cannot be default");
+                    tcx.dcx().struct_span_err(sp, "impls of auto traits cannot be default");
                 err.span_labels(impl_.defaultness_span, "default because of this");
                 err.span_label(sp, "auto trait");
                 res = Err(err.emit());
@@ -217,7 +217,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) -> Result<()
                         let mut spans = vec![span];
                         spans.extend(impl_.defaultness_span);
                         res = Err(struct_span_err!(
-                            tcx.sess,
+                            tcx.dcx(),
                             spans,
                             E0750,
                             "negative impls cannot be default impls"
@@ -485,7 +485,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, trait_def_id: LocalDefId) {
 
         if !unsatisfied_bounds.is_empty() {
             let plural = pluralize!(unsatisfied_bounds.len());
-            let mut err = tcx.sess.struct_span_err(
+            let mut err = tcx.dcx().struct_span_err(
                 gat_item_hir.span,
                 format!("missing required bound{} on `{}`", plural, gat_item_hir.ident),
             );
@@ -829,7 +829,7 @@ fn check_object_unsafe_self_trait_by_name(tcx: TyCtxt<'_>, item: &hir::TraitItem
             return;
         }
         let sugg = trait_should_be_self.iter().map(|span| (*span, "Self".to_string())).collect();
-        tcx.sess
+        tcx.dcx()
             .struct_span_err(
                 trait_should_be_self,
                 "associated item referring to unboxed trait object for its own trait",
@@ -883,15 +883,15 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) -> Result<(),
             } else {
                 let mut diag = match ty.kind() {
                     ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => return Ok(()),
-                    ty::FnPtr(_) => tcx.sess.struct_span_err(
+                    ty::FnPtr(_) => tcx.dcx().struct_span_err(
                         hir_ty.span,
                         "using function pointers as const generic parameters is forbidden",
                     ),
-                    ty::RawPtr(_) => tcx.sess.struct_span_err(
+                    ty::RawPtr(_) => tcx.dcx().struct_span_err(
                         hir_ty.span,
                         "using raw pointers as const generic parameters is forbidden",
                     ),
-                    _ => tcx.sess.struct_span_err(
+                    _ => tcx.dcx().struct_span_err(
                         hir_ty.span,
                         format!("`{}` is forbidden as the type of a const generic parameter", ty),
                     ),
@@ -1032,7 +1032,7 @@ fn check_type_defn<'tcx>(
                     let ty = tcx.type_of(variant.tail().did).instantiate_identity();
                     let ty = tcx.erase_regions(ty);
                     if ty.has_infer() {
-                        tcx.sess
+                        tcx.dcx()
                             .span_delayed_bug(item.span, format!("inference variables in {ty:?}"));
                         // Just treat unresolved type expression as if it needs drop.
                         true
@@ -1114,7 +1114,7 @@ fn check_trait(tcx: TyCtxt<'_>, item: &hir::Item<'_>) -> Result<(), ErrorGuarant
     {
         for associated_def_id in &*tcx.associated_item_def_ids(def_id) {
             struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 tcx.def_span(*associated_def_id),
                 E0714,
                 "marker traits cannot have associated items",
@@ -1532,14 +1532,14 @@ fn check_fn_or_method<'tcx>(
                 tcx.require_lang_item(hir::LangItem::Sized, Some(span)),
             );
         } else {
-            tcx.sess.span_err(
+            tcx.dcx().span_err(
                 hir_decl.inputs.last().map_or(span, |input| input.span),
                 "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
             );
         }
         // No more inputs other than the `self` type and the tuple type
         if inputs.next().is_some() {
-            tcx.sess.span_err(
+            tcx.dcx().span_err(
                 hir_decl.inputs.last().map_or(span, |input| input.span),
                 "functions with the \"rust-call\" ABI must take a single non-self tuple argument",
             );
@@ -1607,7 +1607,7 @@ fn check_method_receiver<'tcx>(
 }
 
 fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) -> ErrorGuaranteed {
-    struct_span_err!(tcx.sess.dcx(), span, E0307, "invalid `self` parameter type: {receiver_ty}")
+    struct_span_err!(tcx.dcx(), span, E0307, "invalid `self` parameter type: {receiver_ty}")
         .note("type of `self` must be `Self` or a type that dereferences to it")
         .help(HELP_FOR_SELF_TYPE)
         .emit()
@@ -1807,7 +1807,7 @@ fn check_variances_for_type_defn<'tcx>(
             //
             // if they aren't in the same order, then the user has written invalid code, and already
             // got an error about it (or I'm wrong about this)
-            tcx.sess.span_delayed_bug(
+            tcx.dcx().span_delayed_bug(
                 hir_param.span,
                 "hir generics and ty generics in different order",
             );
@@ -1913,7 +1913,8 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error
 }
 
 fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) -> DiagnosticBuilder<'_> {
-    let mut err = struct_span_err!(tcx.sess, span, E0392, "parameter `{param_name}` is never used");
+    let mut err =
+        struct_span_err!(tcx.dcx(), span, E0392, "parameter `{param_name}` is never used");
     err.span_label(span, "unused parameter");
     err
 }
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index f277badf275b7..8d362f74b0a26 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -64,7 +64,7 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
 
     let impl_ = tcx.hir().expect_item(impl_did).expect_impl();
 
-    tcx.sess.emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span });
+    tcx.dcx().emit_err(errors::DropImplOnWrongItem { span: impl_.self_ty.span });
 }
 
 fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
@@ -90,10 +90,10 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
             infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span);
         }
         Err(CopyImplementationError::NotAnAdt) => {
-            tcx.sess.emit_err(errors::CopyImplOnNonAdt { span });
+            tcx.dcx().emit_err(errors::CopyImplOnNonAdt { span });
         }
         Err(CopyImplementationError::HasDestructor) => {
-            tcx.sess.emit_err(errors::CopyImplOnTypeWithDtor { span });
+            tcx.dcx().emit_err(errors::CopyImplOnTypeWithDtor { span });
         }
     }
 }
@@ -116,7 +116,7 @@ fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId)
             infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span);
         }
         Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
-            tcx.sess.emit_err(errors::ConstParamTyImplOnNonAdt { span });
+            tcx.dcx().emit_err(errors::ConstParamTyImplOnNonAdt { span });
         }
     }
 }
@@ -173,7 +173,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
                 let source_path = tcx.def_path_str(def_a.did());
                 let target_path = tcx.def_path_str(def_b.did());
 
-                tcx.sess.emit_err(errors::DispatchFromDynCoercion {
+                tcx.dcx().emit_err(errors::DispatchFromDynCoercion {
                     span,
                     trait_name: "DispatchFromDyn",
                     note: true,
@@ -185,7 +185,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
             }
 
             if def_a.repr().c() || def_a.repr().packed() {
-                tcx.sess.emit_err(errors::DispatchFromDynRepr { span });
+                tcx.dcx().emit_err(errors::DispatchFromDynRepr { span });
             }
 
             let fields = &def_a.non_enum_variant().fields;
@@ -207,7 +207,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
                         infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, ty_a, ty_b)
                     {
                         if ok.obligations.is_empty() {
-                            tcx.sess.emit_err(errors::DispatchFromDynZST {
+                            tcx.dcx().emit_err(errors::DispatchFromDynZST {
                                 span,
                                 name: field.name,
                                 ty: ty_a,
@@ -222,13 +222,13 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
                 .collect::<Vec<_>>();
 
             if coerced_fields.is_empty() {
-                tcx.sess.emit_err(errors::DispatchFromDynSingle {
+                tcx.dcx().emit_err(errors::DispatchFromDynSingle {
                     span,
                     trait_name: "DispatchFromDyn",
                     note: true,
                 });
             } else if coerced_fields.len() > 1 {
-                tcx.sess.emit_err(errors::DispatchFromDynMulti {
+                tcx.dcx().emit_err(errors::DispatchFromDynMulti {
                     span,
                     coercions_note: true,
                     number: coerced_fields.len(),
@@ -270,7 +270,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
             }
         }
         _ => {
-            tcx.sess.emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" });
+            tcx.dcx().emit_err(errors::CoerceUnsizedMay { span, trait_name: "DispatchFromDyn" });
         }
     }
 }
@@ -337,7 +337,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
             if def_a != def_b {
                 let source_path = tcx.def_path_str(def_a.did());
                 let target_path = tcx.def_path_str(def_b.did());
-                tcx.sess.emit_err(errors::DispatchFromDynSame {
+                tcx.dcx().emit_err(errors::DispatchFromDynSame {
                     span,
                     trait_name: "CoerceUnsized",
                     note: true,
@@ -419,7 +419,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
                 .collect::<Vec<_>>();
 
             if diff_fields.is_empty() {
-                tcx.sess.emit_err(errors::CoerceUnsizedOneField {
+                tcx.dcx().emit_err(errors::CoerceUnsizedOneField {
                     span,
                     trait_name: "CoerceUnsized",
                     note: true,
@@ -433,7 +433,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
                     tcx.def_span(impl_did)
                 };
 
-                tcx.sess.emit_err(errors::CoerceUnsizedMulti {
+                tcx.dcx().emit_err(errors::CoerceUnsizedMulti {
                     span,
                     coercions_note: true,
                     number: diff_fields.len(),
@@ -453,7 +453,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
         }
 
         _ => {
-            tcx.sess.emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" });
+            tcx.dcx().emit_err(errors::DispatchFromDynStruct { span, trait_name: "CoerceUnsized" });
             return err_info;
         }
     };
@@ -583,7 +583,7 @@ fn infringing_fields_error(
         });
     }
 
-    let mut err = tcx.sess.create_err(errors::TraitCannotImplForTy {
+    let mut err = tcx.dcx().create_err(errors::TraitCannotImplForTy {
         span: impl_span,
         trait_name,
         label_spans,
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 1b4df31b50c70..3162004a6348c 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -62,14 +62,14 @@ impl<'tcx> InherentCollect<'tcx> {
 
             if !self.tcx.has_attr(ty_def_id, sym::rustc_has_incoherent_inherent_impls) {
                 let impl_span = self.tcx.def_span(impl_def_id);
-                self.tcx.sess.emit_err(errors::InherentTyOutside { span: impl_span });
+                self.tcx.dcx().emit_err(errors::InherentTyOutside { span: impl_span });
                 return;
             }
 
             for &impl_item in items {
                 if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
                     let impl_span = self.tcx.def_span(impl_def_id);
-                    self.tcx.sess.emit_err(errors::InherentTyOutsideRelevant {
+                    self.tcx.dcx().emit_err(errors::InherentTyOutsideRelevant {
                         span: impl_span,
                         help_span: self.tcx.def_span(impl_item),
                     });
@@ -84,7 +84,7 @@ impl<'tcx> InherentCollect<'tcx> {
             }
         } else {
             let impl_span = self.tcx.def_span(impl_def_id);
-            self.tcx.sess.emit_err(errors::InherentTyOutsideNew { span: impl_span });
+            self.tcx.dcx().emit_err(errors::InherentTyOutsideNew { span: impl_span });
         }
     }
 
@@ -95,7 +95,7 @@ impl<'tcx> InherentCollect<'tcx> {
                 for &impl_item in items {
                     if !self.tcx.has_attr(impl_item, sym::rustc_allow_incoherent_impl) {
                         let span = self.tcx.def_span(impl_def_id);
-                        self.tcx.sess.emit_err(errors::InherentTyOutsidePrimitive {
+                        self.tcx.dcx().emit_err(errors::InherentTyOutsidePrimitive {
                             span,
                             help_span: self.tcx.def_span(impl_item),
                         });
@@ -108,7 +108,7 @@ impl<'tcx> InherentCollect<'tcx> {
                 if let ty::Ref(_, subty, _) = ty.kind() {
                     note = Some(errors::InherentPrimitiveTyNote { subty: *subty });
                 }
-                self.tcx.sess.emit_err(errors::InherentPrimitiveTy { span, note });
+                self.tcx.dcx().emit_err(errors::InherentPrimitiveTy { span, note });
                 return;
             }
         }
@@ -135,7 +135,7 @@ impl<'tcx> InherentCollect<'tcx> {
                 self.check_def_id(id, self_ty, data.principal_def_id().unwrap());
             }
             ty::Dynamic(..) => {
-                self.tcx.sess.emit_err(errors::InherentDyn { span: item_span });
+                self.tcx.dcx().emit_err(errors::InherentDyn { span: item_span });
             }
             ty::Bool
             | ty::Char
@@ -151,7 +151,7 @@ impl<'tcx> InherentCollect<'tcx> {
             | ty::FnPtr(_)
             | ty::Tuple(..) => self.check_primitive_impl(id, self_ty),
             ty::Alias(..) | ty::Param(_) => {
-                self.tcx.sess.emit_err(errors::InherentNominal { span: item_span });
+                self.tcx.dcx().emit_err(errors::InherentNominal { span: item_span });
             }
             ty::FnDef(..)
             | ty::Closure(..)
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index 3f8c0db8752d3..ec15aa65e7ac2 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -71,7 +71,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
                 Entry::Occupied(entry) => {
                     let former = entry.get();
                     let mut err = struct_span_err!(
-                        self.tcx.sess,
+                        self.tcx.dcx(),
                         span,
                         E0592,
                         "duplicate definitions with name `{}`",
@@ -106,7 +106,7 @@ impl<'tcx> InherentOverlapChecker<'tcx> {
             if let Some(item2) = collision {
                 let name = item1.ident(self.tcx).normalize_to_macros_2_0();
                 let mut err = struct_span_err!(
-                    self.tcx.sess,
+                    self.tcx.dcx(),
                     self.tcx.def_span(item1.def_id),
                     E0592,
                     "duplicate definitions with name `{}`",
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index fc8fab0eabc83..5cc9da25d6a53 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -46,7 +46,7 @@ fn enforce_trait_manually_implementable(
     if tcx.trait_def(trait_def_id).deny_explicit_impl {
         let trait_name = tcx.item_name(trait_def_id);
         let mut err = struct_span_err!(
-            tcx.sess,
+            tcx.dcx(),
             impl_header_span,
             E0322,
             "explicit impls for the `{trait_name}` trait are not permitted"
@@ -67,7 +67,7 @@ fn enforce_trait_manually_implementable(
         tcx.trait_def(trait_def_id).specialization_kind
     {
         if !tcx.features().specialization && !tcx.features().min_specialization {
-            tcx.sess.emit_err(errors::SpecializationTrait { span: impl_header_span });
+            tcx.dcx().emit_err(errors::SpecializationTrait { span: impl_header_span });
             return;
         }
     }
@@ -89,7 +89,7 @@ fn enforce_empty_impls_for_marker_traits(
     }
 
     struct_span_err!(
-        tcx.sess,
+        tcx.dcx(),
         tcx.def_span(impl_def_id),
         E0715,
         "impls for marker traits cannot contain items"
@@ -174,7 +174,7 @@ fn check_object_overlap<'tcx>(
                 if supertrait_def_ids.any(|d| d == trait_def_id) {
                     let span = tcx.def_span(impl_def_id);
                     struct_span_err!(
-                        tcx.sess,
+                        tcx.dcx(),
                         span,
                         E0371,
                         "the object type `{}` automatically implements the trait `{}`",
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index d33cfe4ad4d73..c1d0e0444b673 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -260,7 +260,7 @@ fn do_orphan_check_impl<'tcx>(
             match local_impl {
                 LocalImpl::Allow => {}
                 LocalImpl::Disallow { problematic_kind } => {
-                    return Err(tcx.sess.emit_err(errors::TraitsWithDefaultImpl {
+                    return Err(tcx.dcx().emit_err(errors::TraitsWithDefaultImpl {
                         span: tcx.def_span(def_id),
                         traits: tcx.def_path_str(trait_def_id),
                         problematic_kind,
@@ -272,13 +272,13 @@ fn do_orphan_check_impl<'tcx>(
             match nonlocal_impl {
                 NonlocalImpl::Allow => {}
                 NonlocalImpl::DisallowBecauseNonlocal => {
-                    return Err(tcx.sess.emit_err(errors::CrossCrateTraitsDefined {
+                    return Err(tcx.dcx().emit_err(errors::CrossCrateTraitsDefined {
                         span: tcx.def_span(def_id),
                         traits: tcx.def_path_str(trait_def_id),
                     }));
                 }
                 NonlocalImpl::DisallowOther => {
-                    return Err(tcx.sess.emit_err(errors::CrossCrateTraits {
+                    return Err(tcx.dcx().emit_err(errors::CrossCrateTraits {
                         span: tcx.def_span(def_id),
                         traits: tcx.def_path_str(trait_def_id),
                         self_ty,
@@ -422,7 +422,7 @@ fn emit_orphan_check_error<'tcx>(
                     sugg,
                 },
             };
-            tcx.sess.emit_err(err_struct)
+            tcx.dcx().emit_err(err_struct)
         }
         traits::OrphanCheckErr::UncoveredTy(param_ty, local_type) => {
             let mut sp = sp;
@@ -433,13 +433,13 @@ fn emit_orphan_check_error<'tcx>(
             }
 
             match local_type {
-                Some(local_type) => tcx.sess.emit_err(errors::TyParamFirstLocal {
+                Some(local_type) => tcx.dcx().emit_err(errors::TyParamFirstLocal {
                     span: sp,
                     note: (),
                     param_ty,
                     local_type,
                 }),
-                None => tcx.sess.emit_err(errors::TyParamSome { span: sp, note: (), param_ty }),
+                None => tcx.dcx().emit_err(errors::TyParamSome { span: sp, note: (), param_ty }),
             }
         }
     })
@@ -453,7 +453,7 @@ fn lint_auto_trait_impl<'tcx>(
     impl_def_id: LocalDefId,
 ) {
     if trait_ref.args.len() != 1 {
-        tcx.sess.dcx().span_delayed_bug(
+        tcx.dcx().span_delayed_bug(
             tcx.def_span(impl_def_id),
             "auto traits cannot have generic parameters",
         );
diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index 8a02bab92aaf7..d208c55055b8e 100644
--- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -19,7 +19,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
         match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
             (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
                 struct_span_err!(
-                    tcx.sess,
+                    tcx.dcx(),
                     tcx.def_span(def_id),
                     E0199,
                     "implementing the trait `{}` is not unsafe",
@@ -36,7 +36,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 
             (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
                 struct_span_err!(
-                    tcx.sess,
+                    tcx.dcx(),
                     tcx.def_span(def_id),
                     E0200,
                     "the trait `{}` requires an `unsafe impl` declaration",
@@ -59,7 +59,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 
             (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
                 struct_span_err!(
-                    tcx.sess,
+                    tcx.dcx(),
                     tcx.def_span(def_id),
                     E0569,
                     "requires an `unsafe impl` declaration due to `#[{}]` attribute",
@@ -82,7 +82,7 @@ pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
 
             (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
                 // Reported in AST validation
-                tcx.sess.span_delayed_bug(item.span, "unsafe negative impl");
+                tcx.dcx().span_delayed_bug(item.span, "unsafe negative impl");
             }
             (_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_))
             | (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index d43b4adfe39f2..4513653b64481 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -337,7 +337,7 @@ fn bad_placeholder<'tcx>(
     let kind = if kind.ends_with('s') { format!("{kind}es") } else { format!("{kind}s") };
 
     spans.sort();
-    tcx.sess.create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind })
+    tcx.dcx().create_err(errors::PlaceholderNotAllowedItemSignatures { spans, kind })
 }
 
 impl<'tcx> ItemCtxt<'tcx> {
@@ -476,7 +476,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
             }
             Ty::new_error(
                 self.tcx(),
-                self.tcx().sess.emit_err(errors::AssociatedTypeTraitUninferredGenericParams {
+                self.tcx().dcx().emit_err(errors::AssociatedTypeTraitUninferredGenericParams {
                     span,
                     inferred_sugg,
                     bound,
@@ -672,7 +672,7 @@ fn convert_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
 
         hir::TraitItemKind::Const(ty, body_id) => {
             tcx.ensure().type_of(def_id);
-            if !tcx.sess.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
+            if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
                 && !(is_suggestable_infer_ty(ty) && body_id.is_some())
             {
                 // Account for `const C: _;`.
@@ -756,7 +756,7 @@ fn convert_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) {
                 Some(discr)
             } else {
                 let span = tcx.def_span(variant.def_id);
-                tcx.sess.emit_err(errors::EnumDiscriminantOverflowed {
+                tcx.dcx().emit_err(errors::EnumDiscriminantOverflowed {
                     span,
                     discr: prev_discr.unwrap().to_string(),
                     item_name: tcx.item_name(variant.def_id),
@@ -797,7 +797,7 @@ fn convert_variant(
         .map(|f| {
             let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned();
             if let Some(prev_span) = dup_span {
-                tcx.sess.emit_err(errors::FieldAlreadyDeclared {
+                tcx.dcx().emit_err(errors::FieldAlreadyDeclared {
                     field_name: f.ident,
                     span: f.span,
                     prev_span,
@@ -905,7 +905,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
 
     let paren_sugar = tcx.has_attr(def_id, sym::rustc_paren_sugar);
     if paren_sugar && !tcx.features().unboxed_closures {
-        tcx.sess.emit_err(errors::ParenSugarAttribute { span: item.span });
+        tcx.dcx().emit_err(errors::ParenSugarAttribute { span: item.span });
     }
 
     let is_marker = tcx.has_attr(def_id, sym::marker);
@@ -925,7 +925,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
         // and that they are all identifiers
         .and_then(|attr| match attr.meta_item_list() {
             Some(items) if items.len() < 2 => {
-                tcx.sess.emit_err(errors::MustImplementOneOfAttribute { span: attr.span });
+                tcx.dcx().emit_err(errors::MustImplementOneOfAttribute { span: attr.span });
 
                 None
             }
@@ -934,7 +934,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
                 .map(|item| item.ident().ok_or(item.span()))
                 .collect::<Result<Box<[_]>, _>>()
                 .map_err(|span| {
-                    tcx.sess.emit_err(errors::MustBeNameOfAssociatedFunction { span });
+                    tcx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span });
                 })
                 .ok()
                 .zip(Some(attr.span)),
@@ -950,7 +950,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
                 match item {
                     Some(item) if matches!(item.kind, hir::AssocItemKind::Fn { .. }) => {
                         if !tcx.defaultness(item.id.owner_id).has_value() {
-                            tcx.sess.emit_err(errors::FunctionNotHaveDefaultImplementation {
+                            tcx.dcx().emit_err(errors::FunctionNotHaveDefaultImplementation {
                                 span: item.span,
                                 note_span: attr_span,
                             });
@@ -961,14 +961,14 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
                         return None;
                     }
                     Some(item) => {
-                        tcx.sess.emit_err(errors::MustImplementNotFunction {
+                        tcx.dcx().emit_err(errors::MustImplementNotFunction {
                             span: item.span,
                             span_note: errors::MustImplementNotFunctionSpanNote { span: attr_span },
                             note: errors::MustImplementNotFunctionNote {},
                         });
                     }
                     None => {
-                        tcx.sess.emit_err(errors::FunctionNotFoundInTrait { span: ident.span });
+                        tcx.dcx().emit_err(errors::FunctionNotFoundInTrait { span: ident.span });
                     }
                 }
 
@@ -984,7 +984,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
 
             for ident in &*list {
                 if let Some(dup) = set.insert(ident.name, ident.span) {
-                    tcx.sess
+                    tcx.dcx()
                         .emit_err(errors::FunctionNamesDuplicated { spans: vec![dup, ident.span] });
 
                     no_dups = false;
@@ -1005,7 +1005,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
                 && let Some(lit) = meta.name_value_literal()
             {
                 if seen_attr {
-                    tcx.sess.span_err(meta.span, "duplicated `implement_via_object` meta item");
+                    tcx.dcx().span_err(meta.span, "duplicated `implement_via_object` meta item");
                 }
                 seen_attr = true;
 
@@ -1017,7 +1017,7 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
                         implement_via_object = false;
                     }
                     _ => {
-                        tcx.sess.span_err(
+                        tcx.dcx().span_err(
                             meta.span,
                             format!(
                                 "unknown literal passed to `implement_via_object` attribute: {}",
@@ -1027,14 +1027,14 @@ fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
                     }
                 }
             } else {
-                tcx.sess.span_err(
+                tcx.dcx().span_err(
                     meta.span(),
                     format!("unknown meta item passed to `rustc_deny_explicit_impl` {meta:?}"),
                 );
             }
         }
         if !seen_attr {
-            tcx.sess.span_err(attr.span, "missing `implement_via_object` meta item");
+            tcx.dcx().span_err(attr.span, "missing `implement_via_object` meta item");
         }
     }
 
@@ -1414,7 +1414,7 @@ fn check_impl_constness(
     }
 
     let trait_name = tcx.item_name(trait_def_id).to_string();
-    Some(tcx.sess.emit_err(errors::ConstImplForNonConstTrait {
+    Some(tcx.dcx().emit_err(errors::ConstImplForNonConstTrait {
         trait_ref_span: ast_trait_ref.path.span,
         trait_name,
         local_trait_span:
@@ -1435,7 +1435,7 @@ fn impl_polarity(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplPolarity {
         }) => {
             if is_rustc_reservation {
                 let span = span.to(of_trait.as_ref().map_or(*span, |t| t.path.span));
-                tcx.sess.span_err(span, "reservation impls can't be negative");
+                tcx.dcx().span_err(span, "reservation impls can't be negative");
             }
             ty::ImplPolarity::Negative
         }
@@ -1445,7 +1445,7 @@ fn impl_polarity(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::ImplPolarity {
             ..
         }) => {
             if is_rustc_reservation {
-                tcx.sess.span_err(item.span, "reservation impls can't be inherent");
+                tcx.dcx().span_err(item.span, "reservation impls can't be inherent");
             }
             ty::ImplPolarity::Positive
         }
@@ -1535,7 +1535,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
                     .source_map()
                     .span_to_snippet(ast_ty.span)
                     .map_or_else(|_| String::new(), |s| format!(" `{s}`"));
-                tcx.sess.emit_err(errors::SIMDFFIHighlyExperimental { span: ast_ty.span, snip });
+                tcx.dcx().emit_err(errors::SIMDFFIHighlyExperimental { span: ast_ty.span, snip });
             }
         };
         for (input, ty) in iter::zip(decl.inputs, fty.inputs().skip_binder()) {
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 3ee2822edd8eb..4abebb4596674 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -283,7 +283,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                         );
                     }
                     Defaults::Deny => {
-                        tcx.sess.span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
+                        tcx.dcx().span_err(param.span, TYPE_DEFAULT_NOT_ALLOWED);
                     }
                 }
             }
@@ -304,7 +304,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 // `host` effect params are allowed to have defaults.
                 && !is_host_effect
             {
-                tcx.sess.span_err(
+                tcx.dcx().span_err(
                     param.span,
                     "defaults for const parameters are only allowed in \
                     `struct`, `enum`, `type`, or `trait` definitions",
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 9f0742dade8e7..9a28534d7900b 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -335,7 +335,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     // though this may happen when we call `poly_trait_ref_binder_info` with
                     // an (erroneous, #113423) associated return type bound in an impl header.
                     if !supertrait_bound_vars.is_empty() {
-                        self.tcx.sess.span_delayed_bug(
+                        self.tcx.dcx().span_delayed_bug(
                             DUMMY_SP,
                             format!(
                                 "found supertrait lifetimes without a binder to append \
@@ -461,7 +461,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
 
                 if !infer_spans.is_empty() {
                     self.tcx
-                        .sess
+                        .dcx()
                         .emit_err(errors::ClosureImplicitHrtb { spans: infer_spans, for_sp });
                 }
             }
@@ -738,7 +738,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     let parent_id = self.tcx.hir().parent_id(hir_id);
                     if !parent_id.is_owner() {
                         struct_span_err!(
-                            self.tcx.sess,
+                            self.tcx.dcx(),
                             lifetime.ident.span,
                             E0657,
                             "`impl Trait` can only capture lifetimes bound at the fn or impl level"
@@ -750,7 +750,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                         kind: hir::ItemKind::OpaqueTy { .. }, ..
                     }) = self.tcx.hir_node(parent_id)
                     {
-                        let mut err = self.tcx.sess.struct_span_err(
+                        let mut err = self.tcx.dcx().struct_span_err(
                             lifetime.ident.span,
                             "higher kinded lifetime bounds on nested opaque types are not supported yet",
                         );
@@ -1268,7 +1268,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 let def_span = self.tcx.def_span(param_def_id);
                 let guar = match self.tcx.def_kind(param_def_id) {
                     DefKind::LifetimeParam => {
-                        self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Lifetime {
+                        self.tcx.dcx().emit_err(errors::CannotCaptureLateBound::Lifetime {
                             use_span,
                             def_span,
                             what,
@@ -1323,7 +1323,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 Scope::Binder {
                     where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
                 } => {
-                    self.tcx.sess.emit_err(errors::LateBoundInApit::Lifetime {
+                    self.tcx.dcx().emit_err(errors::LateBoundInApit::Lifetime {
                         span: lifetime_ref.ident.span,
                         param_span: self.tcx.def_span(region_def_id),
                     });
@@ -1341,7 +1341,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
             }
         }
 
-        self.tcx.sess.span_delayed_bug(
+        self.tcx.dcx().span_delayed_bug(
             lifetime_ref.ident.span,
             format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
         );
@@ -1406,14 +1406,14 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 let def_span = self.tcx.def_span(param_def_id);
                 let guar = match self.tcx.def_kind(param_def_id) {
                     DefKind::ConstParam => {
-                        self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Const {
+                        self.tcx.dcx().emit_err(errors::CannotCaptureLateBound::Const {
                             use_span,
                             def_span,
                             what,
                         })
                     }
                     DefKind::TyParam => {
-                        self.tcx.sess.emit_err(errors::CannotCaptureLateBound::Type {
+                        self.tcx.dcx().emit_err(errors::CannotCaptureLateBound::Type {
                             use_span,
                             def_span,
                             what,
@@ -1447,7 +1447,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                 Scope::Binder {
                     where_bound_origin: Some(hir::PredicateOrigin::ImplTrait), ..
                 } => {
-                    let guar = self.tcx.sess.emit_err(match self.tcx.def_kind(param_def_id) {
+                    let guar = self.tcx.dcx().emit_err(match self.tcx.def_kind(param_def_id) {
                         DefKind::TyParam => errors::LateBoundInApit::Type {
                             span: self.tcx.hir().span(hir_id),
                             param_span: self.tcx.def_span(param_def_id),
@@ -1475,7 +1475,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
             }
         }
 
-        self.tcx.sess.span_delayed_bug(
+        self.tcx.dcx().span_delayed_bug(
             self.tcx.hir().span(hir_id),
             format!("could not resolve {param_def_id:?}"),
         );
@@ -1705,7 +1705,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
                     bound_vars
                 } else {
                     self.tcx
-                        .sess
+                        .dcx()
                         .span_delayed_bug(binding.ident.span, "bad return type notation here");
                     vec![]
                 };
@@ -2039,7 +2039,7 @@ fn is_late_bound_map(
                                         Some(true) => Some(arg),
                                         Some(false) => None,
                                         None => {
-                                            tcx.sess.span_delayed_bug(
+                                            tcx.dcx().span_delayed_bug(
                                                 *span,
                                                 format!(
                                                     "Incorrect generic arg count for alias {alias_def:?}"
@@ -2114,7 +2114,7 @@ pub fn deny_non_region_late_bound(
             hir::GenericParamKind::Lifetime { .. } => continue,
         };
 
-        let mut diag = tcx.sess.struct_span_err(
+        let mut diag = tcx.dcx().struct_span_err(
             param.span,
             format!("late-bound {what} parameter not allowed on {where_}"),
         );
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 19e7fe388aae7..55720e6d2aa4f 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -440,7 +440,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
             ItemKind::Impl(hir::Impl { self_ty, .. }) => match self_ty.find_self_aliases() {
                 spans if spans.len() > 0 => {
                     let guar = tcx
-                        .sess
+                        .dcx()
                         .emit_err(crate::errors::SelfInImplSelf { span: spans.into(), note: () });
                     Ty::new_error(tcx, guar)
                 }
@@ -574,7 +574,7 @@ fn infer_placeholder_type<'a>(
     // then the user may have written e.g. `const A = 42;`.
     // In this case, the parser has stashed a diagnostic for
     // us to improve in typeck so we do that now.
-    match tcx.sess.dcx().steal_diagnostic(span, StashKey::ItemNoType) {
+    match tcx.dcx().steal_diagnostic(span, StashKey::ItemNoType) {
         Some(mut err) => {
             if !ty.references_error() {
                 // Only suggest adding `:` if it was missing (and suggested by parsing diagnostic)
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index 3785b61f2f727..5a73097b0f6b3 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -15,7 +15,7 @@ pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) {
             if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
                 let type_of = tcx.type_of(id.owner_id).instantiate_identity();
 
-                tcx.sess.emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of });
+                tcx.dcx().emit_err(TypeOf { span: tcx.def_span(id.owner_id), type_of });
             }
         }
     }
@@ -92,7 +92,7 @@ pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: Local
             // Account for `type Alias = impl Trait<Foo = impl Trait>;` (#116031)
             parent_def_id = tcx.local_parent(parent_def_id);
         }
-        let reported = tcx.sess.emit_err(UnconstrainedOpaqueType {
+        let reported = tcx.dcx().emit_err(UnconstrainedOpaqueType {
             span: tcx.def_span(def_id),
             name: tcx.item_name(parent_def_id.to_def_id()),
             what: match tcx.hir_node(scope) {
@@ -158,7 +158,7 @@ impl TaitConstraintLocator<'_> {
             }
             constrained = true;
             if !self.tcx.opaque_types_defined_by(item_def_id).contains(&self.def_id) {
-                self.tcx.sess.emit_err(TaitForwardCompat {
+                self.tcx.dcx().emit_err(TaitForwardCompat {
                     span: hidden_type.span,
                     item_span: self
                         .tcx
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 78745fe47abb6..2a9101b3808fa 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -28,7 +28,7 @@ fn diagnostic_hir_wf_check<'tcx>(
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
 
     // HIR wfcheck should only ever happen as part of improving an existing error
-    tcx.sess
+    tcx.dcx()
         .span_delayed_bug(tcx.def_span(def_id), "Performed HIR wfcheck without an existing error!");
 
     let icx = ItemCtxt::new(tcx, def_id);
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index fff4a919e91f5..ff5fff9363f35 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -74,7 +74,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
     if impl_self_ty.references_error() {
         // Don't complain about unconstrained type params when self ty isn't known due to errors.
         // (#36836)
-        tcx.sess.span_delayed_bug(
+        tcx.dcx().span_delayed_bug(
             tcx.def_span(impl_def_id),
             format!(
                 "potentially unconstrained type parameters weren't evaluated: {impl_self_ty:?}",
@@ -171,7 +171,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
 
 fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: Symbol) {
     let mut err = struct_span_err!(
-        tcx.sess,
+        tcx.dcx(),
         span,
         E0207,
         "the {} parameter `{}` is not constrained by the \
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 7941861fd2f7d..93dd2342a4d13 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -135,7 +135,7 @@ fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node,
         && tcx.associated_item_def_ids(impl1_def_id).is_empty()
     {
         let base_impl_span = tcx.def_span(impl2_id);
-        tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span });
+        tcx.dcx().emit_err(errors::EmptySpecialization { span, base_impl_span });
     }
 }
 
@@ -152,7 +152,7 @@ fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node,
 
     if let hir::Constness::Const = impl2_constness {
         if let hir::Constness::NotConst = impl1_constness {
-            tcx.sess.emit_err(errors::ConstSpecialize { span });
+            tcx.dcx().emit_err(errors::ConstSpecialize { span });
         }
     }
 }
@@ -207,7 +207,7 @@ fn get_impl_args(
     let _ = ocx.resolve_regions_and_report_errors(impl1_def_id, &outlives_env);
     let Ok(impl2_args) = infcx.fully_resolve(impl2_args) else {
         let span = tcx.def_span(impl1_def_id);
-        let guar = tcx.sess.emit_err(SubstsOnOverriddenImpl { span });
+        let guar = tcx.dcx().emit_err(SubstsOnOverriddenImpl { span });
         return Err(guar);
     };
     Ok((impl1_args, impl2_args))
@@ -295,7 +295,7 @@ fn check_duplicate_params<'tcx>(
     base_params.sort_by_key(|param| param.0);
     if let (_, [duplicate, ..]) = base_params.partition_dedup() {
         let param = impl1_args[duplicate.0 as usize];
-        tcx.sess
+        tcx.dcx()
             .struct_span_err(span, format!("specializing impl repeats parameter `{param}`"))
             .emit();
     }
@@ -315,7 +315,7 @@ fn check_static_lifetimes<'tcx>(
     span: Span,
 ) {
     if tcx.any_free_region_meets(parent_args, |r| r.is_static()) {
-        tcx.sess.emit_err(errors::StaticSpecialize { span });
+        tcx.dcx().emit_err(errors::StaticSpecialize { span });
     }
 }
 
@@ -455,7 +455,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, sp
                 trait_specialization_kind(tcx, clause),
                 Some(TraitSpecializationKind::Marker)
             ) {
-                tcx.sess
+                tcx.dcx()
                     .struct_span_err(
                         span,
                         format!(
@@ -467,7 +467,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, sp
             }
         }
         ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
-            tcx.sess
+            tcx.dcx()
                 .struct_span_err(
                     span,
                     format!("cannot specialize on associated type `{projection_ty} == {term}`",),
@@ -485,7 +485,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, clause: ty::Clause<'tcx>, sp
             // revisited.
         }
         _ => {
-            tcx.sess
+            tcx.dcx()
                 .struct_span_err(span, format!("cannot specialize on predicate `{clause}`"))
                 .emit();
         }
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 91cdffbbe4f69..81d8982eb1574 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -147,7 +147,7 @@ fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi
         (true, false) => CONVENTIONS_UNSTABLE,
     };
 
-    tcx.sess.emit_err(errors::VariadicFunctionCompatibleConvention { span, conventions });
+    tcx.dcx().emit_err(errors::VariadicFunctionCompatibleConvention { span, conventions });
 }
 
 pub fn provide(providers: &mut Providers) {
@@ -234,7 +234,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
 
     tcx.ensure().check_unused_traits(());
 
-    if let Some(reported) = tcx.sess.has_errors() { Err(reported) } else { Ok(()) }
+    if let Some(reported) = tcx.dcx().has_errors() { Err(reported) } else { Ok(()) }
 }
 
 /// A quasi-deprecated helper used in rustdoc and clippy to get
diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs
index b3cbc312721c0..dea3f1a993087 100644
--- a/compiler/rustc_hir_analysis/src/outlives/test.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/test.rs
@@ -18,7 +18,7 @@ pub fn test_inferred_outlives(tcx: TyCtxt<'_>) {
             pred.sort();
 
             let span = tcx.def_span(id.owner_id);
-            let mut err = tcx.sess.struct_span_err(span, "rustc_outlives");
+            let mut err = tcx.dcx().struct_span_err(span, "rustc_outlives");
             for p in pred {
                 err.note(p);
             }
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
index 7cc4982820be1..634904e32715d 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
@@ -28,7 +28,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx, '_> {
                 (None, "".to_string(), Some(()))
             };
 
-        let mut err = self.sess.create_err(errors::PassToVariadicFunction {
+        let mut err = self.sess.dcx().create_err(errors::PassToVariadicFunction {
             span: self.span,
             ty: self.ty,
             cast_ty: self.cast_ty,
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
index 6ba27f4974404..c68d74969a548 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/sized_unsized_cast.rs
@@ -21,7 +21,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for SizedUnsizedCast<'tcx> {
     }
 
     fn diagnostic_common(&self) -> DiagnosticBuilder<'tcx> {
-        let mut err = self.sess.create_err(errors::CastThinPointerToFatPointer {
+        let mut err = self.sess.dcx().create_err(errors::CastThinPointerToFatPointer {
             span: self.span,
             expr_ty: self.expr_ty,
             cast_ty: self.cast_ty.to_owned(),
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index c7818d80dbf9e..ae68a8bf2811e 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -524,7 +524,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         let span = self.path_segment.ident.span;
         let msg = self.create_error_message();
 
-        self.tcx.sess.struct_span_err_with_code(span, msg, self.code())
+        self.tcx.dcx().struct_span_err_with_code(span, msg, self.code())
     }
 
     /// Builds the `expected 1 type argument / supplied 2 type arguments` message.
diff --git a/compiler/rustc_hir_analysis/src/variance/test.rs b/compiler/rustc_hir_analysis/src/variance/test.rs
index d98dc0e6b83ef..5264d5aa26f21 100644
--- a/compiler/rustc_hir_analysis/src/variance/test.rs
+++ b/compiler/rustc_hir_analysis/src/variance/test.rs
@@ -11,7 +11,7 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
             if matches!(tcx.def_kind(id.owner_id), DefKind::OpaqueTy) {
                 let variances_of = tcx.variances_of(id.owner_id);
 
-                tcx.sess.emit_err(errors::VariancesOf {
+                tcx.dcx().emit_err(errors::VariancesOf {
                     span: tcx.def_span(id.owner_id),
                     variances_of: format!("{variances_of:?}"),
                 });
@@ -25,7 +25,7 @@ pub fn test_variance(tcx: TyCtxt<'_>) {
         if tcx.has_attr(id.owner_id, sym::rustc_variance) {
             let variances_of = tcx.variances_of(id.owner_id);
 
-            tcx.sess.emit_err(errors::VariancesOf {
+            tcx.dcx().emit_err(errors::VariancesOf {
                 span: tcx.def_span(id.owner_id),
                 variances_of: format!("{variances_of:?}"),
             });
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 2146effd84f06..2f8ad96deb430 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -51,7 +51,7 @@ pub fn check_legal_trait_for_method_call(
         } else {
             errors::ExplicitDestructorCallSugg::Empty(span)
         };
-        tcx.sess.emit_err(errors::ExplicitDestructorCall { span, sugg });
+        tcx.dcx().emit_err(errors::ExplicitDestructorCall { span, sugg });
     }
 }
 
@@ -244,7 +244,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ) {
                 // Check for `self` receiver on the method, otherwise we can't use this as a `Fn*` trait.
                 if !self.tcx.associated_item(ok.value.def_id).fn_has_self_parameter {
-                    self.tcx.sess.span_delayed_bug(
+                    self.dcx().span_delayed_bug(
                         call_expr.span,
                         "input to overloaded call fn is not a self receiver",
                     );
@@ -259,7 +259,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind() else {
                         // The `fn`/`fn_mut` lang item is ill-formed, which should have
                         // caused an error elsewhere.
-                        self.tcx.sess.span_delayed_bug(
+                        self.dcx().span_delayed_bug(
                             call_expr.span,
                             "input to call/call_mut is not a ref",
                         );
@@ -395,8 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             predicate,
                         );
                         let result = self.evaluate_obligation(&obligation);
-                        self.tcx
-                            .sess
+                        self.dcx()
                             .struct_span_err(
                                 callee_expr.span,
                                 format!("evaluate({predicate:?}) = {result:?}"),
@@ -416,11 +415,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = &callee_expr.kind
                     && let [segment] = path.segments
-                    && let Some(mut diag) = self
-                        .tcx
-                        .sess
-                        .dcx()
-                        .steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod)
+                    && let Some(mut diag) =
+                        self.dcx().steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod)
                 {
                     // Try suggesting `foo(a)` -> `a.foo()` if possible.
                     self.suggest_call_as_method(&mut diag, segment, arg_exprs, call_expr, expected);
@@ -469,7 +465,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 );
                 self.require_type_is_sized(ty, sp, traits::RustCall);
             } else {
-                self.tcx.sess.emit_err(errors::RustCallIncorrectArgs { span: sp });
+                self.dcx().emit_err(errors::RustCallIncorrectArgs { span: sp });
             }
         }
 
@@ -494,7 +490,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         self.tcx.require_lang_item(hir::LangItem::FnOnceOutput, Some(span));
                     if self.tcx.generics_of(fn_once_def_id).host_effect_index.is_none() {
                         if idx == 0 && !self.tcx.is_const_fn_raw(def_id) {
-                            self.tcx.sess.emit_err(errors::ConstSelectMustBeConst { span });
+                            self.dcx().emit_err(errors::ConstSelectMustBeConst { span });
                         }
                     } else {
                         let const_param: ty::GenericArg<'tcx> =
@@ -527,7 +523,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         self.select_obligations_where_possible(|_| {});
                     }
                 } else {
-                    self.tcx.sess.emit_err(errors::ConstSelectMustBeFn { span, ty: arg_ty });
+                    self.dcx().emit_err(errors::ConstSelectMustBeFn { span, ty: arg_ty });
                 }
             }
         }
@@ -657,7 +653,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let callee_ty = self.resolve_vars_if_possible(callee_ty);
-        let mut err = self.tcx.sess.create_err(errors::InvalidCallee {
+        let mut err = self.dcx().create_err(errors::InvalidCallee {
             span: callee_expr.span,
             ty: match &unit_variant {
                 Some((_, kind, path)) => format!("{kind} `{path}`"),
@@ -933,7 +929,7 @@ impl<'a, 'tcx> DeferredCallResolution<'tcx> {
             None => {
                 // This can happen if `#![no_core]` is used and the `fn/fn_mut/fn_once`
                 // lang items are not defined (issue #86238).
-                fcx.inh.tcx.sess.emit_err(errors::MissingFnLangItems { span: self.call_expr.span });
+                fcx.dcx().emit_err(errors::MissingFnLangItems { span: self.call_expr.span });
             }
         }
     }
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 9783fe79a90fc..0d21c013d6753 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -42,7 +42,6 @@ use rustc_middle::ty::cast::{CastKind, CastTy};
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitableExt, VariantDef};
 use rustc_session::lint;
-use rustc_session::Session;
 use rustc_span::def_id::{DefId, LOCAL_CRATE};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
@@ -140,8 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | ty::Dynamic(_, _, ty::DynStar)
             | ty::Error(_) => {
                 let reported = self
-                    .tcx
-                    .sess
+                    .dcx()
                     .span_delayed_bug(span, format!("`{t:?}` should be sized but is not?"));
                 return Err(reported);
             }
@@ -182,14 +180,13 @@ impl From<ErrorGuaranteed> for CastError {
 }
 
 fn make_invalid_casting_error<'a, 'tcx>(
-    sess: &'a Session,
     span: Span,
     expr_ty: Ty<'tcx>,
     cast_ty: Ty<'tcx>,
     fcx: &FnCtxt<'a, 'tcx>,
 ) -> DiagnosticBuilder<'a> {
     type_error_struct!(
-        sess,
+        fcx.dcx(),
         span,
         expr_ty,
         E0606,
@@ -229,13 +226,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 // an error has already been reported
             }
             CastError::NeedDeref => {
-                let mut err = make_invalid_casting_error(
-                    fcx.tcx.sess,
-                    self.span,
-                    self.expr_ty,
-                    self.cast_ty,
-                    fcx,
-                );
+                let mut err =
+                    make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx);
 
                 if matches!(self.expr.kind, ExprKind::AddrOf(..)) {
                     // get just the borrow part of the expression
@@ -258,13 +250,8 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 err.emit();
             }
             CastError::NeedViaThinPtr | CastError::NeedViaPtr => {
-                let mut err = make_invalid_casting_error(
-                    fcx.tcx.sess,
-                    self.span,
-                    self.expr_ty,
-                    self.cast_ty,
-                    fcx,
-                );
+                let mut err =
+                    make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx);
                 if self.cast_ty.is_integral() {
                     err.help(format!(
                         "cast through {} first",
@@ -281,36 +268,17 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 err.emit();
             }
             CastError::NeedViaInt => {
-                make_invalid_casting_error(
-                    fcx.tcx.sess,
-                    self.span,
-                    self.expr_ty,
-                    self.cast_ty,
-                    fcx,
-                )
-                .help("cast through an integer first")
-                .emit();
+                make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx)
+                    .help("cast through an integer first")
+                    .emit();
             }
             CastError::IllegalCast => {
-                make_invalid_casting_error(
-                    fcx.tcx.sess,
-                    self.span,
-                    self.expr_ty,
-                    self.cast_ty,
-                    fcx,
-                )
-                .emit();
+                make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx).emit();
             }
             CastError::DifferingKinds => {
-                make_invalid_casting_error(
-                    fcx.tcx.sess,
-                    self.span,
-                    self.expr_ty,
-                    self.cast_ty,
-                    fcx,
-                )
-                .note("vtable kinds may not match")
-                .emit();
+                make_invalid_casting_error(self.span, self.expr_ty, self.cast_ty, fcx)
+                    .note("vtable kinds may not match")
+                    .emit();
             }
             CastError::CastToBool => {
                 let expr_ty = fcx.resolve_vars_if_possible(self.expr_ty);
@@ -321,11 +289,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 } else {
                     errors::CannotCastToBoolHelp::Unsupported(self.span)
                 };
-                fcx.tcx.sess.emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help });
+                fcx.tcx.dcx().emit_err(errors::CannotCastToBool { span: self.span, expr_ty, help });
             }
             CastError::CastToChar => {
                 let mut err = type_error_struct!(
-                    fcx.tcx.sess,
+                    fcx.dcx(),
                     self.span,
                     self.expr_ty,
                     E0604,
@@ -355,7 +323,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             }
             CastError::NonScalar => {
                 let mut err = type_error_struct!(
-                    fcx.tcx.sess,
+                    fcx.dcx(),
                     self.span,
                     self.expr_ty,
                     E0605,
@@ -515,7 +483,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 let metadata = known_metadata.unwrap_or("type-specific metadata");
                 let known_wide = known_metadata.is_some();
                 let span = self.cast_span;
-                fcx.tcx.sess.emit_err(errors::IntToWide {
+                fcx.dcx().emit_err(errors::IntToWide {
                     span,
                     metadata,
                     expr_ty,
@@ -535,15 +503,10 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 } else {
                     (self.cast_span, errors::CastUnknownPointerSub::From(self.span))
                 };
-                fcx.tcx.sess.emit_err(errors::CastUnknownPointer {
-                    span,
-                    to: unknown_cast_to,
-                    sub,
-                });
+                fcx.dcx().emit_err(errors::CastUnknownPointer { span, to: unknown_cast_to, sub });
             }
             CastError::ForeignNonExhaustiveAdt => {
                 make_invalid_casting_error(
-                    fcx.tcx.sess,
                     self.span,
                     self.expr_ty,
                     self.cast_ty,
@@ -565,7 +528,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
 
         let tstr = fcx.ty_to_string(self.cast_ty);
         let mut err = type_error_struct!(
-            fcx.tcx.sess,
+            fcx.dcx(),
             self.span,
             self.expr_ty,
             E0620,
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index 8e2af40291879..f4bcee384a740 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -215,22 +215,22 @@ pub(super) fn check_fn<'a, 'tcx>(
 fn check_panic_info_fn(tcx: TyCtxt<'_>, fn_id: LocalDefId, fn_sig: ty::FnSig<'_>) {
     let DefKind::Fn = tcx.def_kind(fn_id) else {
         let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "should be a function");
+        tcx.dcx().span_err(span, "should be a function");
         return;
     };
 
     let generic_counts = tcx.generics_of(fn_id).own_counts();
     if generic_counts.types != 0 {
         let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "should have no type parameters");
+        tcx.dcx().span_err(span, "should have no type parameters");
     }
     if generic_counts.consts != 0 {
         let span = tcx.def_span(fn_id);
-        tcx.sess.span_err(span, "should have no const parameters");
+        tcx.dcx().span_err(span, "should have no const parameters");
     }
 
     let Some(panic_info_did) = tcx.lang_items().panic_info() else {
-        tcx.sess.err("language item required, but not found: `panic_info`");
+        tcx.dcx().err("language item required, but not found: `panic_info`");
         return;
     };
 
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index aed2dbb4505f0..1aa25a5bd7f76 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1548,9 +1548,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 // any superfluous errors we might encounter while trying to
                 // emit or provide suggestions on how to fix the initial error.
                 fcx.set_tainted_by_errors(
-                    fcx.tcx
-                        .sess
-                        .span_delayed_bug(cause.span, "coercion error but no error emitted"),
+                    fcx.dcx().span_delayed_bug(cause.span, "coercion error but no error emitted"),
                 );
                 let (expected, found) = if label_expression_as_expected {
                     // In the case where this is a "forced unit", like
@@ -1574,7 +1572,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                 match *cause.code() {
                     ObligationCauseCode::ReturnNoExpression => {
                         err = struct_span_err!(
-                            fcx.tcx.sess,
+                            fcx.dcx(),
                             cause.span,
                             E0069,
                             "`return;` in a function whose return type is not `()`"
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 6e5bd740b2ee4..c717319e5072a 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -256,7 +256,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         self.adjust_expr_for_assert_eq_macro(&mut expr, &mut expected_ty_expr);
 
-        self.set_tainted_by_errors(self.tcx.sess.span_delayed_bug(
+        self.set_tainted_by_errors(self.dcx().span_delayed_bug(
             expr.span,
             "`TypeError` when attempting coercion but no error emitted",
         ));
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index c4755b852bd0b..267fd00da84e8 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -75,7 +75,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // coercions from ! to `expected`.
         if ty.is_never() {
             if let Some(adjustments) = self.typeck_results.borrow().adjustments().get(expr.hir_id) {
-                let reported = self.tcx().sess.span_delayed_bug(
+                let reported = self.dcx().span_delayed_bug(
                     expr.span,
                     "expression with never type wound up being adjusted",
                 );
@@ -376,7 +376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         oprnd_t = ty;
                     } else {
                         let mut err = type_error_struct!(
-                            tcx.sess,
+                            self.dcx(),
                             expr.span,
                             oprnd_t,
                             E0614,
@@ -489,7 +489,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
         });
         if !is_named {
-            self.tcx.sess.emit_err(AddressOfTemporaryTaken { span: oprnd.span });
+            self.dcx().emit_err(AddressOfTemporaryTaken { span: oprnd.span });
         }
     }
 
@@ -514,7 +514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             Res::Err => {
                 self.suggest_assoc_method_call(segs);
                 let e =
-                    self.tcx.sess.span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
+                    self.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
                 Ty::new_error(tcx, e)
             }
@@ -623,7 +623,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Set expectation to error in that case and set tainted
                 // by error (#114529)
                 let coerce_to = opt_coerce_to.unwrap_or_else(|| {
-                    let guar = tcx.sess.span_delayed_bug(
+                    let guar = tcx.dcx().span_delayed_bug(
                         expr.span,
                         "illegal break with value found but no error reported",
                     );
@@ -690,7 +690,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // else an error would have been flagged by the
                 // `loops` pass for using break with an expression
                 // where you are not supposed to.
-                assert!(expr_opt.is_none() || self.tcx.sess.has_errors().is_some());
+                assert!(expr_opt.is_none() || self.dcx().has_errors().is_some());
             }
 
             // If we encountered a `break`, then (no surprise) it may be possible to break from the
@@ -901,7 +901,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             err.encl_fn_span = Some(*encl_fn_span);
         }
 
-        self.tcx.sess.emit_err(err);
+        self.dcx().emit_err(err);
     }
 
     fn point_at_return_for_opaque_ty_error(
@@ -940,7 +940,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         // FIXME: Make this use Diagnostic once error codes can be dynamically set.
-        let mut err = self.tcx.sess.struct_span_err_with_code(
+        let mut err = self.dcx().struct_span_err_with_code(
             op_span,
             "invalid left-hand side of assignment",
             DiagnosticId::Error(err_code.into()),
@@ -1292,7 +1292,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // permit break with a value [1].
         if ctxt.coerce.is_none() && !ctxt.may_break {
             // [1]
-            self.tcx.sess.span_delayed_bug(body.span, "no coercion, but loop may not break");
+            self.dcx().span_delayed_bug(body.span, "no coercion, but loop may not break");
         }
         ctxt.coerce.map(|c| c.complete(self)).unwrap_or_else(|| Ty::new_unit(self.tcx))
     }
@@ -1436,7 +1436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let hir::ArrayLen::Body(hir::AnonConst { hir_id, .. }) = length
             && let Some(span) = self.tcx.hir().opt_span(hir_id)
         {
-            match self.tcx.sess.dcx().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) {
+            match self.dcx().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) {
                 Some(mut err) => {
                     err.span_suggestion(
                         span,
@@ -1631,8 +1631,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Prohibit struct expressions when non-exhaustive flag is set.
         let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type");
         if !adt.did().is_local() && variant.is_field_list_non_exhaustive() {
-            self.tcx
-                .sess
+            self.dcx()
                 .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() });
         }
 
@@ -1705,7 +1704,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             } else {
                 error_happened = true;
                 let guar = if let Some(prev_span) = seen_fields.get(&ident) {
-                    tcx.sess.emit_err(FieldMultiplySpecifiedInInitializer {
+                    tcx.dcx().emit_err(FieldMultiplySpecifiedInInitializer {
                         span: field.ident.span,
                         prev_span: *prev_span,
                         ident,
@@ -1748,7 +1747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if adt_kind == AdtKind::Union {
             if ast_fields.len() != 1 {
                 struct_span_err!(
-                    tcx.sess,
+                    tcx.dcx(),
                     span,
                     E0784,
                     "union expressions should have exactly one field",
@@ -1842,9 +1841,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // Check the base_expr, regardless of a bad expected adt_ty, so we can get
                     // type errors on that expression, too.
                     self.check_expr(base_expr);
-                    self.tcx
-                        .sess
-                        .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
+                    self.dcx().emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
                     return;
                 }
             } else {
@@ -1869,8 +1866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .map(|f| self.normalize(expr.span, f.ty(self.tcx, args)))
                         .collect(),
                     _ => {
-                        self.tcx
-                            .sess
+                        self.dcx()
                             .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span });
                         return;
                     }
@@ -1958,7 +1954,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let mut err = struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             span,
             E0063,
             "missing field{} {}{} in initializer of `{}`",
@@ -1998,7 +1994,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         {
             // Suppress any range expr type mismatches
             if let Some(mut diag) =
-                self.tcx.sess.dcx().steal_diagnostic(last_expr_field.span, StashKey::MaybeFruTypo)
+                self.dcx().steal_diagnostic(last_expr_field.span, StashKey::MaybeFruTypo)
             {
                 diag.delay_as_bug();
             }
@@ -2047,7 +2043,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         used_fields: &'tcx [hir::ExprField<'tcx>],
     ) {
         let mut err =
-            self.tcx.sess.struct_span_err(
+            self.dcx().struct_span_err(
                 span,
                 format!(
                     "cannot construct `{adt_ty}` with struct literal syntax due to private fields",
@@ -2176,10 +2172,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         kind_name: &str,
     ) -> ErrorGuaranteed {
         if variant.is_recovered() {
-            let guar = self
-                .tcx
-                .sess
-                .span_delayed_bug(expr.span, "parser recovered but no error was emitted");
+            let guar =
+                self.dcx().span_delayed_bug(expr.span, "parser recovered but no error was emitted");
             self.set_tainted_by_errors(guar);
             return guar;
         }
@@ -2187,7 +2181,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             field.ident.span,
             |actual| match ty.kind() {
                 ty::Adt(adt, ..) if adt.is_enum() => struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     field.ident.span,
                     E0559,
                     "{} `{}::{}` has no field named `{}`",
@@ -2197,7 +2191,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     field.ident
                 ),
                 _ => struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     field.ident.span,
                     E0560,
                     "{} `{}` has no field named `{}`",
@@ -2395,7 +2389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let guar = if field.name == kw::Empty {
-            self.tcx.sess.span_delayed_bug(field.span, "field name with no name")
+            self.dcx().span_delayed_bug(field.span, "field name with no name")
         } else if self.method_exists(field, base_ty, expr.hir_id, expected.only_has_type(self)) {
             self.ban_take_value_of_method(expr, base_ty, field)
         } else if !base_ty.is_primitive_ty() {
@@ -2403,7 +2397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else {
             let field_name = field.to_string();
             let mut err = type_error_struct!(
-                self.tcx().sess,
+                self.dcx(),
                 field.span,
                 base_ty,
                 E0610,
@@ -2604,7 +2598,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         field: Ident,
     ) -> ErrorGuaranteed {
         let mut err = type_error_struct!(
-            self.tcx().sess,
+            self.dcx(),
             field.span,
             expr_t,
             E0615,
@@ -2743,7 +2737,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         debug!("no_such_field_err(span: {:?}, field: {:?}, expr_t: {:?})", span, field, expr_t);
 
         let mut err = type_error_struct!(
-            self.tcx().sess,
+            self.dcx(),
             span,
             expr_t,
             E0609,
@@ -2825,7 +2819,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let struct_path = self.tcx().def_path_str(base_did);
         let kind_name = self.tcx().def_descr(base_did);
         let mut err = struct_span_err!(
-            self.tcx().sess,
+            self.dcx(),
             field.span,
             E0616,
             "field `{field}` of {kind_name} `{struct_path}` is private",
@@ -2963,7 +2957,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
 
                     let mut err = type_error_struct!(
-                        self.tcx.sess,
+                        self.dcx(),
                         brackets_span,
                         base_t,
                         E0608,
@@ -3168,7 +3162,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Ty::new_unit(self.tcx)
             }
             _ => {
-                self.tcx.sess.emit_err(YieldExprOutsideOfCoroutine { span: expr.span });
+                self.dcx().emit_err(YieldExprOutsideOfCoroutine { span: expr.span });
                 // Avoid expressions without types during writeback (#78653).
                 self.check_expr(value);
                 Ty::new_unit(self.tcx)
@@ -3182,7 +3176,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         self.require_type_is_sized(ty, expr.span, traits::InlineAsmSized);
 
         if !is_input && !expr.is_syntactic_place_expr() {
-            let mut err = self.tcx.sess.struct_span_err(expr.span, "invalid asm output");
+            let mut err = self.dcx().struct_span_err(expr.span, "invalid asm output");
             err.span_label(expr.span, "cannot assign to this expression");
             err.emit();
         }
@@ -3278,7 +3272,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .find(|(_, v)| v.ident(self.tcx).normalize_to_macros_2_0() == ident)
                     else {
                         let mut err = type_error_struct!(
-                            self.tcx().sess,
+                            self.dcx(),
                             ident.span,
                             container,
                             E0599,
@@ -3290,7 +3284,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     };
                     let Some(&subfield) = fields.next() else {
                         let mut err = type_error_struct!(
-                            self.tcx().sess,
+                            self.dcx(),
                             ident.span,
                             container,
                             E0795,
@@ -3309,7 +3303,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == subident)
                     else {
                         let mut err = type_error_struct!(
-                            self.tcx().sess,
+                            self.dcx(),
                             ident.span,
                             container,
                             E0609,
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index c22b15231a155..e952a7ff9e8ce 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -538,7 +538,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
 
             // The struct path probably didn't resolve
             if self.mc.typeck_results.opt_field_index(field.hir_id).is_none() {
-                self.tcx().sess.span_delayed_bug(field.span, "couldn't resolve index for field");
+                self.tcx().dcx().span_delayed_bug(field.span, "couldn't resolve index for field");
             }
         }
 
@@ -576,7 +576,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
                 // struct; however, when EUV is run during typeck, it
                 // may not. This will generate an error earlier in typeck,
                 // so we can just ignore it.
-                if self.tcx().sess.has_errors().is_none() {
+                if self.tcx().dcx().has_errors().is_none() {
                     span_bug!(with_expr.span, "with expression doesn't evaluate to a struct");
                 }
             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 4bc237c2383b2..994f11b57d195 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -277,7 +277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // FIXME: currently we never try to compose autoderefs
                     // and ReifyFnPointer/UnsafeFnPointer, but we could.
                     _ => {
-                        self.tcx.sess.span_delayed_bug(
+                        self.dcx().span_delayed_bug(
                             expr.span,
                             format!(
                                 "while adjusting {:?}, can't compose {:?} and {:?}",
@@ -845,11 +845,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             .and_then(|r| {
                 // lint bare trait if the method is found in the trait
                 if span.edition().at_least_rust_2021()
-                    && let Some(mut diag) = self
-                        .tcx
-                        .sess
-                        .dcx()
-                        .steal_diagnostic(qself.span, StashKey::TraitMissingMethod)
+                    && let Some(mut diag) =
+                        self.dcx().steal_diagnostic(qself.span, StashKey::TraitMissingMethod)
                 {
                     diag.emit();
                 }
@@ -857,8 +854,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             })
             .or_else(|error| {
                 let guar = self
-                    .tcx
-                    .sess
+                    .dcx()
                     .span_delayed_bug(span, "method resolution should've emitted an error");
                 let result = match error {
                     method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
@@ -881,11 +877,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 // emit or cancel the diagnostic for bare traits
                 if span.edition().at_least_rust_2021()
-                    && let Some(mut diag) = self
-                        .tcx
-                        .sess
-                        .dcx()
-                        .steal_diagnostic(qself.span, StashKey::TraitMissingMethod)
+                    && let Some(mut diag) =
+                        self.dcx().steal_diagnostic(qself.span, StashKey::TraitMissingMethod)
                 {
                     if trait_missing_method {
                         // cancel the diag for bare traits when meeting `MyTrait::missing_method`
@@ -1216,7 +1209,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // Check the visibility of the ctor.
                     let vis = tcx.visibility(ctor_def_id);
                     if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) {
-                        tcx.sess
+                        tcx.dcx()
                             .emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) });
                     }
                     let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
@@ -1225,7 +1218,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     (new_res, Some(user_args.args))
                 }
                 _ => {
-                    let mut err = tcx.sess.struct_span_err(
+                    let mut err = tcx.dcx().struct_span_err(
                         span,
                         "the `Self` constructor can only be used with tuple or unit structs",
                     );
@@ -1433,7 +1426,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ) {
                 Ok(ok) => self.register_infer_ok_obligations(ok),
                 Err(_) => {
-                    self.tcx.sess.span_delayed_bug(
+                    self.dcx().span_delayed_bug(
                         span,
                         format!(
                         "instantiate_value_path: (UFCS) {self_ty:?} was a subtype of {impl_ty:?} but now is not?",
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 752401845cd92..7b85c492eae5c 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -205,7 +205,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     // Otherwise, there's a mismatch, so clear out what we're expecting, and set
                     // our input types to err_args so we don't blow up the error messages
                     struct_span_err!(
-                        tcx.sess,
+                        tcx.dcx(),
                         call_span,
                         E0059,
                         "cannot use call notation; the first type parameter \
@@ -488,7 +488,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let tcx = self.tcx;
         // FIXME: taint after emitting errors and pass through an `ErrorGuaranteed`
         self.set_tainted_by_errors(
-            tcx.sess.span_delayed_bug(call_span, "no errors reported for args"),
+            tcx.dcx().span_delayed_bug(call_span, "no errors reported for args"),
         );
 
         // Get the argument span in the context of the call span so that
@@ -664,7 +664,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             format!("arguments to this {call_name} are incorrect"),
                         );
                     } else {
-                        err = tcx.sess.struct_span_err_with_code(
+                        err = tcx.dcx().struct_span_err_with_code(
                             full_call_span,
                             format!(
                                 "{call_name} takes {}{} but {} {} supplied",
@@ -721,7 +721,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if cfg!(debug_assertions) {
                 span_bug!(error_span, "expected errors from argument matrix");
             } else {
-                tcx.sess.emit_err(errors::ArgMismatchIndeterminate { span: error_span });
+                tcx.dcx().emit_err(errors::ArgMismatchIndeterminate { span: error_span });
             }
             return;
         }
@@ -808,14 +808,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let mut err = if formal_and_expected_inputs.len() == provided_args.len() {
             struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 full_call_span,
                 E0308,
                 "arguments to this {} are incorrect",
                 call_name,
             )
         } else {
-            tcx.sess.struct_span_err_with_code(
+            tcx.dcx().struct_span_err_with_code(
                 full_call_span,
                 format!(
                     "this {} takes {}{} but {} {} supplied",
@@ -1334,7 +1334,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let variant = match def {
             Res::Err => {
                 let guar =
-                    self.tcx.sess.span_delayed_bug(path_span, "`Res::Err` but no error emitted");
+                    self.dcx().span_delayed_bug(path_span, "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(guar);
                 return Err(guar);
             }
@@ -1378,7 +1378,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     guar
                 }
                 _ => struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     path_span,
                     E0071,
                     "expected struct, variant or union type, found {}",
@@ -1822,8 +1822,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         errors_causecode: Vec<(Span, ObligationCauseCode<'tcx>)>,
     ) {
         for (span, code) in errors_causecode {
-            let Some(mut diag) =
-                self.tcx.sess.dcx().steal_diagnostic(span, StashKey::MaybeForgetReturn)
+            let Some(mut diag) = self.dcx().steal_diagnostic(span, StashKey::MaybeForgetReturn)
             else {
                 continue;
             };
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 072df1343ce65..635284c5f7323 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -4,10 +4,9 @@ mod arg_matrix;
 mod checks;
 mod suggestions;
 
-use rustc_errors::ErrorGuaranteed;
-
 use crate::coercion::DynamicCoerceMany;
 use crate::{Diverges, EnclosingBreakables, Inherited};
+use rustc_errors::{DiagCtxt, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir_analysis::astconv::AstConv;
@@ -120,7 +119,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         FnCtxt {
             body_id,
             param_env,
-            err_count_on_creation: inh.tcx.sess.err_count(),
+            err_count_on_creation: inh.tcx.dcx().err_count(),
             ret_coercion: None,
             ret_coercion_span: Cell::new(None),
             resume_yield_tys: None,
@@ -134,6 +133,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
     }
 
+    pub(crate) fn dcx(&self) -> &'tcx DiagCtxt {
+        self.tcx.dcx()
+    }
+
     pub fn cause(&self, span: Span, code: ObligationCauseCode<'tcx>) -> ObligationCause<'tcx> {
         ObligationCause::new(span, self.body_id, code)
     }
@@ -185,7 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub fn errors_reported_since_creation(&self) -> bool {
-        self.tcx.sess.err_count() > self.err_count_on_creation
+        self.dcx().err_count() > self.err_count_on_creation
     }
 
     pub fn next_root_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index a3c77af62a7c7..44d28123fa3fa 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -48,7 +48,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let to = normalize(to);
         trace!(?from, ?to);
         if from.has_non_region_infer() || to.has_non_region_infer() {
-            tcx.sess.span_delayed_bug(span, "argument to transmute has inference variables");
+            tcx.dcx().span_delayed_bug(span, "argument to transmute has inference variables");
             return;
         }
         // Transmutes that are only changing lifetimes are always ok.
@@ -73,7 +73,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to)
                 && size_to == Pointer(dl.instruction_address_space).size(&tcx)
             {
-                struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
+                struct_span_err!(tcx.dcx(), span, E0591, "can't transmute zero-sized type")
                     .note(format!("source type: {from}"))
                     .note(format!("target type: {to}"))
                     .help("cast with `as` to a pointer instead")
@@ -113,7 +113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         let mut err = struct_span_err!(
-            tcx.sess,
+            tcx.dcx(),
             span,
             E0512,
             "cannot transmute between types of different sizes, \
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index c6d7650f74592..d910643942003 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -71,8 +71,8 @@ rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
 
 #[macro_export]
 macro_rules! type_error_struct {
-    ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
-        let mut err = rustc_errors::struct_span_err!($session, $span, $code, $($message)*);
+    ($dcx:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({
+        let mut err = rustc_errors::struct_span_err!($dcx, $span, $code, $($message)*);
 
         if $typ.references_error() {
             err.downgrade_to_delayed_bug();
@@ -371,7 +371,7 @@ fn report_unexpected_variant_res(
         _ => res.descr(),
     };
     let path_str = rustc_hir_pretty::qpath_to_string(qpath);
-    let mut err = tcx.sess.struct_span_err_with_code(
+    let mut err = tcx.dcx().struct_span_err_with_code(
         span,
         format!("expected {expected}, found {res_descr} `{path_str}`"),
         DiagnosticId::Error(err_code.into()),
@@ -413,7 +413,7 @@ enum TupleArgumentsFlag {
 }
 
 fn fatally_break_rust(tcx: TyCtxt<'_>, span: Span) -> ! {
-    let dcx = tcx.sess.dcx();
+    let dcx = tcx.dcx();
     let mut diag = dcx.struct_span_bug(
         span,
         "It looks like you're trying to break rust; would you like some ICE?",
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index ebb15e072aaf5..ce3a4b4c80ce7 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -539,7 +539,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         let ty = self.typeck_results.node_type(pat_hir_id);
         let ty::Adt(adt_def, _) = ty.kind() else {
             self.tcx()
-                .sess
+                .dcx()
                 .span_delayed_bug(span, "struct or tuple struct pattern not applied to an ADT");
             return Err(());
         };
@@ -574,7 +574,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()),
             _ => {
                 self.tcx()
-                    .sess
+                    .dcx()
                     .span_delayed_bug(span, "struct or tuple struct pattern not applied to an ADT");
                 Err(())
             }
@@ -588,7 +588,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         match ty.kind() {
             ty::Tuple(args) => Ok(args.len()),
             _ => {
-                self.tcx().sess.span_delayed_bug(span, "tuple pattern not applied to a tuple");
+                self.tcx().dcx().span_delayed_bug(span, "tuple pattern not applied to a tuple");
                 Err(())
             }
         }
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index f820835acef96..c746fb8af89a2 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -385,7 +385,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // type parameters or early-bound regions.
         let tcx = self.tcx;
         let Some(method_item) = self.associated_value(trait_def_id, m_name) else {
-            tcx.sess.span_delayed_bug(
+            tcx.dcx().span_delayed_bug(
                 obligation.cause.span,
                 "operator trait does not have corresponding operator method",
             );
@@ -393,7 +393,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
 
         if method_item.kind != ty::AssocKind::Fn {
-            self.tcx.sess.span_delayed_bug(tcx.def_span(method_item.def_id), "not a method");
+            self.dcx().span_delayed_bug(tcx.def_span(method_item.def_id), "not a method");
             return None;
         }
 
@@ -401,7 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let generics = tcx.generics_of(def_id);
 
         if generics.params.len() != 0 {
-            tcx.sess.emit_fatal(OpMethodGenericParams {
+            tcx.dcx().emit_fatal(OpMethodGenericParams {
                 span: tcx.def_span(method_item.def_id),
                 method_name: m_name.to_string(),
             });
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index fe2d43a3c9244..10c31d8c641c7 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -438,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // so we do a future-compat lint here for the 2015 edition
                 // (see https://github.com/rust-lang/rust/issues/46906)
                 if self.tcx.sess.at_least_rust_2018() {
-                    self.tcx.sess.emit_err(MethodCallOnUnknownRawPointee { span });
+                    self.dcx().emit_err(MethodCallOnUnknownRawPointee { span });
                 } else {
                     self.tcx.struct_span_lint_hir(
                         lint::builtin::TYVAR_BEHIND_RAW_POINTER,
@@ -802,7 +802,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         let trait_ref = principal.with_self_ty(self.tcx, self_ty);
         self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| {
             if new_trait_ref.has_non_region_bound_vars() {
-                this.tcx.sess.span_delayed_bug(
+                this.dcx().span_delayed_bug(
                     this.span,
                     "tried to select method from HRTB with non-lifetime bound vars",
                 );
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 9327161eccb0f..6530d828b3be2 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -149,7 +149,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             MethodError::Ambiguity(mut sources) => {
                 let mut err = struct_span_err!(
-                    self.sess(),
+                    self.dcx(),
                     item_name.span,
                     E0034,
                     "multiple applicable items in scope"
@@ -172,7 +172,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             MethodError::PrivateMatch(kind, def_id, out_of_scope_traits) => {
                 let kind = self.tcx.def_kind_descr(kind, def_id);
                 let mut err = struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     item_name.span,
                     E0624,
                     "{} `{}` is private",
@@ -198,7 +198,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 } else {
                     format!("the `{item_name}` method cannot be invoked on a trait object")
                 };
-                let mut err = self.sess().struct_span_err(span, msg);
+                let mut err = self.dcx().struct_span_err(span, msg);
                 if !needs_mut {
                     err.span_label(bound_span, "this has a `Sized` requirement");
                 }
@@ -263,13 +263,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> DiagnosticBuilder<'_> {
         let mut file = None;
         let ty_str = self.tcx.short_ty_string(rcvr_ty, &mut file);
-        let mut err = struct_span_err!(
-            self.tcx.sess,
-            rcvr_expr.span,
-            E0599,
-            "cannot write into `{}`",
-            ty_str
-        );
+        let mut err =
+            struct_span_err!(self.dcx(), rcvr_expr.span, E0599, "cannot write into `{}`", ty_str);
         err.span_note(
             rcvr_expr.span,
             "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method",
@@ -381,7 +376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source {
             self.suggest_missing_writer(rcvr_ty, rcvr_expr)
         } else {
-            tcx.sess.create_err(NoAssociatedItem {
+            tcx.dcx().create_err(NoAssociatedItem {
                 span,
                 item_kind,
                 item_name,
@@ -820,7 +815,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         span: item_span,
                         ..
                     })) => {
-                        tcx.sess.span_delayed_bug(
+                        tcx.dcx().span_delayed_bug(
                             *item_span,
                             "auto trait is invoked with no method error, but no error reported?",
                         );
@@ -1783,7 +1778,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     );
                     if pick.is_ok() {
                         let range_span = parent_expr.span.with_hi(expr.span.hi());
-                        tcx.sess.emit_err(errors::MissingParenthesesInRange {
+                        tcx.dcx().emit_err(errors::MissingParenthesesInRange {
                             span,
                             ty_str: ty_str.to_string(),
                             method_name: item_name.as_str().to_string(),
@@ -1842,7 +1837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             && let SelfSource::MethodCall(expr) = source
         {
             let mut err = struct_span_err!(
-                tcx.sess,
+                tcx.dcx(),
                 span,
                 E0689,
                 "can't call {} `{}` on ambiguous numeric type `{}`",
@@ -1928,7 +1923,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         };
         let Some(mut diag) =
-            self.tcx.sess.dcx().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
+            self.dcx().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
         else {
             return;
         };
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 59b4b0032f80d..7fe5e409aa1c8 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -307,7 +307,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let (mut err, output_def_id) = match is_assign {
                     IsAssign::Yes => {
                         let mut err = struct_span_err!(
-                            self.tcx.sess,
+                            self.dcx(),
                             expr.span,
                             E0368,
                             "binary assignment operation `{}=` cannot be applied to type `{}`",
@@ -370,7 +370,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 })
                                 .cloned()
                         });
-                        let mut err = struct_span_err!(self.tcx.sess, op.span, E0369, "{message}");
+                        let mut err = struct_span_err!(self.dcx(), op.span, E0369, "{message}");
                         if !lhs_expr.span.eq(&rhs_expr.span) {
                             err.span_label(lhs_expr.span, lhs_ty.to_string());
                             err.span_label(rhs_expr.span, rhs_ty.to_string());
@@ -788,7 +788,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 let actual = self.resolve_vars_if_possible(operand_ty);
                 let guar = actual.error_reported().err().unwrap_or_else(|| {
                     let mut err = struct_span_err!(
-                        self.tcx.sess,
+                        self.dcx(),
                         ex.span,
                         E0600,
                         "cannot apply unary operator `{}` to type `{}`",
@@ -898,8 +898,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 Op::Unary(..) => 0,
             },
         ) {
-            self.tcx
-                .sess
+            self.dcx()
                 .span_delayed_bug(span, "operator didn't have the right number of generic args");
             return Err(vec![]);
         }
@@ -933,7 +932,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // This path may do some inference, so make sure we've really
                 // doomed compilation so as to not accidentally stabilize new
                 // inference or something here...
-                self.tcx.sess.span_delayed_bug(span, "this path really should be doomed...");
+                self.dcx().span_delayed_bug(span, "this path really should be doomed...");
                 // Guide inference for the RHS expression if it's provided --
                 // this will allow us to better error reporting, at the expense
                 // of making some error messages a bit more specific.
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 0c0af51cb0dfd..6deeb8bee5d2a 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -547,7 +547,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             _ => span_bug!(span, "emit_err_pat_range: no side failed or exists but still error?"),
         };
         let mut err = struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             span,
             E0029,
             "only `char` and numeric types are allowed in range patterns"
@@ -838,7 +838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
             let type_str = self.ty_to_string(expected);
             let mut err = struct_span_err!(
-                self.tcx.sess,
+                self.dcx(),
                 span,
                 E0033,
                 "type `{}` cannot be dereferenced",
@@ -899,7 +899,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let (res, opt_ty, segments) = path_resolution;
         match res {
             Res::Err => {
-                let e = tcx.sess.span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
+                let e = tcx.dcx().span_delayed_bug(qpath.span(), "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
                 return Ty::new_error(tcx, e);
             }
@@ -1068,7 +1068,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let (res, opt_ty, segments) =
             self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span, None);
         if res == Res::Err {
-            let e = tcx.sess.span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
+            let e = tcx.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
             self.set_tainted_by_errors(e);
             on_error(e);
             return Ty::new_error(tcx, e);
@@ -1084,7 +1084,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let variant = match res {
             Res::Err => {
-                let e = tcx.sess.span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
+                let e = tcx.dcx().span_delayed_bug(pat.span, "`Res::Err` but no error emitted");
                 self.set_tainted_by_errors(e);
                 on_error(e);
                 return Ty::new_error(tcx, e);
@@ -1172,7 +1172,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let last_field_def_span = *field_def_spans.last().unwrap();
 
         let mut err = struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             MultiSpan::from_spans(subpat_spans),
             E0023,
             "this pattern has {} field{}, but the corresponding {} has {} field{}",
@@ -1437,10 +1437,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Report an error if an incorrect number of fields was specified.
         if adt.is_union() {
             if fields.len() != 1 {
-                tcx.sess.emit_err(errors::UnionPatMultipleFields { span: pat.span });
+                tcx.dcx().emit_err(errors::UnionPatMultipleFields { span: pat.span });
             }
             if has_rest_pat {
-                tcx.sess.emit_err(errors::UnionPatDotDot { span: pat.span });
+                tcx.dcx().emit_err(errors::UnionPatDotDot { span: pat.span });
             }
         } else if !unmentioned_fields.is_empty() {
             let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
@@ -1519,7 +1519,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if has_shorthand_field_name {
                 let path = rustc_hir_pretty::qpath_to_string(qpath);
                 let mut err = struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     pat.span,
                     E0769,
                     "tuple variant `{path}` written as struct variant",
@@ -1544,7 +1544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let sugg = if no_fields || sp_brace != sp_comma { ".. }" } else { ", .. }" };
 
         let mut err = struct_span_err!(
-            sess,
+            self.dcx(),
             pat.span,
             E0638,
             "`..` required with {descr} marked as non-exhaustive",
@@ -1565,7 +1565,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         other_field: Span,
     ) -> ErrorGuaranteed {
         struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             span,
             E0025,
             "field `{}` bound multiple times in the pattern",
@@ -1604,7 +1604,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         };
         let spans = inexistent_fields.iter().map(|field| field.ident.span).collect::<Vec<_>>();
         let mut err = struct_span_err!(
-            tcx.sess,
+            tcx.dcx(),
             spans,
             E0026,
             "{} `{}` does not have {}",
@@ -1701,7 +1701,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
             let path = rustc_hir_pretty::qpath_to_string(qpath);
             let mut err = struct_span_err!(
-                self.tcx.sess,
+                self.dcx(),
                 pat.span,
                 E0769,
                 "tuple variant `{}` written as struct variant",
@@ -1777,8 +1777,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         fields: &'tcx [hir::PatField<'tcx>],
     ) -> DiagnosticBuilder<'tcx> {
         let mut err = self
-            .tcx
-            .sess
+            .dcx()
             .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields");
 
         if let Some(field) = fields.last() {
@@ -1880,7 +1879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             format!("fields {fields}{inaccessible}")
         };
         let mut err = struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             pat.span,
             E0027,
             "pattern does not mention {}",
@@ -2230,7 +2229,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         size: u64,
     ) -> ErrorGuaranteed {
         struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             span,
             E0527,
             "pattern requires {} element{} but array has {}",
@@ -2249,7 +2248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         size: u64,
     ) -> ErrorGuaranteed {
         struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             span,
             E0528,
             "pattern requires at least {} element{} but array has {}",
@@ -2266,7 +2265,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     fn error_scrutinee_unfixed_length(&self, span: Span) -> ErrorGuaranteed {
         struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             span,
             E0730,
             "cannot pattern-match on an array without a fixed length",
@@ -2281,7 +2280,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         ti: TopInfo<'tcx>,
     ) -> ErrorGuaranteed {
         let mut err = struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             span,
             E0529,
             "expected an array or slice, found `{expected_ty}`"
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 79e41ef922759..c3bcdcfa5cd81 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -71,7 +71,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         base_expr: &hir::Expr<'_>,
     ) -> Option<(Ty<'tcx>, Ty<'tcx>)> {
         let ty = self.resolve_vars_if_possible(ty);
-        let mut err = self.tcx.sess.struct_span_err(
+        let mut err = self.dcx().struct_span_err(
             span,
             format!("negative integers cannot be used to index on a `{ty}`"),
         );
@@ -332,7 +332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         if inside_union
                             && source.ty_adt_def().is_some_and(|adt| adt.is_manually_drop())
                         {
-                            let mut err = self.tcx.sess.struct_span_err(
+                            let mut err = self.dcx().struct_span_err(
                                 expr.span,
                                 "not automatically applying `DerefMut` on `ManuallyDrop` union field",
                             );
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 726ee02d75e3a..fc525a0fd4efd 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -714,7 +714,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 }
 
-                self.tcx.sess.span_delayed_bug(
+                self.dcx().span_delayed_bug(
                     closure_span,
                     format!(
                         "two identical projections: ({:?}, {:?})",
@@ -1501,7 +1501,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) {
         if self.should_log_capture_analysis(closure_def_id) {
             let mut diag =
-                self.tcx.sess.struct_span_err(closure_span, "First Pass analysis includes:");
+                self.dcx().struct_span_err(closure_span, "First Pass analysis includes:");
             for (place, capture_info) in capture_information {
                 let capture_str = construct_capture_info_string(self.tcx, place, capture_info);
                 let output_str = format!("Capturing {capture_str}");
@@ -1520,7 +1520,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.typeck_results.borrow().closure_min_captures.get(&closure_def_id)
             {
                 let mut diag =
-                    self.tcx.sess.struct_span_err(closure_span, "Min Capture analysis includes:");
+                    self.dcx().struct_span_err(closure_span, "Min Capture analysis includes:");
 
                 for (_, min_captures_for_var) in min_captures {
                     for capture in min_captures_for_var {
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index d0cf4575c8f68..719d85ed3dba8 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -222,7 +222,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                 // When encountering `return [0][0]` outside of a `fn` body we can encounter a base
                 // that isn't in the type table. We assume more relevant errors have already been
                 // emitted, so we delay an ICE if none have. (#64638)
-                self.tcx().sess.span_delayed_bug(e.span, format!("bad base: `{base:?}`"));
+                self.tcx().dcx().span_delayed_bug(e.span, format!("bad base: `{base:?}`"));
             }
             if let Some(base_ty) = base_ty
                 && let ty::Ref(_, base_ty_inner, _) = *base_ty.kind()
@@ -316,7 +316,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
             }
             hir::GenericParamKind::Type { .. } | hir::GenericParamKind::Const { .. } => {
                 self.tcx()
-                    .sess
+                    .dcx()
                     .span_delayed_bug(p.span, format!("unexpected generic param: {p:?}"));
             }
         }
@@ -497,7 +497,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
                     // We need to buffer the errors in order to guarantee a consistent
                     // order when emitting them.
                     let err =
-                        self.tcx().sess.struct_span_err(span, format!("user args: {user_args:?}"));
+                        self.tcx().dcx().struct_span_err(span, format!("user args: {user_args:?}"));
                     err.buffer(&mut errors_buffer);
                 }
             }
@@ -505,7 +505,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
             if !errors_buffer.is_empty() {
                 errors_buffer.sort_by_key(|diag| diag.span.primary_span());
                 for diag in errors_buffer {
-                    self.tcx().sess.dcx().emit_diagnostic(diag);
+                    self.tcx().dcx().emit_diagnostic(diag);
                 }
             }
         }
@@ -753,7 +753,7 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
     }
 
     fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed {
-        match self.fcx.tcx.sess.has_errors() {
+        match self.fcx.dcx().has_errors() {
             Some(e) => e,
             None => self
                 .fcx
diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs
index a5e0654c81df6..7b8d91702b39d 100644
--- a/compiler/rustc_incremental/src/assert_dep_graph.rs
+++ b/compiler/rustc_incremental/src/assert_dep_graph.rs
@@ -134,7 +134,7 @@ impl<'tcx> IfThisChanged<'tcx> {
                     Some(n) => {
                         match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) {
                             Ok(n) => n,
-                            Err(()) => self.tcx.sess.emit_fatal(errors::UnrecognizedDepNode {
+                            Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode {
                                 span: attr.span,
                                 name: n,
                             }),
@@ -148,14 +148,14 @@ impl<'tcx> IfThisChanged<'tcx> {
                     Some(n) => {
                         match DepNode::from_label_string(self.tcx, n.as_str(), def_path_hash) {
                             Ok(n) => n,
-                            Err(()) => self.tcx.sess.emit_fatal(errors::UnrecognizedDepNode {
+                            Err(()) => self.tcx.dcx().emit_fatal(errors::UnrecognizedDepNode {
                                 span: attr.span,
                                 name: n,
                             }),
                         }
                     }
                     None => {
-                        self.tcx.sess.emit_fatal(errors::MissingDepNode { span: attr.span });
+                        self.tcx.dcx().emit_fatal(errors::MissingDepNode { span: attr.span });
                     }
                 };
                 self.then_this_would_need.push((
@@ -201,7 +201,7 @@ fn check_paths<'tcx>(tcx: TyCtxt<'tcx>, if_this_changed: &Sources, then_this_wou
     // Return early here so as not to construct the query, which is not cheap.
     if if_this_changed.is_empty() {
         for &(target_span, _, _, _) in then_this_would_need {
-            tcx.sess.emit_err(errors::MissingIfThisChanged { span: target_span });
+            tcx.dcx().emit_err(errors::MissingIfThisChanged { span: target_span });
         }
         return;
     }
@@ -210,13 +210,13 @@ fn check_paths<'tcx>(tcx: TyCtxt<'tcx>, if_this_changed: &Sources, then_this_wou
             let dependents = query.transitive_predecessors(source_dep_node);
             for &(target_span, ref target_pass, _, ref target_dep_node) in then_this_would_need {
                 if !dependents.contains(&target_dep_node) {
-                    tcx.sess.emit_err(errors::NoPath {
+                    tcx.dcx().emit_err(errors::NoPath {
                         span: target_span,
                         source: tcx.def_path_str(source_def_id),
                         target: *target_pass,
                     });
                 } else {
-                    tcx.sess.emit_err(errors::Ok { span: target_span });
+                    tcx.dcx().emit_err(errors::Ok { span: target_span });
                 }
             }
         }
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 8a7b97139ea0f..f6acc60190a8f 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -199,7 +199,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
         let loaded_from_disk = self.loaded_from_disk(attr);
         for e in except.items().into_sorted_stable_ord() {
             if !auto.remove(e) {
-                self.tcx.sess.emit_fatal(errors::AssertionAuto { span: attr.span, name, e });
+                self.tcx.dcx().emit_fatal(errors::AssertionAuto { span: attr.span, name, e });
             }
         }
         Assertion { clean: auto, dirty: except, loaded_from_disk }
@@ -281,7 +281,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
                     // An implementation, eg `impl<A> Trait for Foo { .. }`
                     HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL),
 
-                    _ => self.tcx.sess.emit_fatal(errors::UndefinedCleanDirtyItem {
+                    _ => self.tcx.dcx().emit_fatal(errors::UndefinedCleanDirtyItem {
                         span: attr.span,
                         kind: format!("{:?}", item.kind),
                     }),
@@ -297,7 +297,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
                 ImplItemKind::Const(..) => ("NodeImplConst", LABELS_CONST_IN_IMPL),
                 ImplItemKind::Type(..) => ("NodeImplType", LABELS_CONST_IN_IMPL),
             },
-            _ => self.tcx.sess.emit_fatal(errors::UndefinedCleanDirty {
+            _ => self.tcx.dcx().emit_fatal(errors::UndefinedCleanDirty {
                 span: attr.span,
                 kind: format!("{node:?}"),
             }),
@@ -314,13 +314,13 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
             if DepNode::has_label_string(label) {
                 if out.contains(label) {
                     self.tcx
-                        .sess
+                        .dcx()
                         .emit_fatal(errors::RepeatedDepNodeLabel { span: item.span(), label });
                 }
                 out.insert(label.to_string());
             } else {
                 self.tcx
-                    .sess
+                    .dcx()
                     .emit_fatal(errors::UnrecognizedDepNodeLabel { span: item.span(), label });
             }
         }
@@ -341,7 +341,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
         if self.tcx.dep_graph.is_green(&dep_node) {
             let dep_node_str = self.dep_node_str(&dep_node);
             self.tcx
-                .sess
+                .dcx()
                 .emit_err(errors::NotDirty { span: item_span, dep_node_str: &dep_node_str });
         }
     }
@@ -352,7 +352,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
         if self.tcx.dep_graph.is_red(&dep_node) {
             let dep_node_str = self.dep_node_str(&dep_node);
             self.tcx
-                .sess
+                .dcx()
                 .emit_err(errors::NotClean { span: item_span, dep_node_str: &dep_node_str });
         }
     }
@@ -363,7 +363,7 @@ impl<'tcx> DirtyCleanVisitor<'tcx> {
         if !self.tcx.dep_graph.debug_was_loaded_from_disk(dep_node) {
             let dep_node_str = self.dep_node_str(&dep_node);
             self.tcx
-                .sess
+                .dcx()
                 .emit_err(errors::NotLoaded { span: item_span, dep_node_str: &dep_node_str });
         }
     }
@@ -405,12 +405,12 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
             debug!("check_config: searching for cfg {:?}", value);
             cfg = Some(config.contains(&(value, None)));
         } else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) {
-            tcx.sess.emit_err(errors::UnknownItem { span: attr.span, name: item.name_or_empty() });
+            tcx.dcx().emit_err(errors::UnknownItem { span: attr.span, name: item.name_or_empty() });
         }
     }
 
     match cfg {
-        None => tcx.sess.emit_fatal(errors::NoCfg { span: attr.span }),
+        None => tcx.dcx().emit_fatal(errors::NoCfg { span: attr.span }),
         Some(c) => c,
     }
 }
@@ -420,9 +420,9 @@ fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol {
         value
     } else {
         if let Some(ident) = item.ident() {
-            tcx.sess.emit_fatal(errors::AssociatedValueExpectedFor { span: item.span(), ident });
+            tcx.dcx().emit_fatal(errors::AssociatedValueExpectedFor { span: item.span(), ident });
         } else {
-            tcx.sess.emit_fatal(errors::AssociatedValueExpected { span: item.span() });
+            tcx.dcx().emit_fatal(errors::AssociatedValueExpected { span: item.span() });
         }
     }
 }
@@ -447,7 +447,7 @@ impl<'tcx> FindAllAttrs<'tcx> {
     fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet<ast::AttrId>) {
         for attr in &self.found_attrs {
             if !checked_attrs.contains(&attr.id) {
-                self.tcx.sess.emit_err(errors::UncheckedClean { span: attr.span });
+                self.tcx.dcx().emit_err(errors::UncheckedClean { span: attr.span });
                 checked_attrs.insert(attr.id);
             }
         }
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index b5742b97d0242..e68195acee097 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -56,7 +56,7 @@ where
         }
         Err(err) if err.kind() == io::ErrorKind::NotFound => (),
         Err(err) => {
-            sess.emit_err(errors::DeleteOld { name, path: path_buf, err });
+            sess.dcx().emit_err(errors::DeleteOld { name, path: path_buf, err });
             return;
         }
     }
@@ -64,7 +64,7 @@ where
     let mut encoder = match FileEncoder::new(&path_buf) {
         Ok(encoder) => encoder,
         Err(err) => {
-            sess.emit_err(errors::CreateNew { name, path: path_buf, err });
+            sess.dcx().emit_err(errors::CreateNew { name, path: path_buf, err });
             return;
         }
     };
@@ -81,7 +81,7 @@ where
             debug!("save: data written to disk successfully");
         }
         Err((path, err)) => {
-            sess.emit_err(errors::WriteNew { name, path, err });
+            sess.dcx().emit_err(errors::WriteNew { name, path, err });
         }
     }
 }
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index 92297a27a63ef..2c6ae91786d10 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -230,7 +230,7 @@ pub(crate) fn prepare_session_directory(
     let crate_dir = match try_canonicalize(&crate_dir) {
         Ok(v) => v,
         Err(err) => {
-            return Err(sess.emit_err(errors::CanonicalizePath { path: crate_dir, err }));
+            return Err(sess.dcx().emit_err(errors::CanonicalizePath { path: crate_dir, err }));
         }
     };
 
@@ -273,7 +273,7 @@ pub(crate) fn prepare_session_directory(
             debug!("successfully copied data from: {}", source_directory.display());
 
             if !allows_links {
-                sess.emit_warning(errors::HardLinkFailed { path: &session_dir });
+                sess.dcx().emit_warning(errors::HardLinkFailed { path: &session_dir });
             }
 
             sess.init_incr_comp_session(session_dir, directory_lock);
@@ -288,7 +288,7 @@ pub(crate) fn prepare_session_directory(
             // Try to remove the session directory we just allocated. We don't
             // know if there's any garbage in it from the failed copy action.
             if let Err(err) = safe_remove_dir_all(&session_dir) {
-                sess.emit_warning(errors::DeletePartial { path: &session_dir, err });
+                sess.dcx().emit_warning(errors::DeletePartial { path: &session_dir, err });
             }
 
             delete_session_dir_lock_file(sess, &lock_file_path);
@@ -312,7 +312,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) {
 
     let incr_comp_session_dir: PathBuf = sess.incr_comp_session_dir().clone();
 
-    if let Some(_) = sess.has_errors_or_span_delayed_bugs() {
+    if let Some(_) = sess.dcx().has_errors_or_span_delayed_bugs() {
         // If there have been any errors during compilation, we don't want to
         // publish this session directory. Rather, we'll just delete it.
 
@@ -322,7 +322,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) {
         );
 
         if let Err(err) = safe_remove_dir_all(&*incr_comp_session_dir) {
-            sess.emit_warning(errors::DeleteFull { path: &incr_comp_session_dir, err });
+            sess.dcx().emit_warning(errors::DeleteFull { path: &incr_comp_session_dir, err });
         }
 
         let lock_file_path = lock_file_path(&*incr_comp_session_dir);
@@ -365,7 +365,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) {
         }
         Err(e) => {
             // Warn about the error. However, no need to abort compilation now.
-            sess.emit_warning(errors::Finalize { path: &incr_comp_session_dir, err: e });
+            sess.dcx().emit_warning(errors::Finalize { path: &incr_comp_session_dir, err: e });
 
             debug!("finalize_session_directory() - error, marking as invalid");
             // Drop the file lock, so we can garage collect
@@ -466,7 +466,7 @@ fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ErrorGua
             debug!("{} directory created successfully", dir_tag);
             Ok(())
         }
-        Err(err) => Err(sess.emit_err(errors::CreateIncrCompDir { tag: dir_tag, path, err })),
+        Err(err) => Err(sess.dcx().emit_err(errors::CreateIncrCompDir { tag: dir_tag, path, err })),
     }
 }
 
@@ -488,7 +488,7 @@ fn lock_directory(
         Ok(lock) => Ok((lock, lock_file_path)),
         Err(lock_err) => {
             let is_unsupported_lock = flock::Lock::error_unsupported(&lock_err).then_some(());
-            Err(sess.emit_err(errors::CreateLock {
+            Err(sess.dcx().emit_err(errors::CreateLock {
                 lock_err,
                 session_dir,
                 is_unsupported_lock,
@@ -500,7 +500,7 @@ fn lock_directory(
 
 fn delete_session_dir_lock_file(sess: &Session, lock_file_path: &Path) {
     if let Err(err) = safe_remove_file(lock_file_path) {
-        sess.emit_warning(errors::DeleteLock { path: lock_file_path, err });
+        sess.dcx().emit_warning(errors::DeleteLock { path: lock_file_path, err });
     }
 }
 
@@ -724,7 +724,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result<
         if !lock_file_to_session_dir.items().any(|(_, dir)| *dir == directory_name) {
             let path = crate_directory.join(directory_name);
             if let Err(err) = safe_remove_dir_all(&path) {
-                sess.emit_warning(errors::InvalidGcFailed { path: &path, err });
+                sess.dcx().emit_warning(errors::InvalidGcFailed { path: &path, err });
             }
         }
     }
@@ -830,7 +830,7 @@ pub(crate) fn garbage_collect_session_directories(sess: &Session) -> io::Result<
         debug!("garbage_collect_session_directories() - deleting `{}`", path.display());
 
         if let Err(err) = safe_remove_dir_all(&path) {
-            sess.emit_warning(errors::FinalizedGcFailed { path: &path, err });
+            sess.dcx().emit_warning(errors::FinalizedGcFailed { path: &path, err });
         } else {
             delete_session_dir_lock_file(sess, &lock_file_path(&path));
         }
@@ -848,7 +848,7 @@ fn delete_old(sess: &Session, path: &Path) {
     debug!("garbage_collect_session_directories() - deleting `{}`", path.display());
 
     if let Err(err) = safe_remove_dir_all(path) {
-        sess.emit_warning(errors::SessionGcFailed { path: path, err });
+        sess.dcx().emit_warning(errors::SessionGcFailed { path: path, err });
     } else {
         delete_session_dir_lock_file(sess, &lock_file_path(path));
     }
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index f2c1d0b83aac3..ce8f5bb69ae3b 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -38,25 +38,26 @@ impl<T: Default> LoadResult<T> {
         // Check for errors when using `-Zassert-incremental-state`
         match (sess.opts.assert_incr_state, &self) {
             (Some(IncrementalStateAssertion::NotLoaded), LoadResult::Ok { .. }) => {
-                sess.emit_fatal(errors::AssertNotLoaded);
+                sess.dcx().emit_fatal(errors::AssertNotLoaded);
             }
             (
                 Some(IncrementalStateAssertion::Loaded),
                 LoadResult::LoadDepGraph(..) | LoadResult::DataOutOfDate,
             ) => {
-                sess.emit_fatal(errors::AssertLoaded);
+                sess.dcx().emit_fatal(errors::AssertLoaded);
             }
             _ => {}
         };
 
         match self {
             LoadResult::LoadDepGraph(path, err) => {
-                sess.emit_warning(errors::LoadDepGraph { path, err });
+                sess.dcx().emit_warning(errors::LoadDepGraph { path, err });
                 Default::default()
             }
             LoadResult::DataOutOfDate => {
                 if let Err(err) = delete_all_session_dir_contents(sess) {
-                    sess.emit_err(errors::DeleteIncompatible { path: dep_graph_path(sess), err });
+                    sess.dcx()
+                        .emit_err(errors::DeleteIncompatible { path: dep_graph_path(sess), err });
                 }
                 Default::default()
             }
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index ff0953e9f7b44..bdc935a5e3b6f 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -32,7 +32,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
             return;
         }
         // This is going to be deleted in finalize_session_directory, so let's not create it
-        if let Some(_) = sess.has_errors_or_span_delayed_bugs() {
+        if let Some(_) = sess.dcx().has_errors_or_span_delayed_bugs() {
             return;
         }
 
@@ -51,7 +51,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
             move || {
                 sess.time("incr_comp_persist_dep_graph", || {
                     if let Err(err) = fs::rename(&staging_dep_graph_path, &dep_graph_path) {
-                        sess.emit_err(errors::MoveDepGraph {
+                        sess.dcx().emit_err(errors::MoveDepGraph {
                             from: &staging_dep_graph_path,
                             to: &dep_graph_path,
                             err,
@@ -87,7 +87,7 @@ pub fn save_work_product_index(
         return;
     }
     // This is going to be deleted in finalize_session_directory, so let's not create it
-    if let Some(_) = sess.has_errors_or_span_delayed_bugs() {
+    if let Some(_) = sess.dcx().has_errors_or_span_delayed_bugs() {
         return;
     }
 
@@ -161,7 +161,7 @@ pub(crate) fn build_dep_graph(
     let mut encoder = match FileEncoder::new(&path_buf) {
         Ok(encoder) => encoder,
         Err(err) => {
-            sess.emit_err(errors::CreateDepGraph { path: &path_buf, err });
+            sess.dcx().emit_err(errors::CreateDepGraph { path: &path_buf, err });
             return None;
         }
     };
diff --git a/compiler/rustc_incremental/src/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs
index 1ee3d13922b40..1450d8a99abbc 100644
--- a/compiler/rustc_incremental/src/persist/work_product.rs
+++ b/compiler/rustc_incremental/src/persist/work_product.rs
@@ -30,7 +30,7 @@ pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
                 let _ = saved_files.insert(ext.to_string(), file_name);
             }
             Err(err) => {
-                sess.emit_warning(errors::CopyWorkProductToCache {
+                sess.dcx().emit_warning(errors::CopyWorkProductToCache {
                     from: path,
                     to: &path_in_incr_dir,
                     err,
@@ -50,7 +50,7 @@ pub(crate) fn delete_workproduct_files(sess: &Session, work_product: &WorkProduc
     for (_, path) in work_product.saved_files.items().into_sorted_stable_ord() {
         let path = in_incr_comp_dir_sess(sess, path);
         if let Err(err) = std_fs::remove_file(&path) {
-            sess.emit_warning(errors::DeleteWorkProduct { path: &path, err });
+            sess.dcx().emit_warning(errors::DeleteWorkProduct { path: &path, err });
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 5b00ef42211e8..69a9644846784 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -221,7 +221,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
                 // rust-lang/rust#57464: `impl Trait` can leak local
                 // scopes (in manner violating typeck). Therefore, use
                 // `span_delayed_bug` to allow type error over an ICE.
-                canonicalizer.tcx.sess.span_delayed_bug(
+                canonicalizer.tcx.dcx().span_delayed_bug(
                     rustc_span::DUMMY_SP,
                     format!("unexpected region in query response: `{r:?}`"),
                 );
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index d77c224f3c86a..0c0292f329ef6 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -59,8 +59,10 @@ use crate::traits::{
 };
 
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
-use rustc_errors::{error_code, Applicability, DiagnosticBuilder, DiagnosticStyledString};
-use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed, IntoDiagnosticArg};
+use rustc_errors::{
+    error_code, pluralize, struct_span_err, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder,
+    DiagnosticStyledString, ErrorGuaranteed, IntoDiagnosticArg,
+};
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -131,7 +133,7 @@ pub struct TypeErrCtxt<'a, 'tcx> {
 
 impl Drop for TypeErrCtxt<'_, '_> {
     fn drop(&mut self) {
-        if let Some(_) = self.infcx.tcx.sess.has_errors_or_span_delayed_bugs() {
+        if let Some(_) = self.dcx().has_errors_or_span_delayed_bugs() {
             // ok, emitted an error.
         } else {
             self.infcx
@@ -142,7 +144,11 @@ impl Drop for TypeErrCtxt<'_, '_> {
     }
 }
 
-impl TypeErrCtxt<'_, '_> {
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
+    pub fn dcx(&self) -> &'tcx DiagCtxt {
+        self.infcx.tcx.dcx()
+    }
+
     /// This is just to avoid a potential footgun of accidentally
     /// dropping `typeck_results` by calling `InferCtxt::err_ctxt`
     #[deprecated(note = "you already have a `TypeErrCtxt`")]
@@ -307,7 +313,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
     hidden_region: ty::Region<'tcx>,
     opaque_ty_key: ty::OpaqueTypeKey<'tcx>,
 ) -> DiagnosticBuilder<'tcx> {
-    let mut err = tcx.sess.create_err(errors::OpaqueCapturesLifetime {
+    let mut err = tcx.dcx().create_err(errors::OpaqueCapturesLifetime {
         span,
         opaque_ty: Ty::new_opaque(tcx, opaque_ty_key.def_id.to_def_id(), opaque_ty_key.args),
         opaque_ty_span: tcx.def_span(opaque_ty_key.def_id),
@@ -516,7 +522,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
 
         self.tcx
-            .sess
+            .dcx()
             .span_delayed_bug(self.tcx.def_span(generic_param_scope), "expected region errors")
     }
 
@@ -2180,7 +2186,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             span,
             self.type_error_additional_suggestions(&trace, terr),
         );
-        let mut diag = self.tcx.sess.create_err(failure_code);
+        let mut diag = self.tcx.dcx().create_err(failure_code);
         self.note_type_err(&mut diag, &trace.cause, None, Some(trace.values), terr, false, false);
         diag
     }
@@ -2346,7 +2352,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             },
         };
 
-        let mut err = self.tcx.sess.struct_span_err_with_code(
+        let mut err = self.tcx.dcx().struct_span_err_with_code(
             span,
             format!("{labeled_user_string} may not live long enough"),
             match sub.kind() {
@@ -2771,7 +2777,7 @@ impl<'tcx> InferCtxt<'tcx> {
         };
 
         struct_span_err!(
-            self.tcx.sess,
+            self.tcx.dcx(),
             var_origin.span(),
             E0495,
             "cannot infer an appropriate lifetime{} due to conflicting requirements",
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index fd38e52cfde1f..4aefadf590dd4 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -366,7 +366,7 @@ impl<'tcx> InferCtxt<'tcx> {
         let multi_suggestions = Vec::new();
         let bad_label = Some(arg_data.make_bad_error(span));
         match error_code {
-            TypeAnnotationNeeded::E0282 => self.tcx.sess.dcx().create_err(AnnotationRequired {
+            TypeAnnotationNeeded::E0282 => self.dcx().create_err(AnnotationRequired {
                 span,
                 source_kind,
                 source_name,
@@ -375,7 +375,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 multi_suggestions,
                 bad_label,
             }),
-            TypeAnnotationNeeded::E0283 => self.tcx.sess.dcx().create_err(AmbiguousImpl {
+            TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl {
                 span,
                 source_kind,
                 source_name,
@@ -384,7 +384,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 multi_suggestions,
                 bad_label,
             }),
-            TypeAnnotationNeeded::E0284 => self.tcx.sess.dcx().create_err(AmbiguousReturn {
+            TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn {
                 span,
                 source_kind,
                 source_name,
@@ -570,7 +570,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
         }
         match error_code {
-            TypeAnnotationNeeded::E0282 => self.tcx.sess.dcx().create_err(AnnotationRequired {
+            TypeAnnotationNeeded::E0282 => self.dcx().create_err(AnnotationRequired {
                 span,
                 source_kind,
                 source_name: &name,
@@ -579,7 +579,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 multi_suggestions,
                 bad_label: None,
             }),
-            TypeAnnotationNeeded::E0283 => self.tcx.sess.dcx().create_err(AmbiguousImpl {
+            TypeAnnotationNeeded::E0283 => self.dcx().create_err(AmbiguousImpl {
                 span,
                 source_kind,
                 source_name: &name,
@@ -588,7 +588,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 multi_suggestions,
                 bad_label: None,
             }),
-            TypeAnnotationNeeded::E0284 => self.tcx.sess.dcx().create_err(AmbiguousReturn {
+            TypeAnnotationNeeded::E0284 => self.dcx().create_err(AmbiguousReturn {
                 span,
                 source_kind,
                 source_name: &name,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index f56d5d7d345b2..adb3267d5bee7 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -130,7 +130,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let suggestion =
             AddLifetimeParamsSuggestion { tcx: self.tcx(), sub, ty_sup, ty_sub, add_note: true };
         let err = LifetimeMismatch { span, labels, suggestion };
-        let reported = self.tcx().sess.emit_err(err);
+        let reported = self.tcx().dcx().emit_err(err);
         Some(reported)
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index df7907e1fd3af..b93b8dc03f8a4 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -116,7 +116,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 .unwrap_or(DoesNotOutliveStaticFromImpl::Unspanned),
             implicit_static_lifetimes,
         };
-        let reported = self.tcx().sess.emit_err(err);
+        let reported = self.tcx().dcx().emit_err(err);
         Some(reported)
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index a5a69b77a050a..ee892326dedfe 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -88,6 +88,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             },
             None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty },
         };
-        Some(self.tcx().sess.parse_sess.create_err(err))
+        Some(self.tcx().sess.dcx().create_err(err))
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index 45affb538a31a..e1a83c86318e9 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -331,7 +331,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
             leading_ellipsis,
         );
 
-        self.tcx().sess.create_err(TraitPlaceholderMismatch {
+        self.tcx().dcx().create_err(TraitPlaceholderMismatch {
             span,
             satisfy_span,
             where_span,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
index 51b65a9dd2d0e..e1dbf36607481 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_relation.rs
@@ -81,7 +81,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
                     }
                     _ => PlaceholderRelationLfNotSatisfied::OnlyPrimarySpan { span, note: () },
                 };
-                Some(self.tcx().sess.create_err(diag))
+                Some(self.tcx().dcx().create_err(diag))
             }
             _ => None,
         }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 01b43f7197d05..a7d1c2ca66695 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -67,7 +67,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                         AssocItemContainer::ImplContainer => (false, String::new()),
                     };
 
-                    let mut err = self.tcx().sess.create_err(ButCallingIntroduces {
+                    let mut err = self.tcx().dcx().create_err(ButCallingIntroduces {
                         param_ty_span: param.param_ty_span,
                         cause_span: cause.span,
                         has_param_name: simple_ident.is_some(),
@@ -195,7 +195,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             bound,
         };
 
-        let mut err = self.tcx().sess.create_err(diag);
+        let mut err = self.tcx().dcx().create_err(diag);
 
         let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index b16d5c509e00c..ded628fe13663 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -121,7 +121,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             found,
         };
 
-        self.tcx().sess.emit_err(diag)
+        self.tcx().dcx().emit_err(diag)
     }
 }
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 73139d8e72084..ae30cf53c71e1 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -134,7 +134,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     note_and_explain::PrefixKind::ContentValidFor,
                     note_and_explain::SuffixKind::Empty,
                 );
-                self.tcx.sess.dcx().create_err(OutlivesContent {
+                self.dcx().create_err(OutlivesContent {
                     span,
                     notes: reference_valid.into_iter().chain(content_valid).collect(),
                 })
@@ -154,7 +154,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     note_and_explain::PrefixKind::SourcePointerValidFor,
                     note_and_explain::SuffixKind::Empty,
                 );
-                self.tcx.sess.dcx().create_err(OutlivesBound {
+                self.dcx().create_err(OutlivesBound {
                     span,
                     notes: object_valid.into_iter().chain(pointer_valid).collect(),
                 })
@@ -172,7 +172,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 let note = note_and_explain::RegionExplanation::new(
                     self.tcx, sub, opt_span, prefix, suffix,
                 );
-                self.tcx.sess.dcx().create_err(FulfillReqLifetime {
+                self.dcx().create_err(FulfillReqLifetime {
                     span,
                     ty: self.resolve_vars_if_possible(ty),
                     note,
@@ -193,7 +193,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     note_and_explain::PrefixKind::LfParamMustOutlive,
                     note_and_explain::SuffixKind::Empty,
                 );
-                self.tcx.sess.dcx().create_err(LfBoundNotSatisfied {
+                self.dcx().create_err(LfBoundNotSatisfied {
                     span,
                     notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
                 })
@@ -213,7 +213,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     note_and_explain::PrefixKind::DataValidFor,
                     note_and_explain::SuffixKind::Empty,
                 );
-                self.tcx.sess.dcx().create_err(RefLongerThanData {
+                self.dcx().create_err(RefLongerThanData {
                     span,
                     ty: self.resolve_vars_if_possible(ty),
                     notes: pointer_valid.into_iter().chain(data_valid).collect(),
@@ -274,7 +274,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     note_and_explain::PrefixKind::LfMustOutlive,
                     note_and_explain::SuffixKind::Empty,
                 );
-                self.tcx.sess.dcx().create_err(LfBoundNotSatisfied {
+                self.dcx().create_err(LfBoundNotSatisfied {
                     span,
                     notes: instantiated.into_iter().chain(must_outlive).collect(),
                 })
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 76d4dc24dce32..0562c6ccfcf75 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -800,7 +800,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
 
         // Errors in earlier passes can yield error variables without
         // resolution errors here; delay ICE in favor of those errors.
-        self.tcx().sess.span_delayed_bug(
+        self.tcx().dcx().span_delayed_bug(
             self.var_infos[node_idx].origin.span(),
             format!(
                 "collect_error_for_expanding_node() could not find \
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index a36735b7600f2..fa694f09f178d 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -20,7 +20,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::undo_log::Rollback;
 use rustc_data_structures::unify as ut;
-use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{DiagCtxt, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue, EffectVarValue};
@@ -704,7 +704,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
             reported_trait_errors: Default::default(),
             reported_closure_mismatch: Default::default(),
             tainted_by_errors: Cell::new(None),
-            err_count_on_creation: tcx.sess.err_count(),
+            err_count_on_creation: tcx.dcx().err_count(),
             universe: Cell::new(ty::UniverseIndex::ROOT),
             intercrate,
             next_trait_solver,
@@ -739,6 +739,10 @@ pub struct CombinedSnapshot<'tcx> {
 }
 
 impl<'tcx> InferCtxt<'tcx> {
+    pub fn dcx(&self) -> &'tcx DiagCtxt {
+        self.tcx.dcx()
+    }
+
     pub fn next_trait_solver(&self) -> bool {
         self.next_trait_solver
     }
@@ -1258,7 +1262,7 @@ impl<'tcx> InferCtxt<'tcx> {
         debug!(
             "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \
              tainted_by_errors={})",
-            self.tcx.sess.err_count(),
+            self.dcx().err_count(),
             self.err_count_on_creation,
             self.tainted_by_errors.get().is_some()
         );
@@ -1267,9 +1271,9 @@ impl<'tcx> InferCtxt<'tcx> {
             return Some(e);
         }
 
-        if self.tcx.sess.err_count() > self.err_count_on_creation {
+        if self.dcx().err_count() > self.err_count_on_creation {
             // errors reported since this infcx was made
-            let e = self.tcx.sess.has_errors().unwrap();
+            let e = self.dcx().has_errors().unwrap();
             self.set_tainted_by_errors(e);
             return Some(e);
         }
@@ -1432,7 +1436,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 if value.has_infer_regions() {
                     let guar = self
                         .tcx
-                        .sess
+                        .dcx()
                         .span_delayed_bug(DUMMY_SP, format!("`{value:?}` is not fully resolved"));
                     Ok(self.tcx.fold_regions(value, |re, _| {
                         if re.is_var() { ty::Region::new_error(self.tcx, guar) } else { re }
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index a492c6bf9bb4f..2656fd529cde6 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -157,7 +157,7 @@ impl<'tcx> InferCtxt<'tcx> {
                     if let Some(OpaqueTyOrigin::TyAlias { .. }) =
                         b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id))
                     {
-                        self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
+                        self.tcx.dcx().emit_err(OpaqueHiddenTypeDiag {
                             span: cause.span,
                             hidden_type: self.tcx.def_span(b_def_id),
                             opaque_type: self.tcx.def_span(def_id),
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index 715006a50d3da..c91eb7eddd846 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -41,7 +41,7 @@ impl<'tcx> Drop for OpaqueTypeStorage<'tcx> {
     fn drop(&mut self) {
         if !self.opaque_types.is_empty() {
             ty::tls::with(|tcx| {
-                tcx.sess.span_delayed_bug(DUMMY_SP, format!("{:?}", self.opaque_types))
+                tcx.dcx().span_delayed_bug(DUMMY_SP, format!("{:?}", self.opaque_types))
             });
         }
     }
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index 395830d937b80..d7a3bfcbc41b6 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -254,7 +254,7 @@ where
                     // ignore this, we presume it will yield an error
                     // later, since if a type variable is not resolved by
                     // this point it never will be
-                    self.tcx.sess.span_delayed_bug(
+                    self.tcx.dcx().span_delayed_bug(
                         origin.span(),
                         format!("unresolved inference variable in outlives: {v:?}"),
                     );
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 90282f58e94fa..dd364312cade2 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -175,7 +175,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
                 // ignore this, we presume it will yield an error
                 // later, since if a type variable is not resolved by
                 // this point it never will be
-                self.tcx.sess.span_delayed_bug(
+                self.tcx.dcx().span_delayed_bug(
                     rustc_span::DUMMY_SP,
                     format!("unresolved inference variable in outlives: {v:?}"),
                 );
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index ee911c43284aa..6d8384e7a4791 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -180,7 +180,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 &mut OriginalQueryValues::default(),
             );
             self.tcx.check_tys_might_be_eq(canonical).map_err(|_| {
-                self.tcx.sess.span_delayed_bug(
+                self.tcx.dcx().span_delayed_bug(
                     DUMMY_SP,
                     format!("cannot relate consts of different types (a={a:?}, b={b:?})",),
                 )
diff --git a/compiler/rustc_infer/src/infer/relate/nll.rs b/compiler/rustc_infer/src/infer/relate/nll.rs
index 1ef865cfc5f8b..8b80646a386c8 100644
--- a/compiler/rustc_infer/src/infer/relate/nll.rs
+++ b/compiler/rustc_infer/src/infer/relate/nll.rs
@@ -496,7 +496,7 @@ where
                     // shouldn't ever fail. Instead, it unconditionally emits an
                     // alias-relate goal.
                     assert!(!self.infcx.next_trait_solver());
-                    self.tcx().sess.span_delayed_bug(
+                    self.tcx().dcx().span_delayed_bug(
                         self.delegate.span(),
                         "failure to relate an opaque to itself should result in an error later on",
                     );
@@ -554,7 +554,7 @@ where
         match b.kind() {
             ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
                 // Forbid inference variables in the RHS.
-                self.infcx.tcx.sess.span_delayed_bug(
+                self.infcx.dcx().span_delayed_bug(
                     self.delegate.span(),
                     format!("unexpected inference var {b:?}",),
                 );
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index 99fb4b33f249e..d89c205da3f52 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -20,7 +20,7 @@ impl<'tcx> InferCtxt<'tcx> {
         requirement: &dyn fmt::Display,
     ) -> DiagnosticBuilder<'tcx> {
         let mut err = struct_span_err!(
-            self.tcx.sess,
+            self.tcx.dcx(),
             error_span,
             E0276,
             "impl has stricter requirements than trait"
@@ -51,7 +51,7 @@ pub fn report_object_safety_error<'tcx>(
         _ => None,
     });
     let mut err = struct_span_err!(
-        tcx.sess,
+        tcx.dcx(),
         span,
         E0038,
         "the trait `{}` cannot be made into an object",
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 21beb90d73f75..559874641c3d5 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -216,7 +216,7 @@ fn configure_and_expand(
         // If we hit a recursion limit, exit early to avoid later passes getting overwhelmed
         // with a large AST
         if ecx.reduced_recursion_limit.is_some() {
-            sess.abort_if_errors();
+            sess.dcx().abort_if_errors();
             unreachable!();
         }
 
@@ -246,15 +246,15 @@ fn configure_and_expand(
 
     if crate_types.len() > 1 {
         if is_executable_crate {
-            sess.emit_err(errors::MixedBinCrate);
+            sess.dcx().emit_err(errors::MixedBinCrate);
         }
         if is_proc_macro_crate {
-            sess.emit_err(errors::MixedProcMacroCrate);
+            sess.dcx().emit_err(errors::MixedProcMacroCrate);
         }
     }
 
     if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
-        sess.emit_warning(errors::ProcMacroCratePanicAbort);
+        sess.dcx().emit_warning(errors::ProcMacroCratePanicAbort);
     }
 
     sess.time("maybe_create_a_macro_crate", || {
@@ -314,9 +314,9 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
             spans.sort();
             if ident == sym::ferris {
                 let first_span = spans[0];
-                sess.emit_err(errors::FerrisIdentifier { spans, first_span });
+                sess.dcx().emit_err(errors::FerrisIdentifier { spans, first_span });
             } else {
-                sess.emit_err(errors::EmojiIdentifier { spans, ident });
+                sess.dcx().emit_err(errors::EmojiIdentifier { spans, ident });
             }
         }
     });
@@ -530,7 +530,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
             }
         }
         Err(error) => {
-            sess.emit_fatal(errors::ErrorWritingDependencies { path: deps_filename, error });
+            sess.dcx().emit_fatal(errors::ErrorWritingDependencies { path: deps_filename, error });
         }
     }
 }
@@ -576,10 +576,10 @@ pub(crate) fn write_dep_info(tcx: TyCtxt<'_>) {
     if let Some(input_path) = sess.io.input.opt_path() {
         if sess.opts.will_create_output_file() {
             if output_contains_path(&output_paths, input_path) {
-                sess.emit_fatal(errors::InputFileWouldBeOverWritten { path: input_path });
+                sess.dcx().emit_fatal(errors::InputFileWouldBeOverWritten { path: input_path });
             }
             if let Some(dir_path) = output_conflicts_with_dir(&output_paths) {
-                sess.emit_fatal(errors::GeneratedFileConflictsWithDirectory {
+                sess.dcx().emit_fatal(errors::GeneratedFileConflictsWithDirectory {
                     input_path,
                     dir_path,
                 });
@@ -589,7 +589,7 @@ pub(crate) fn write_dep_info(tcx: TyCtxt<'_>) {
 
     if let Some(ref dir) = sess.io.temps_dir {
         if fs::create_dir_all(dir).is_err() {
-            sess.emit_fatal(errors::TempsDirError);
+            sess.dcx().emit_fatal(errors::TempsDirError);
         }
     }
 
@@ -601,7 +601,7 @@ pub(crate) fn write_dep_info(tcx: TyCtxt<'_>) {
     if !only_dep_info {
         if let Some(ref dir) = sess.io.output_dir {
             if fs::create_dir_all(dir).is_err() {
-                sess.emit_fatal(errors::OutDirError);
+                sess.dcx().emit_fatal(errors::OutDirError);
             }
         }
     }
@@ -776,7 +776,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
     // lot of annoying errors in the ui tests (basically,
     // lint warnings and so on -- kindck used to do this abort, but
     // kindck is gone now). -nmatsakis
-    if let Some(reported) = sess.has_errors() {
+    if let Some(reported) = sess.dcx().has_errors() {
         return Err(reported);
     }
 
@@ -937,8 +937,9 @@ pub fn start_codegen<'tcx>(
 
     if tcx.sess.opts.output_types.contains_key(&OutputType::Mir) {
         if let Err(error) = rustc_mir_transform::dump_mir::emit_mir(tcx) {
-            tcx.sess.emit_err(errors::CantEmitMIR { error });
-            tcx.sess.abort_if_errors();
+            let dcx = tcx.dcx();
+            dcx.emit_err(errors::CantEmitMIR { error });
+            dcx.abort_if_errors();
         }
     }
 
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 8a553b95e8e95..1ea3db26e212b 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -208,12 +208,12 @@ impl<'tcx> Queries<'tcx> {
 
                 // Bare `#[rustc_error]`.
                 None => {
-                    tcx.sess.emit_fatal(RustcErrorFatal { span: tcx.def_span(def_id) });
+                    tcx.dcx().emit_fatal(RustcErrorFatal { span: tcx.def_span(def_id) });
                 }
 
                 // Some other attribute.
                 Some(_) => {
-                    tcx.sess.emit_warning(RustcErrorUnexpectedAnnotation {
+                    tcx.dcx().emit_warning(RustcErrorUnexpectedAnnotation {
                         span: tcx.def_span(def_id),
                     });
                 }
@@ -292,7 +292,9 @@ impl Linker {
                 &codegen_results,
                 &*self.output_filenames,
             )
-            .map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?;
+            .map_err(|error| {
+                sess.dcx().emit_fatal(FailedWritingFile { path: &rlink_file, error })
+            })?;
             return Ok(());
         }
 
@@ -330,7 +332,7 @@ impl Compiler {
         // the global context.
         _timer = Some(self.sess.timer("free_global_ctxt"));
         if let Err((path, error)) = queries.finish() {
-            self.sess.emit_err(errors::FailedWritingFile { path: &path, error });
+            self.sess.dcx().emit_err(errors::FailedWritingFile { path: &path, error });
         }
 
         ret
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index f230c5b172c29..92a6445ed0916 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -431,7 +431,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C
 
     base.retain(|crate_type| {
         if output::invalid_output_for_target(session, *crate_type) {
-            session.emit_warning(errors::UnsupportedCrateTypeForTarget {
+            session.dcx().emit_warning(errors::UnsupportedCrateTypeForTarget {
                 crate_type: *crate_type,
                 target_triple: &session.opts.target_triple,
             });
@@ -473,7 +473,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
         &sess.opts.output_types,
         sess.io.output_file == Some(OutFileName::Stdout),
     ) {
-        sess.emit_fatal(errors::MultipleOutputTypesToStdout);
+        sess.dcx().emit_fatal(errors::MultipleOutputTypesToStdout);
     }
 
     let crate_name = sess
@@ -507,16 +507,16 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu
             let unnamed_output_types =
                 sess.opts.output_types.values().filter(|a| a.is_none()).count();
             let ofile = if unnamed_output_types > 1 {
-                sess.emit_warning(errors::MultipleOutputTypesAdaption);
+                sess.dcx().emit_warning(errors::MultipleOutputTypesAdaption);
                 None
             } else {
                 if !sess.opts.cg.extra_filename.is_empty() {
-                    sess.emit_warning(errors::IgnoringExtraFilename);
+                    sess.dcx().emit_warning(errors::IgnoringExtraFilename);
                 }
                 Some(out_file.clone())
             };
             if sess.io.output_dir != None {
-                sess.emit_warning(errors::IgnoringOutDir);
+                sess.dcx().emit_warning(errors::IgnoringOutDir);
             }
 
             let out_filestem =
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 045ff38c0568c..8afb5f2d32ebf 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1728,7 +1728,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
                     None => format!("&(..={end})"),
                 };
                 if join.edition() >= Edition::Edition2021 {
-                    cx.sess().emit_err(BuiltinEllipsisInclusiveRangePatterns {
+                    cx.sess().dcx().emit_err(BuiltinEllipsisInclusiveRangePatterns {
                         span: pat.span,
                         suggestion: pat.span,
                         replace,
@@ -1746,7 +1746,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
             } else {
                 let replace = "..=";
                 if join.edition() >= Edition::Edition2021 {
-                    cx.sess().emit_err(BuiltinEllipsisInclusiveRangePatterns {
+                    cx.sess().dcx().emit_err(BuiltinEllipsisInclusiveRangePatterns {
                         span: pat.span,
                         suggestion: join,
                         replace: replace.to_string(),
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index c7a9d5e80aca6..40b70ba4e0429 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -1056,6 +1056,7 @@ pub trait LintContext {
         // a dummy diagnostic and emit is as usual, which will be suppressed and stored like a normal
         // expected lint diagnostic.
         self.sess()
+            .dcx()
             .struct_expect(
                 "this is a dummy diagnostic, to submit and store an expectation",
                 expectation,
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index b9add9e9f0657..70af6572246f4 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -426,7 +426,7 @@ pub fn check_ast_node_inner<'a, T: EarlyLintPass>(
     // that was not lint-checked (perhaps it doesn't exist?). This is a bug.
     for (id, lints) in cx.context.buffered.map {
         for early_lint in lints {
-            sess.span_delayed_bug(
+            sess.dcx().span_delayed_bug(
                 early_lint.span,
                 format!(
                     "failed to process buffered lint here (dummy = {})",
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 5dcc1bce5ff82..2b6290e8a0067 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -16,7 +16,7 @@ fn check_expectations(tcx: TyCtxt<'_>, tool_filter: Option<Symbol>) {
     }
 
     let lint_expectations = tcx.lint_expectations(());
-    let fulfilled_expectations = tcx.sess.dcx().steal_fulfilled_expectation_ids();
+    let fulfilled_expectations = tcx.dcx().steal_fulfilled_expectation_ids();
 
     tracing::debug!(?lint_expectations, ?fulfilled_expectations);
 
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 6eff2bfe13c69..17c56f1ca582e 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -144,7 +144,7 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
     builder.add_id(hir::CRATE_HIR_ID);
     tcx.hir().walk_toplevel_module(&mut builder);
 
-    tcx.sess.dcx().update_unstable_expectation_id(&builder.provider.unstable_to_stable_ids);
+    tcx.dcx().update_unstable_expectation_id(&builder.provider.unstable_to_stable_ids);
 
     builder.provider.expectations
 }
@@ -562,7 +562,9 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
             if lint_name_only == crate::WARNINGS.name_lower()
                 && matches!(level, Level::ForceWarn(_))
             {
-                self.sess.emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
+                self.sess
+                    .dcx()
+                    .emit_err(UnsupportedGroup { lint_group: crate::WARNINGS.name_lower() });
             }
             match self.store.check_lint_name(lint_name_only, tool_name, self.registered_tools) {
                 CheckLintNameResult::Renamed(ref replace) => {
@@ -593,7 +595,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                     self.emit_lint(RENAMED_AND_REMOVED_LINTS, lint);
                 }
                 CheckLintNameResult::NoTool => {
-                    self.sess.emit_err(CheckNameUnknownTool {
+                    self.sess.dcx().emit_err(CheckNameUnknownTool {
                         tool_name: tool_name.unwrap(),
                         sub: RequestedLevel { level, lint_name },
                     });
@@ -671,7 +673,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                     LintLevelSource::CommandLine(_, _) => OverruledAttributeSub::CommandLineSource,
                 };
                 if !fcw_warning {
-                    self.sess.emit_err(OverruledAttribute {
+                    self.sess.dcx().emit_err(OverruledAttribute {
                         span: src.span(),
                         overruled: src.span(),
                         lint_level: level.as_str(),
@@ -792,7 +794,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                                 }
                                 reason = Some(rationale);
                             } else {
-                                sess.emit_err(MalformedAttribute {
+                                sess.dcx().emit_err(MalformedAttribute {
                                     span: name_value.span,
                                     sub: MalformedAttributeSub::ReasonMustBeStringLiteral(
                                         name_value.span,
@@ -802,14 +804,14 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                             // found reason, reslice meta list to exclude it
                             metas.pop().unwrap();
                         } else {
-                            sess.emit_err(MalformedAttribute {
+                            sess.dcx().emit_err(MalformedAttribute {
                                 span: item.span,
                                 sub: MalformedAttributeSub::BadAttributeArgument(item.span),
                             });
                         }
                     }
                     ast::MetaItemKind::List(_) => {
-                        sess.emit_err(MalformedAttribute {
+                        sess.dcx().emit_err(MalformedAttribute {
                             span: item.span,
                             sub: MalformedAttributeSub::BadAttributeArgument(item.span),
                         });
@@ -833,7 +835,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                         if let Some(item) = li.meta_item() {
                             if let ast::MetaItemKind::NameValue(_) = item.kind {
                                 if item.path == sym::reason {
-                                    sess.emit_err(MalformedAttribute {
+                                    sess.dcx().emit_err(MalformedAttribute {
                                         span: sp,
                                         sub: MalformedAttributeSub::ReasonMustComeLast(sp),
                                     });
@@ -841,7 +843,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                                 }
                             }
                         }
-                        sess.emit_err(MalformedAttribute {
+                        sess.dcx().emit_err(MalformedAttribute {
                             span: sp,
                             sub: MalformedAttributeSub::BadAttributeArgument(sp),
                         });
@@ -957,7 +959,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                     }
 
                     &CheckLintNameResult::NoTool => {
-                        sess.emit_err(UnknownToolInScopedLint {
+                        sess.dcx().emit_err(UnknownToolInScopedLint {
                             span: tool_ident.map(|ident| ident.span),
                             tool_name: tool_name.unwrap(),
                             lint_name: pprust::path_to_string(&meta_item.path),
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 972c84b10f48e..a3da8c14f63a7 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -10,6 +10,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::owned_slice::OwnedSlice;
 use rustc_data_structures::svh::Svh;
 use rustc_data_structures::sync::{self, FreezeReadGuard, FreezeWriteGuard};
+use rustc_errors::DiagCtxt;
 use rustc_expand::base::SyntaxExtension;
 use rustc_fs_util::try_canonicalize;
 use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE};
@@ -89,6 +90,12 @@ impl<'a, 'tcx> std::ops::Deref for CrateLoader<'a, 'tcx> {
     }
 }
 
+impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
+    fn dcx(&self) -> &'tcx DiagCtxt {
+        &self.tcx.dcx()
+    }
+}
+
 pub enum LoadedMacro {
     MacroDef(ast::Item, Edition),
     ProcMacro(SyntaxExtension),
@@ -267,11 +274,7 @@ impl CStore {
             let unused_externs =
                 self.unused_externs.iter().map(|ident| ident.to_ident_string()).collect::<Vec<_>>();
             let unused_externs = unused_externs.iter().map(String::as_str).collect::<Vec<&str>>();
-            tcx.sess.dcx().emit_unused_externs(
-                level,
-                json_unused_externs.is_loud(),
-                &unused_externs,
-            );
+            tcx.dcx().emit_unused_externs(level, json_unused_externs.is_loud(), &unused_externs);
         }
     }
 
@@ -768,10 +771,10 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // Sanity check the loaded crate to ensure it is indeed a panic runtime
         // and the panic strategy is indeed what we thought it was.
         if !data.is_panic_runtime() {
-            self.sess.emit_err(errors::CrateNotPanicRuntime { crate_name: name });
+            self.dcx().emit_err(errors::CrateNotPanicRuntime { crate_name: name });
         }
         if data.required_panic_strategy() != Some(desired_strategy) {
-            self.sess
+            self.dcx()
                 .emit_err(errors::NoPanicStrategy { crate_name: name, strategy: desired_strategy });
         }
 
@@ -792,7 +795,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 
         let name = Symbol::intern(&self.sess.opts.unstable_opts.profiler_runtime);
         if name == sym::profiler_builtins && attr::contains_name(&krate.attrs, sym::no_core) {
-            self.sess.emit_err(errors::ProfilerBuiltinsNeedsCore);
+            self.dcx().emit_err(errors::ProfilerBuiltinsNeedsCore);
         }
 
         let Some(cnum) = self.resolve_crate(name, DUMMY_SP, CrateDepKind::Implicit) else {
@@ -802,21 +805,21 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
 
         // Sanity check the loaded crate to ensure it is indeed a profiler runtime
         if !data.is_profiler_runtime() {
-            self.sess.emit_err(errors::NotProfilerRuntime { crate_name: name });
+            self.dcx().emit_err(errors::NotProfilerRuntime { crate_name: name });
         }
     }
 
     fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
         self.cstore.has_global_allocator = match &*global_allocator_spans(krate) {
             [span1, span2, ..] => {
-                self.sess.emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
+                self.dcx().emit_err(errors::NoMultipleGlobalAlloc { span2: *span2, span1: *span1 });
                 true
             }
             spans => !spans.is_empty(),
         };
         self.cstore.has_alloc_error_handler = match &*alloc_error_handler_spans(krate) {
             [span1, span2, ..] => {
-                self.sess
+                self.dcx()
                     .emit_err(errors::NoMultipleAllocErrorHandler { span2: *span2, span1: *span1 });
                 true
             }
@@ -853,7 +856,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             if data.has_global_allocator() {
                 match global_allocator {
                     Some(other_crate) => {
-                        self.sess.emit_err(errors::ConflictingGlobalAlloc {
+                        self.dcx().emit_err(errors::ConflictingGlobalAlloc {
                             crate_name: data.name(),
                             other_crate_name: other_crate,
                         });
@@ -868,7 +871,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             if data.has_alloc_error_handler() {
                 match alloc_error_handler {
                     Some(other_crate) => {
-                        self.sess.emit_err(errors::ConflictingAllocErrorHandler {
+                        self.dcx().emit_err(errors::ConflictingAllocErrorHandler {
                             crate_name: data.name(),
                             other_crate_name: other_crate,
                         });
@@ -888,7 +891,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
             if !attr::contains_name(&krate.attrs, sym::default_lib_allocator)
                 && !self.cstore.iter_crate_data().any(|(_, data)| data.has_default_lib_allocator())
             {
-                self.sess.emit_err(errors::GlobalAllocRequired);
+                self.dcx().emit_err(errors::GlobalAllocRequired);
             }
             self.cstore.allocator_kind = Some(AllocatorKind::Default);
         }
@@ -922,7 +925,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         // don't perform this validation if the session has errors, as one of
         // those errors may indicate a circular dependency which could cause
         // this to stack overflow.
-        if self.sess.has_errors().is_some() {
+        if self.dcx().has_errors().is_some() {
             return;
         }
 
@@ -932,7 +935,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
         for dep in self.cstore.crate_dependencies_in_reverse_postorder(krate) {
             let data = self.cstore.get_crate_data(dep);
             if needs_dep(&data) {
-                self.sess.emit_err(errors::NoTransitiveNeedsDep {
+                self.dcx().emit_err(errors::NoTransitiveNeedsDep {
                     crate_name: self.cstore.get_crate_data(krate).name(),
                     needs_crate_name: what,
                     deps_crate_name: data.name(),
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index cb057cd39e29b..b80a9e9612aad 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -148,7 +148,7 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
                     if src.rlib.is_some() {
                         continue;
                     }
-                    sess.emit_err(RlibRequired { crate_name: tcx.crate_name(cnum) });
+                    sess.dcx().emit_err(RlibRequired { crate_name: tcx.crate_name(cnum) });
                 }
                 return Vec::new();
             }
@@ -236,9 +236,9 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
                 };
                 let crate_name = tcx.crate_name(cnum);
                 if crate_name.as_str().starts_with("rustc_") {
-                    sess.emit_err(RustcLibRequired { crate_name, kind });
+                    sess.dcx().emit_err(RustcLibRequired { crate_name, kind });
                 } else {
-                    sess.emit_err(LibRequired { crate_name, kind });
+                    sess.dcx().emit_err(LibRequired { crate_name, kind });
                 }
             }
         }
@@ -263,7 +263,7 @@ fn add_library(
             // This error is probably a little obscure, but I imagine that it
             // can be refined over time.
             if link2 != link || link == RequireStatic {
-                tcx.sess.emit_err(CrateDepMultiple { crate_name: tcx.crate_name(cnum) });
+                tcx.dcx().emit_err(CrateDepMultiple { crate_name: tcx.crate_name(cnum) });
             }
         }
         None => {
@@ -357,7 +357,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
             if let Some((prev, _)) = panic_runtime {
                 let prev_name = tcx.crate_name(prev);
                 let cur_name = tcx.crate_name(cnum);
-                sess.emit_err(TwoPanicRuntimes { prev_name, cur_name });
+                sess.dcx().emit_err(TwoPanicRuntimes { prev_name, cur_name });
             }
             panic_runtime = Some((
                 cnum,
@@ -377,7 +377,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
         // First up, validate that our selected panic runtime is indeed exactly
         // our same strategy.
         if found_strategy != desired_strategy {
-            sess.emit_err(BadPanicStrategy {
+            sess.dcx().emit_err(BadPanicStrategy {
                 runtime: tcx.crate_name(runtime_cnum),
                 strategy: desired_strategy,
             });
@@ -399,7 +399,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
             if let Some(found_strategy) = tcx.required_panic_strategy(cnum)
                 && desired_strategy != found_strategy
             {
-                sess.emit_err(RequiredPanicStrategy {
+                sess.dcx().emit_err(RequiredPanicStrategy {
                     crate_name: tcx.crate_name(cnum),
                     found_strategy,
                     desired_strategy,
@@ -408,7 +408,7 @@ fn verify_ok(tcx: TyCtxt<'_>, list: &[Linkage]) {
 
             let found_drop_strategy = tcx.panic_in_drop_strategy(cnum);
             if tcx.sess.opts.unstable_opts.panic_in_drop != found_drop_strategy {
-                sess.emit_err(IncompatiblePanicInDropStrategy {
+                sess.dcx().emit_err(IncompatiblePanicInDropStrategy {
                     crate_name: tcx.crate_name(cnum),
                     found_strategy: found_drop_strategy,
                     desired_strategy: tcx.sess.opts.unstable_opts.panic_in_drop,
diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs
index e80afcc482eaf..a0abda53eb3e7 100644
--- a/compiler/rustc_metadata/src/fs.rs
+++ b/compiler/rustc_metadata/src/fs.rs
@@ -32,7 +32,7 @@ pub fn emit_wrapper_file(
     let result = fs::write(&out_filename, data);
 
     if let Err(err) = result {
-        sess.emit_fatal(FailedWriteError { filename: out_filename, err });
+        sess.dcx().emit_fatal(FailedWriteError { filename: out_filename, err });
     }
 
     out_filename
@@ -48,7 +48,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
     let metadata_tmpdir = TempFileBuilder::new()
         .prefix("rmeta")
         .tempdir_in(out_filename.parent().unwrap_or_else(|| Path::new("")))
-        .unwrap_or_else(|err| tcx.sess.emit_fatal(FailedCreateTempdir { err }));
+        .unwrap_or_else(|err| tcx.dcx().emit_fatal(FailedCreateTempdir { err }));
     let metadata_tmpdir = MaybeTempDir::new(metadata_tmpdir, tcx.sess.opts.cg.save_temps);
     let metadata_filename = metadata_tmpdir.as_ref().join(METADATA_FILENAME);
 
@@ -58,7 +58,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
     match metadata_kind {
         MetadataKind::None => {
             std::fs::File::create(&metadata_filename).unwrap_or_else(|err| {
-                tcx.sess.emit_fatal(FailedCreateFile { filename: &metadata_filename, err });
+                tcx.dcx().emit_fatal(FailedCreateFile { filename: &metadata_filename, err });
             });
         }
         MetadataKind::Uncompressed | MetadataKind::Compressed => {
@@ -76,22 +76,22 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
         let filename = match out_filename {
             OutFileName::Real(ref path) => {
                 if let Err(err) = non_durable_rename(&metadata_filename, path) {
-                    tcx.sess.emit_fatal(FailedWriteError { filename: path.to_path_buf(), err });
+                    tcx.dcx().emit_fatal(FailedWriteError { filename: path.to_path_buf(), err });
                 }
                 path.clone()
             }
             OutFileName::Stdout => {
                 if out_filename.is_tty() {
-                    tcx.sess.emit_err(BinaryOutputToTty);
+                    tcx.dcx().emit_err(BinaryOutputToTty);
                 } else if let Err(err) = copy_to_stdout(&metadata_filename) {
-                    tcx.sess
+                    tcx.dcx()
                         .emit_err(FailedCopyToStdout { filename: metadata_filename.clone(), err });
                 }
                 metadata_filename
             }
         };
         if tcx.sess.opts.json_artifact_notifications {
-            tcx.sess.dcx().emit_artifact_notification(out_filename.as_path(), "metadata");
+            tcx.dcx().emit_artifact_notification(out_filename.as_path(), "metadata");
         }
         (filename, None)
     } else {
@@ -101,7 +101,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
     // Load metadata back to memory: codegen may need to include it in object files.
     let metadata =
         EncodedMetadata::from_path(metadata_filename, metadata_tmpdir).unwrap_or_else(|err| {
-            tcx.sess.emit_fatal(FailedCreateEncodedMetadata { err });
+            tcx.dcx().emit_fatal(FailedCreateEncodedMetadata { err });
         });
 
     let need_metadata_module = metadata_kind == MetadataKind::Compressed;
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index f9219d12afdd2..2376d95334155 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -947,27 +947,28 @@ impl fmt::Display for MetadataError<'_> {
 
 impl CrateError {
     pub(crate) fn report(self, sess: &Session, span: Span, missing_core: bool) {
+        let dcx = sess.dcx();
         match self {
             CrateError::NonAsciiName(crate_name) => {
-                sess.emit_err(errors::NonAsciiName { span, crate_name });
+                dcx.emit_err(errors::NonAsciiName { span, crate_name });
             }
             CrateError::ExternLocationNotExist(crate_name, loc) => {
-                sess.emit_err(errors::ExternLocationNotExist { span, crate_name, location: &loc });
+                dcx.emit_err(errors::ExternLocationNotExist { span, crate_name, location: &loc });
             }
             CrateError::ExternLocationNotFile(crate_name, loc) => {
-                sess.emit_err(errors::ExternLocationNotFile { span, crate_name, location: &loc });
+                dcx.emit_err(errors::ExternLocationNotFile { span, crate_name, location: &loc });
             }
             CrateError::MultipleCandidates(crate_name, flavor, candidates) => {
-                sess.emit_err(errors::MultipleCandidates { span, crate_name, flavor, candidates });
+                dcx.emit_err(errors::MultipleCandidates { span, crate_name, flavor, candidates });
             }
             CrateError::SymbolConflictsCurrent(root_name) => {
-                sess.emit_err(errors::SymbolConflictsCurrent { span, crate_name: root_name });
+                dcx.emit_err(errors::SymbolConflictsCurrent { span, crate_name: root_name });
             }
             CrateError::StableCrateIdCollision(crate_name0, crate_name1) => {
-                sess.emit_err(errors::StableCrateIdCollision { span, crate_name0, crate_name1 });
+                dcx.emit_err(errors::StableCrateIdCollision { span, crate_name0, crate_name1 });
             }
             CrateError::DlOpen(s) | CrateError::DlSym(s) => {
-                sess.emit_err(errors::DlError { span, err: s });
+                dcx.emit_err(errors::DlError { span, err: s });
             }
             CrateError::LocatorCombined(locator) => {
                 let crate_name = locator.crate_name;
@@ -978,12 +979,12 @@ impl CrateError {
                 if !locator.crate_rejections.via_filename.is_empty() {
                     let mismatches = locator.crate_rejections.via_filename.iter();
                     for CrateMismatch { path, .. } in mismatches {
-                        sess.emit_err(errors::CrateLocationUnknownType {
+                        dcx.emit_err(errors::CrateLocationUnknownType {
                             span,
                             path: path,
                             crate_name,
                         });
-                        sess.emit_err(errors::LibFilenameForm {
+                        dcx.emit_err(errors::LibFilenameForm {
                             span,
                             dll_prefix: &locator.dll_prefix,
                             dll_suffix: &locator.dll_suffix,
@@ -1009,7 +1010,7 @@ impl CrateError {
                             ));
                         }
                     }
-                    sess.emit_err(errors::NewerCrateVersion {
+                    dcx.emit_err(errors::NewerCrateVersion {
                         span,
                         crate_name: crate_name,
                         add_info,
@@ -1025,7 +1026,7 @@ impl CrateError {
                             path.display(),
                         ));
                     }
-                    sess.emit_err(errors::NoCrateWithTriple {
+                    dcx.emit_err(errors::NoCrateWithTriple {
                         span,
                         crate_name,
                         locator_triple: locator.triple.triple(),
@@ -1041,7 +1042,7 @@ impl CrateError {
                             path.display()
                         ));
                     }
-                    sess.emit_err(errors::FoundStaticlib {
+                    dcx.emit_err(errors::FoundStaticlib {
                         span,
                         crate_name,
                         add_info,
@@ -1057,7 +1058,7 @@ impl CrateError {
                             path.display(),
                         ));
                     }
-                    sess.emit_err(errors::IncompatibleRustc {
+                    dcx.emit_err(errors::IncompatibleRustc {
                         span,
                         crate_name,
                         add_info,
@@ -1069,14 +1070,14 @@ impl CrateError {
                     for CrateMismatch { path: _, got } in locator.crate_rejections.via_invalid {
                         crate_rejections.push(got);
                     }
-                    sess.emit_err(errors::InvalidMetadataFiles {
+                    dcx.emit_err(errors::InvalidMetadataFiles {
                         span,
                         crate_name,
                         add_info,
                         crate_rejections,
                     });
                 } else {
-                    sess.emit_err(errors::CannotFindCrate {
+                    dcx.emit_err(errors::CannotFindCrate {
                         span,
                         crate_name,
                         add_info,
@@ -1094,7 +1095,7 @@ impl CrateError {
                 }
             }
             CrateError::NotFound(crate_name) => {
-                sess.emit_err(errors::CannotFindCrate {
+                dcx.emit_err(errors::CannotFindCrate {
                     span,
                     crate_name,
                     add_info: String::new(),
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index b3760b1099b4b..a639a887544e1 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -44,7 +44,7 @@ pub fn find_native_static_library(
         }
     }
 
-    sess.emit_fatal(errors::MissingNativeLibrary::new(name, verbatim));
+    sess.dcx().emit_fatal(errors::MissingNativeLibrary::new(name, verbatim));
 }
 
 fn find_bundled_library(
@@ -121,26 +121,26 @@ impl<'tcx> Collector<'tcx> {
                 match item.name_or_empty() {
                     sym::name => {
                         if name.is_some() {
-                            sess.emit_err(errors::MultipleNamesInLink { span: item.span() });
+                            sess.dcx().emit_err(errors::MultipleNamesInLink { span: item.span() });
                             continue;
                         }
                         let Some(link_name) = item.value_str() else {
-                            sess.emit_err(errors::LinkNameForm { span: item.span() });
+                            sess.dcx().emit_err(errors::LinkNameForm { span: item.span() });
                             continue;
                         };
                         let span = item.name_value_literal_span().unwrap();
                         if link_name.is_empty() {
-                            sess.emit_err(errors::EmptyLinkName { span });
+                            sess.dcx().emit_err(errors::EmptyLinkName { span });
                         }
                         name = Some((link_name, span));
                     }
                     sym::kind => {
                         if kind.is_some() {
-                            sess.emit_err(errors::MultipleKindsInLink { span: item.span() });
+                            sess.dcx().emit_err(errors::MultipleKindsInLink { span: item.span() });
                             continue;
                         }
                         let Some(link_kind) = item.value_str() else {
-                            sess.emit_err(errors::LinkKindForm { span: item.span() });
+                            sess.dcx().emit_err(errors::LinkKindForm { span: item.span() });
                             continue;
                         };
 
@@ -150,13 +150,13 @@ impl<'tcx> Collector<'tcx> {
                             "dylib" => NativeLibKind::Dylib { as_needed: None },
                             "framework" => {
                                 if !sess.target.is_like_osx {
-                                    sess.emit_err(errors::LinkFrameworkApple { span });
+                                    sess.dcx().emit_err(errors::LinkFrameworkApple { span });
                                 }
                                 NativeLibKind::Framework { as_needed: None }
                             }
                             "raw-dylib" => {
                                 if !sess.target.is_like_windows {
-                                    sess.emit_err(errors::FrameworkOnlyWindows { span });
+                                    sess.dcx().emit_err(errors::FrameworkOnlyWindows { span });
                                 }
                                 NativeLibKind::RawDylib
                             }
@@ -173,7 +173,7 @@ impl<'tcx> Collector<'tcx> {
                                 NativeLibKind::LinkArg
                             }
                             kind => {
-                                sess.emit_err(errors::UnknownLinkKind { span, kind });
+                                sess.dcx().emit_err(errors::UnknownLinkKind { span, kind });
                                 continue;
                             }
                         };
@@ -181,26 +181,28 @@ impl<'tcx> Collector<'tcx> {
                     }
                     sym::modifiers => {
                         if modifiers.is_some() {
-                            sess.emit_err(errors::MultipleLinkModifiers { span: item.span() });
+                            sess.dcx()
+                                .emit_err(errors::MultipleLinkModifiers { span: item.span() });
                             continue;
                         }
                         let Some(link_modifiers) = item.value_str() else {
-                            sess.emit_err(errors::LinkModifiersForm { span: item.span() });
+                            sess.dcx().emit_err(errors::LinkModifiersForm { span: item.span() });
                             continue;
                         };
                         modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
                     }
                     sym::cfg => {
                         if cfg.is_some() {
-                            sess.emit_err(errors::MultipleCfgs { span: item.span() });
+                            sess.dcx().emit_err(errors::MultipleCfgs { span: item.span() });
                             continue;
                         }
                         let Some(link_cfg) = item.meta_item_list() else {
-                            sess.emit_err(errors::LinkCfgForm { span: item.span() });
+                            sess.dcx().emit_err(errors::LinkCfgForm { span: item.span() });
                             continue;
                         };
                         let [NestedMetaItem::MetaItem(link_cfg)] = link_cfg else {
-                            sess.emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
+                            sess.dcx()
+                                .emit_err(errors::LinkCfgSinglePredicate { span: item.span() });
                             continue;
                         };
                         if !features.link_cfg {
@@ -216,26 +218,27 @@ impl<'tcx> Collector<'tcx> {
                     }
                     sym::wasm_import_module => {
                         if wasm_import_module.is_some() {
-                            sess.emit_err(errors::MultipleWasmImport { span: item.span() });
+                            sess.dcx().emit_err(errors::MultipleWasmImport { span: item.span() });
                             continue;
                         }
                         let Some(link_wasm_import_module) = item.value_str() else {
-                            sess.emit_err(errors::WasmImportForm { span: item.span() });
+                            sess.dcx().emit_err(errors::WasmImportForm { span: item.span() });
                             continue;
                         };
                         wasm_import_module = Some((link_wasm_import_module, item.span()));
                     }
                     sym::import_name_type => {
                         if import_name_type.is_some() {
-                            sess.emit_err(errors::MultipleImportNameType { span: item.span() });
+                            sess.dcx()
+                                .emit_err(errors::MultipleImportNameType { span: item.span() });
                             continue;
                         }
                         let Some(link_import_name_type) = item.value_str() else {
-                            sess.emit_err(errors::ImportNameTypeForm { span: item.span() });
+                            sess.dcx().emit_err(errors::ImportNameTypeForm { span: item.span() });
                             continue;
                         };
                         if self.tcx.sess.target.arch != "x86" {
-                            sess.emit_err(errors::ImportNameTypeX86 { span: item.span() });
+                            sess.dcx().emit_err(errors::ImportNameTypeX86 { span: item.span() });
                             continue;
                         }
 
@@ -244,7 +247,7 @@ impl<'tcx> Collector<'tcx> {
                             "noprefix" => PeImportNameType::NoPrefix,
                             "undecorated" => PeImportNameType::Undecorated,
                             import_name_type => {
-                                sess.emit_err(errors::UnknownImportNameType {
+                                sess.dcx().emit_err(errors::UnknownImportNameType {
                                     span: item.span(),
                                     import_name_type,
                                 });
@@ -254,7 +257,7 @@ impl<'tcx> Collector<'tcx> {
                         import_name_type = Some((link_import_name_type, item.span()));
                     }
                     _ => {
-                        sess.emit_err(errors::UnexpectedLinkArg { span: item.span() });
+                        sess.dcx().emit_err(errors::UnexpectedLinkArg { span: item.span() });
                     }
                 }
             }
@@ -266,7 +269,7 @@ impl<'tcx> Collector<'tcx> {
                     let (modifier, value) = match modifier.strip_prefix(&['+', '-']) {
                         Some(m) => (m, modifier.starts_with('+')),
                         None => {
-                            sess.emit_err(errors::InvalidLinkModifier { span });
+                            sess.dcx().emit_err(errors::InvalidLinkModifier { span });
                             continue;
                         }
                     };
@@ -284,7 +287,7 @@ impl<'tcx> Collector<'tcx> {
                     }
                     let assign_modifier = |dst: &mut Option<bool>| {
                         if dst.is_some() {
-                            sess.emit_err(errors::MultipleModifiers { span, modifier });
+                            sess.dcx().emit_err(errors::MultipleModifiers { span, modifier });
                         } else {
                             *dst = Some(value);
                         }
@@ -294,7 +297,7 @@ impl<'tcx> Collector<'tcx> {
                             assign_modifier(bundle)
                         }
                         ("bundle", _) => {
-                            sess.emit_err(errors::BundleNeedsStatic { span });
+                            sess.dcx().emit_err(errors::BundleNeedsStatic { span });
                         }
 
                         ("verbatim", _) => assign_modifier(&mut verbatim),
@@ -303,7 +306,7 @@ impl<'tcx> Collector<'tcx> {
                             assign_modifier(whole_archive)
                         }
                         ("whole-archive", _) => {
-                            sess.emit_err(errors::WholeArchiveNeedsStatic { span });
+                            sess.dcx().emit_err(errors::WholeArchiveNeedsStatic { span });
                         }
 
                         ("as-needed", Some(NativeLibKind::Dylib { as_needed }))
@@ -312,11 +315,11 @@ impl<'tcx> Collector<'tcx> {
                             assign_modifier(as_needed)
                         }
                         ("as-needed", _) => {
-                            sess.emit_err(errors::AsNeededCompatibility { span });
+                            sess.dcx().emit_err(errors::AsNeededCompatibility { span });
                         }
 
                         _ => {
-                            sess.emit_err(errors::UnknownLinkModifier { span, modifier });
+                            sess.dcx().emit_err(errors::UnknownLinkModifier { span, modifier });
                         }
                     }
                 }
@@ -324,7 +327,7 @@ impl<'tcx> Collector<'tcx> {
 
             if let Some((_, span)) = wasm_import_module {
                 if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
-                    sess.emit_err(errors::IncompatibleWasmLink { span });
+                    sess.dcx().emit_err(errors::IncompatibleWasmLink { span });
                 }
             }
 
@@ -332,21 +335,21 @@ impl<'tcx> Collector<'tcx> {
                 (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
             }
             let Some((name, name_span)) = name else {
-                sess.emit_err(errors::LinkRequiresName { span: m.span });
+                sess.dcx().emit_err(errors::LinkRequiresName { span: m.span });
                 continue;
             };
 
             // Do this outside of the loop so that `import_name_type` can be specified before `kind`.
             if let Some((_, span)) = import_name_type {
                 if kind != Some(NativeLibKind::RawDylib) {
-                    sess.emit_err(errors::ImportNameTypeRaw { span });
+                    sess.dcx().emit_err(errors::ImportNameTypeRaw { span });
                 }
             }
 
             let dll_imports = match kind {
                 Some(NativeLibKind::RawDylib) => {
                     if name.as_str().contains('\0') {
-                        sess.emit_err(errors::RawDylibNoNul { span: name_span });
+                        sess.dcx().emit_err(errors::RawDylibNoNul { span: name_span });
                     }
                     foreign_items
                         .iter()
@@ -366,7 +369,7 @@ impl<'tcx> Collector<'tcx> {
                         {
                             let link_ordinal_attr =
                                 self.tcx.get_attr(child_item, sym::link_ordinal).unwrap();
-                            sess.emit_err(errors::LinkOrdinalRawDylib {
+                            sess.dcx().emit_err(errors::LinkOrdinalRawDylib {
                                 span: link_ordinal_attr.span,
                             });
                         }
@@ -399,16 +402,16 @@ impl<'tcx> Collector<'tcx> {
                 && !self.tcx.sess.target.is_like_osx
             {
                 // Cannot check this when parsing options because the target is not yet available.
-                self.tcx.sess.emit_err(errors::LibFrameworkApple);
+                self.tcx.dcx().emit_err(errors::LibFrameworkApple);
             }
             if let Some(ref new_name) = lib.new_name {
                 let any_duplicate = self.libs.iter().any(|n| n.name.as_str() == lib.name);
                 if new_name.is_empty() {
-                    self.tcx.sess.emit_err(errors::EmptyRenamingTarget { lib_name: &lib.name });
+                    self.tcx.dcx().emit_err(errors::EmptyRenamingTarget { lib_name: &lib.name });
                 } else if !any_duplicate {
-                    self.tcx.sess.emit_err(errors::RenamingNoLink { lib_name: &lib.name });
+                    self.tcx.dcx().emit_err(errors::RenamingNoLink { lib_name: &lib.name });
                 } else if !renames.insert(&lib.name) {
-                    self.tcx.sess.emit_err(errors::MultipleRenamings { lib_name: &lib.name });
+                    self.tcx.dcx().emit_err(errors::MultipleRenamings { lib_name: &lib.name });
                 }
             }
         }
@@ -433,12 +436,15 @@ impl<'tcx> Collector<'tcx> {
                         // explicit `:rename` in particular.
                         if lib.has_modifiers() || passed_lib.has_modifiers() {
                             match lib.foreign_module {
-                                Some(def_id) => self.tcx.sess.emit_err(errors::NoLinkModOverride {
-                                    span: Some(self.tcx.def_span(def_id)),
-                                }),
-                                None => {
-                                    self.tcx.sess.emit_err(errors::NoLinkModOverride { span: None })
+                                Some(def_id) => {
+                                    self.tcx.dcx().emit_err(errors::NoLinkModOverride {
+                                        span: Some(self.tcx.def_span(def_id)),
+                                    })
                                 }
+                                None => self
+                                    .tcx
+                                    .dcx()
+                                    .emit_err(errors::NoLinkModOverride { span: None }),
                             };
                         }
                         if passed_lib.kind != NativeLibKind::Unspecified {
@@ -527,14 +533,14 @@ impl<'tcx> Collector<'tcx> {
                     DllCallingConvention::Vectorcall(self.i686_arg_list_size(item))
                 }
                 _ => {
-                    self.tcx.sess.emit_fatal(errors::UnsupportedAbiI686 { span });
+                    self.tcx.dcx().emit_fatal(errors::UnsupportedAbiI686 { span });
                 }
             }
         } else {
             match abi {
                 Abi::C { .. } | Abi::Win64 { .. } | Abi::System { .. } => DllCallingConvention::C,
                 _ => {
-                    self.tcx.sess.emit_fatal(errors::UnsupportedAbi { span });
+                    self.tcx.dcx().emit_fatal(errors::UnsupportedAbi { span });
                 }
             }
         };
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 057fb15ac3b13..bf1976d123c77 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -2186,7 +2186,7 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) {
     }
 
     let mut encoder = opaque::FileEncoder::new(path)
-        .unwrap_or_else(|err| tcx.sess.emit_fatal(FailCreateFileEncoder { err }));
+        .unwrap_or_else(|err| tcx.dcx().emit_fatal(FailCreateFileEncoder { err }));
     encoder.emit_raw_bytes(METADATA_HEADER);
 
     // Will be filled with the root position after encoding everything.
@@ -2227,12 +2227,12 @@ pub fn encode_metadata(tcx: TyCtxt<'_>, path: &Path) {
     // If we forget this, compilation can succeed with an incomplete rmeta file,
     // causing an ICE when the rmeta file is read by another compilation.
     if let Err((path, err)) = ecx.opaque.finish() {
-        tcx.sess.emit_err(FailWriteFile { path: &path, err });
+        tcx.dcx().emit_err(FailWriteFile { path: &path, err });
     }
 
     let file = ecx.opaque.file();
     if let Err(err) = encode_root_position(file, root.position.get()) {
-        tcx.sess.emit_err(FailWriteFile { path: ecx.opaque.path(), err });
+        tcx.dcx().emit_err(FailWriteFile { path: ecx.opaque.path(), err });
     }
 
     // Record metadata size for self-profiling
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 8c1e58fefc589..26ca90db018e6 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -4,10 +4,10 @@
 ///
 /// If you have a span available, you should use [`span_bug`] instead.
 ///
-/// If the bug should only be emitted when compilation didn't fail, [`Session::span_delayed_bug`]
+/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxt::span_delayed_bug`]
 /// may be useful.
 ///
-/// [`Session::span_delayed_bug`]: rustc_session::Session::span_delayed_bug
+/// [`DiagCtxt::span_delayed_bug`]: rustc_errors::DiagCtxt::span_delayed_bug
 /// [`span_bug`]: crate::span_bug
 #[macro_export]
 macro_rules! bug {
@@ -24,10 +24,10 @@ macro_rules! bug {
 /// at the code the compiler was compiling when it ICEd. This is the preferred way to trigger
 /// ICEs.
 ///
-/// If the bug should only be emitted when compilation didn't fail, [`Session::span_delayed_bug`]
+/// If the bug should only be emitted when compilation didn't fail, [`DiagCtxt::span_delayed_bug`]
 /// may be useful.
 ///
-/// [`Session::span_delayed_bug`]: rustc_session::Session::span_delayed_bug
+/// [`DiagCtxt::span_delayed_bug`]: rustc_errors::DiagCtxt::span_delayed_bug
 #[macro_export]
 macro_rules! span_bug {
     ($span:expr, $msg:expr) => ({ $crate::util::bug::span_bug_fmt($span, ::std::format_args!($msg)) });
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index 2899e629d7914..f92c72c8a588c 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -19,7 +19,7 @@ impl<'tcx> TyCtxt<'tcx> {
     /// If not found, fatally aborts compilation.
     pub fn require_lang_item(self, lang_item: LangItem, span: Option<Span>) -> DefId {
         self.lang_items().get(lang_item).unwrap_or_else(|| {
-            self.sess.emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() });
+            self.dcx().emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() });
         })
     }
 
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index b29be92ae2663..344ea38192e9a 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -64,7 +64,7 @@ fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: u
                         IntErrorKind::Zero => bug!("zero is a valid `limit`"),
                         kind => bug!("unimplemented IntErrorKind variant: {:?}", kind),
                     };
-                    sess.emit_err(LimitInvalid { span: attr.span, value_span, error_str });
+                    sess.dcx().emit_err(LimitInvalid { span: attr.span, value_span, error_str });
                 }
             }
         }
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 0cba6d5b52a8f..b2d1124b2edc5 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -565,7 +565,7 @@ impl<'tcx> TyCtxt<'tcx> {
             |span, def_id| {
                 // The API could be uncallable for other reasons, for example when a private module
                 // was referenced.
-                self.sess.span_delayed_bug(span, format!("encountered unmarked API: {def_id:?}"));
+                self.dcx().span_delayed_bug(span, format!("encountered unmarked API: {def_id:?}"));
             },
         )
     }
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 2a9e0847f439f..a92b85a716f9e 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -315,7 +315,7 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
     pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> {
         Self::uninit_inner(size, align, || {
             ty::tls::with(|tcx| {
-                tcx.sess.span_delayed_bug(DUMMY_SP, "exhausted memory during interpretation")
+                tcx.dcx().span_delayed_bug(DUMMY_SP, "exhausted memory during interpretation")
             });
             InterpError::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted).into()
         })
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 2cd2fcca9d5aa..e6536074f35fc 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -47,7 +47,7 @@ impl ErrorHandled {
         match self {
             &ErrorHandled::Reported(err, span) => {
                 if !err.is_tainted_by_errors && !span.is_dummy() {
-                    tcx.sess.emit_note(error::ErroneousConstant { span });
+                    tcx.dcx().emit_note(error::ErroneousConstant { span });
                 }
             }
             &ErrorHandled::TooGeneric(_) => {}
@@ -91,7 +91,7 @@ pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
 pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
 
 pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> {
-    struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg)
+    struct_span_err!(tcx.dcx(), tcx.span, E0080, "{}", msg)
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs
index 0d1f3c1f8b522..d2ff1e3c0944b 100644
--- a/compiler/rustc_middle/src/query/plumbing.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -551,7 +551,7 @@ macro_rules! define_feedable {
                                 // We have an inconsistency. This can happen if one of the two
                                 // results is tainted by errors. In this case, delay a bug to
                                 // ensure compilation is doomed, and keep the `old` value.
-                                tcx.sess.span_delayed_bug(DUMMY_SP, format!(
+                                tcx.dcx().span_delayed_bug(DUMMY_SP, format!(
                                     "Trying to feed an already recorded value for query {} key={key:?}:\n\
                                     old value: {old:?}\nnew value: {value:?}",
                                     stringify!($name),
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 34c56eb0d7b1e..5f02dd22961c0 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -105,7 +105,7 @@ pub struct DropckOutlivesResult<'tcx> {
 impl<'tcx> DropckOutlivesResult<'tcx> {
     pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
         if let Some(overflow_ty) = self.overflows.get(0) {
-            tcx.sess.emit_err(DropCheckOverflow { span, ty, overflow_ty: *overflow_ty });
+            tcx.dcx().emit_err(DropCheckOverflow { span, ty, overflow_ty: *overflow_ty });
         }
     }
 }
diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs
index 6db427064d16c..898258445dc85 100644
--- a/compiler/rustc_middle/src/traits/specialization_graph.rs
+++ b/compiler/rustc_middle/src/traits/specialization_graph.rs
@@ -76,7 +76,7 @@ impl OverlapMode {
                     })
                     .find(|attr| attr.has_name(sym::rustc_strict_coherence))
                     .map(|attr| attr.span);
-                tcx.sess.emit_err(StrictCoherenceNeedsNegativeCoherence {
+                tcx.dcx().emit_err(StrictCoherenceNeedsNegativeCoherence {
                     span: tcx.def_span(trait_id),
                     attr_span,
                 });
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 1d9a25628b047..b95ae5881e24f 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -470,7 +470,7 @@ impl<'tcx> AdtDef<'tcx> {
                     Some(Discr { val: b, ty })
                 } else {
                     info!("invalid enum discriminant: {:#?}", val);
-                    tcx.sess.emit_err(crate::error::ConstEvalNonIntError {
+                    tcx.dcx().emit_err(crate::error::ConstEvalNonIntError {
                         span: tcx.def_span(expr_did),
                     });
                     None
@@ -481,7 +481,7 @@ impl<'tcx> AdtDef<'tcx> {
                     ErrorHandled::Reported(..) => "enum discriminant evaluation failed",
                     ErrorHandled::TooGeneric(..) => "enum discriminant depends on generics",
                 };
-                tcx.sess.span_delayed_bug(tcx.def_span(expr_did), msg);
+                tcx.dcx().span_delayed_bug(tcx.def_span(expr_did), msg);
                 None
             }
         }
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index 2d3ee33489e4f..6ec1dec97816c 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -159,7 +159,7 @@ impl<'tcx> Const<'tcx> {
         span: S,
         msg: &'static str,
     ) -> Const<'tcx> {
-        let reported = tcx.sess.span_delayed_bug(span, msg);
+        let reported = tcx.dcx().span_delayed_bug(span, msg);
         Const::new_error(tcx, reported, ty)
     }
 
@@ -223,7 +223,7 @@ impl<'tcx> Const<'tcx> {
             match tcx.at(expr.span).lit_to_const(lit_input) {
                 Ok(c) => return Some(c),
                 Err(e) => {
-                    tcx.sess.span_delayed_bug(
+                    tcx.dcx().span_delayed_bug(
                         expr.span,
                         format!("Const::from_anon_const: couldn't lit_to_const {e:?}"),
                     );
@@ -322,7 +322,7 @@ impl<'tcx> Const<'tcx> {
                 let Some(c) = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?
                 else {
                     // This can happen when we run on ill-typed code.
-                    let e = tcx.sess.span_delayed_bug(
+                    let e = tcx.dcx().span_delayed_bug(
                         span.unwrap_or(DUMMY_SP),
                         "`ty::Const::eval` called on a non-valtree-compatible type",
                     );
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 655dde1d9c987..ac675a70b546e 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -44,7 +44,7 @@ use rustc_data_structures::sync::{self, FreezeReadGuard, Lock, WorkerLocal};
 use rustc_data_structures::sync::{DynSend, DynSync};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::{
-    DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
+    DecorateLint, DiagCtxt, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
@@ -747,7 +747,7 @@ impl<'tcx> TyCtxt<'tcx> {
             {
                 Bound::Included(a)
             } else {
-                self.sess.span_delayed_bug(
+                self.dcx().span_delayed_bug(
                     attr.span,
                     "invalid rustc_layout_scalar_valid_range attribute",
                 );
@@ -783,7 +783,7 @@ impl<'tcx> TyCtxt<'tcx> {
         hooks: crate::hooks::Providers,
     ) -> GlobalCtxt<'tcx> {
         let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| {
-            s.emit_fatal(err);
+            s.dcx().emit_fatal(err);
         });
         let interners = CtxtInterners::new(arena);
         let common_types = CommonTypes::new(&interners, s, &untracked);
@@ -1018,6 +1018,10 @@ impl<'tcx> TyCtxt<'tcx> {
             self.def_path(def_id).to_string_no_crate_verbose()
         )
     }
+
+    pub fn dcx(self) -> &'tcx DiagCtxt {
+        self.sess.dcx()
+    }
 }
 
 impl<'tcx> TyCtxtAt<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 5ae758edfa337..8a02914b4359c 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -284,7 +284,7 @@ impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> {
     type TargetDataLayoutRef = &'tcx TargetDataLayout;
 
     fn delayed_bug(&self, txt: String) {
-        self.tcx.sess.span_delayed_bug(DUMMY_SP, txt);
+        self.tcx.dcx().span_delayed_bug(DUMMY_SP, txt);
     }
 
     fn current_data_layout(&self) -> Self::TargetDataLayoutRef {
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 36b8d387d6966..9f1ff4538aa24 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1495,7 +1495,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
         } else {
             TypeMismatchReason::PreviousUse { span: self.span }
         };
-        tcx.sess.create_err(OpaqueHiddenTypeMismatch {
+        tcx.dcx().create_err(OpaqueHiddenTypeMismatch {
             self_ty: self.ty,
             other_ty: other.ty,
             other_span: other.span,
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index 1305f63bdbc2f..71fe7d15a6cf7 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -130,7 +130,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
             None => {
                 let e = self
                     .tcx
-                    .sess
+                    .dcx()
                     .struct_span_err(self.span, "non-defining opaque type use in defining scope")
                     .span_label(
                         self.span,
@@ -174,7 +174,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
                         debug!(?param, ?self.map);
                         if !self.ignore_errors {
                             self.tcx
-                                .sess
+                                .dcx()
                                 .struct_span_err(
                                     self.span,
                                     format!(
@@ -208,7 +208,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
                     None => {
                         let guar = self
                             .tcx
-                            .sess
+                            .dcx()
                             .create_err(ConstNotUsedTraitAlias {
                                 ct: ct.to_string(),
                                 span: self.span,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index a0debc8a165dd..5b9dff8e3f29d 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -1557,7 +1557,7 @@ impl<'tcx> Region<'tcx> {
         span: S,
         msg: &'static str,
     ) -> Region<'tcx> {
-        let reported = tcx.sess.span_delayed_bug(span, msg);
+        let reported = tcx.dcx().span_delayed_bug(span, msg);
         Region::new_error(tcx, reported)
     }
 
@@ -2004,7 +2004,7 @@ impl<'tcx> Ty<'tcx> {
         span: S,
         msg: impl Into<DiagnosticMessage>,
     ) -> Ty<'tcx> {
-        let reported = tcx.sess.span_delayed_bug(span, msg);
+        let reported = tcx.dcx().span_delayed_bug(span, msg);
         Ty::new(tcx, Error(reported))
     }
 
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index d372c1cd60496..58699c934b69b 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -391,7 +391,7 @@ impl<'tcx> TypeckResults<'tcx> {
 
     pub fn extract_binding_mode(&self, s: &Session, id: HirId, sp: Span) -> Option<BindingMode> {
         self.pat_binding_modes().get(id).copied().or_else(|| {
-            s.span_delayed_bug(sp, "missing binding mode");
+            s.dcx().span_delayed_bug(sp, "missing binding mode");
             None
         })
     }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index ab2488f2e9103..55dc72b19d3f4 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -223,8 +223,9 @@ impl<'tcx> TyCtxt<'tcx> {
                     Limit(0) => Limit(2),
                     limit => limit * 2,
                 };
-                let reported =
-                    self.sess.emit_err(crate::error::RecursionLimitReached { ty, suggested_limit });
+                let reported = self
+                    .dcx()
+                    .emit_err(crate::error::RecursionLimitReached { ty, suggested_limit });
                 return Ty::new_error(self, reported);
             }
             match *ty.kind() {
@@ -360,13 +361,13 @@ impl<'tcx> TyCtxt<'tcx> {
             }
 
             let Some(item_id) = self.associated_item_def_ids(impl_did).first() else {
-                self.sess
+                self.dcx()
                     .span_delayed_bug(self.def_span(impl_did), "Drop impl without drop function");
                 return;
             };
 
             if let Some((old_item_id, _)) = dtor_candidate {
-                self.sess
+                self.dcx()
                     .struct_span_err(self.def_span(item_id), "multiple drop impls found")
                     .span_note(self.def_span(old_item_id), "other impl here")
                     .delay_as_bug();
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index e1ce941256c95..1f8978aa8633d 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -55,7 +55,7 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
     }
     fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
         if self.references_error() {
-            if let Some(reported) = ty::tls::with(|tcx| tcx.sess.is_compilation_going_to_fail()) {
+            if let Some(reported) = ty::tls::with(|tcx| tcx.dcx().is_compilation_going_to_fail()) {
                 Err(reported)
             } else {
                 bug!("expect tcx.sess.is_compilation_going_to_fail return `Some`");
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
index 5c9dd18aeacb0..d1a3dbbf5d3b9 100644
--- a/compiler/rustc_middle/src/util/bug.rs
+++ b/compiler/rustc_middle/src/util/bug.rs
@@ -31,8 +31,8 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
     tls::with_opt(move |tcx| {
         let msg = format!("{location}: {args}");
         match (tcx, span) {
-            (Some(tcx), Some(span)) => tcx.sess.dcx().span_bug(span, msg),
-            (Some(tcx), None) => tcx.sess.dcx().bug(msg),
+            (Some(tcx), Some(span)) => tcx.dcx().span_bug(span, msg),
+            (Some(tcx), None) => tcx.dcx().bug(msg),
             (None, _) => panic_any(msg),
         }
     })
@@ -42,7 +42,7 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
 /// `span_delayed_bug`, so what is the point of this? It exists to help us test `span_delayed_bug`'s
 /// interactions with the query system and incremental.
 pub fn trigger_span_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
-    tcx.sess.span_delayed_bug(
+    tcx.dcx().span_delayed_bug(
         tcx.def_span(key),
         "delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]",
     );
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 3224f2f26df5b..b4e45ad568562 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -51,7 +51,7 @@ impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
         {
             sig.decl.inputs.len() + sig.decl.implicit_self.has_implicit_self() as usize
         } else {
-            tcx.sess.abort_if_errors();
+            tcx.dcx().abort_if_errors();
             unreachable!()
         };
 
@@ -191,7 +191,7 @@ pub fn recursive_type_error(
         s
     };
     let mut err = struct_span_err!(
-        tcx.sess,
+        tcx.dcx(),
         err_span,
         E0072,
         "recursive type{} {} {} infinite size",
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index ead20539e2518..c2bff9084c67e 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -92,7 +92,7 @@ pub(super) fn build_custom_mir<'tcx>(
         pctxt.parse_body(expr)?;
     };
     if let Err(err) = res {
-        tcx.sess.dcx().span_fatal(
+        tcx.dcx().span_fatal(
             err.span,
             format!("Could not parse {}, found: {:?}", err.expected, err.item_description),
         )
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 3bfffa7354db0..e77e82d9954e8 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -114,7 +114,7 @@ fn lit_to_mir_constant<'tcx>(
         let width = tcx
             .layout_of(param_ty)
             .map_err(|_| {
-                LitToConstError::Reported(tcx.sess.span_delayed_bug(
+                LitToConstError::Reported(tcx.dcx().span_delayed_bug(
                     DUMMY_SP,
                     format!("couldn't compute width of literal: {:?}", lit_input.lit),
                 ))
@@ -158,7 +158,7 @@ fn lit_to_mir_constant<'tcx>(
         }
         (ast::LitKind::Float(n, _), ty::Float(fty)) => parse_float_into_constval(*n, *fty, neg)
             .ok_or_else(|| {
-                LitToConstError::Reported(tcx.sess.span_delayed_bug(
+                LitToConstError::Reported(tcx.dcx().span_delayed_bug(
                     DUMMY_SP,
                     format!("couldn't parse float literal: {:?}", lit_input.lit),
                 ))
@@ -167,7 +167,7 @@ fn lit_to_mir_constant<'tcx>(
         (ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
         (ast::LitKind::Err, _) => {
             return Err(LitToConstError::Reported(
-                tcx.sess.span_delayed_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
+                tcx.dcx().span_delayed_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
             ));
         }
         _ => return Err(LitToConstError::TypeError),
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 62190848dd55e..133b924c33730 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -470,7 +470,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     if let Some((assigned_ty, assignment_span)) = self.assignment_info {
                         if assigned_ty.needs_drop(self.tcx, self.param_env) {
                             // This would be unsafe, but should be outright impossible since we reject such unions.
-                            self.tcx.sess.span_delayed_bug(assignment_span, format!("union fields that need dropping should be impossible: {assigned_ty}"));
+                            self.tcx.dcx().span_delayed_bug(assignment_span, format!("union fields that need dropping should be impossible: {assigned_ty}"));
                         }
                     } else {
                         self.requires_unsafe(expr.span, AccessToUnionField);
@@ -735,101 +735,93 @@ impl UnsafeOpKind {
             None
         };
 
+        let dcx = tcx.dcx();
         match self {
             CallToUnsafeFunction(Some(did)) if unsafe_op_in_unsafe_fn_allowed => {
-                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                     span,
                     unsafe_not_inherited_note,
                     function: &tcx.def_path_str(*did),
                 });
             }
             CallToUnsafeFunction(Some(did)) => {
-                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafe {
+                dcx.emit_err(CallToUnsafeFunctionRequiresUnsafe {
                     span,
                     unsafe_not_inherited_note,
                     function: &tcx.def_path_str(*did),
                 });
             }
             CallToUnsafeFunction(None) if unsafe_op_in_unsafe_fn_allowed => {
-                tcx.sess.emit_err(
-                    CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed {
-                        span,
-                        unsafe_not_inherited_note,
-                    },
-                );
+                dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed {
+                    span,
+                    unsafe_not_inherited_note,
+                });
             }
             CallToUnsafeFunction(None) => {
-                tcx.sess.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless {
+                dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless {
                     span,
                     unsafe_not_inherited_note,
                 });
             }
             UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
-                tcx.sess.emit_err(UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                dcx.emit_err(UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                     span,
                     unsafe_not_inherited_note,
                 });
             }
             UseOfInlineAssembly => {
-                tcx.sess.emit_err(UseOfInlineAssemblyRequiresUnsafe {
-                    span,
-                    unsafe_not_inherited_note,
-                });
+                dcx.emit_err(UseOfInlineAssemblyRequiresUnsafe { span, unsafe_not_inherited_note });
             }
             InitializingTypeWith if unsafe_op_in_unsafe_fn_allowed => {
-                tcx.sess.emit_err(InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                dcx.emit_err(InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                     span,
                     unsafe_not_inherited_note,
                 });
             }
             InitializingTypeWith => {
-                tcx.sess.emit_err(InitializingTypeWithRequiresUnsafe {
+                dcx.emit_err(InitializingTypeWithRequiresUnsafe {
                     span,
                     unsafe_not_inherited_note,
                 });
             }
             UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => {
-                tcx.sess.emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                dcx.emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                     span,
                     unsafe_not_inherited_note,
                 });
             }
             UseOfMutableStatic => {
-                tcx.sess
-                    .emit_err(UseOfMutableStaticRequiresUnsafe { span, unsafe_not_inherited_note });
+                dcx.emit_err(UseOfMutableStaticRequiresUnsafe { span, unsafe_not_inherited_note });
             }
             UseOfExternStatic if unsafe_op_in_unsafe_fn_allowed => {
-                tcx.sess.emit_err(UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                dcx.emit_err(UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                     span,
                     unsafe_not_inherited_note,
                 });
             }
             UseOfExternStatic => {
-                tcx.sess
-                    .emit_err(UseOfExternStaticRequiresUnsafe { span, unsafe_not_inherited_note });
+                dcx.emit_err(UseOfExternStaticRequiresUnsafe { span, unsafe_not_inherited_note });
             }
             DerefOfRawPointer if unsafe_op_in_unsafe_fn_allowed => {
-                tcx.sess.emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                dcx.emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                     span,
                     unsafe_not_inherited_note,
                 });
             }
             DerefOfRawPointer => {
-                tcx.sess
-                    .emit_err(DerefOfRawPointerRequiresUnsafe { span, unsafe_not_inherited_note });
+                dcx.emit_err(DerefOfRawPointerRequiresUnsafe { span, unsafe_not_inherited_note });
             }
             AccessToUnionField if unsafe_op_in_unsafe_fn_allowed => {
-                tcx.sess.emit_err(AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                dcx.emit_err(AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                     span,
                     unsafe_not_inherited_note,
                 });
             }
             AccessToUnionField => {
-                tcx.sess
-                    .emit_err(AccessToUnionFieldRequiresUnsafe { span, unsafe_not_inherited_note });
+                dcx.emit_err(AccessToUnionFieldRequiresUnsafe { span, unsafe_not_inherited_note });
             }
             MutationOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
-                tcx.sess.emit_err(
+                dcx.emit_err(
                     MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                         span,
                         unsafe_not_inherited_note,
@@ -837,13 +829,13 @@ impl UnsafeOpKind {
                 );
             }
             MutationOfLayoutConstrainedField => {
-                tcx.sess.emit_err(MutationOfLayoutConstrainedFieldRequiresUnsafe {
+                dcx.emit_err(MutationOfLayoutConstrainedFieldRequiresUnsafe {
                     span,
                     unsafe_not_inherited_note,
                 });
             }
             BorrowOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
-                tcx.sess.emit_err(
+                dcx.emit_err(
                     BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                         span,
                         unsafe_not_inherited_note,
@@ -851,7 +843,7 @@ impl UnsafeOpKind {
                 );
             }
             BorrowOfLayoutConstrainedField => {
-                tcx.sess.emit_err(BorrowOfLayoutConstrainedFieldRequiresUnsafe {
+                dcx.emit_err(BorrowOfLayoutConstrainedFieldRequiresUnsafe {
                     span,
                     unsafe_not_inherited_note,
                 });
@@ -859,7 +851,7 @@ impl UnsafeOpKind {
             CallToFunctionWith { function, missing, build_enabled }
                 if unsafe_op_in_unsafe_fn_allowed =>
             {
-                tcx.sess.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
+                dcx.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
                     span,
                     missing_target_features: DiagnosticArgValue::StrListSepByAnd(
                         missing.iter().map(|feature| Cow::from(feature.as_str())).collect(),
@@ -875,7 +867,7 @@ impl UnsafeOpKind {
                 });
             }
             CallToFunctionWith { function, missing, build_enabled } => {
-                tcx.sess.emit_err(CallToFunctionWithRequiresUnsafe {
+                dcx.emit_err(CallToFunctionWithRequiresUnsafe {
                     span,
                     missing_target_features: DiagnosticArgValue::StrListSepByAnd(
                         missing.iter().map(|feature| Cow::from(feature.as_str())).collect(),
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index 240aa10ac918f..3a56b03948ec9 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -16,7 +16,7 @@ pub(crate) fn lit_to_const<'tcx>(
         let width = tcx
             .layout_of(param_ty)
             .map_err(|_| {
-                LitToConstError::Reported(tcx.sess.span_delayed_bug(
+                LitToConstError::Reported(tcx.dcx().span_delayed_bug(
                     DUMMY_SP,
                     format!("couldn't compute width of literal: {:?}", lit_input.lit),
                 ))
@@ -62,7 +62,7 @@ pub(crate) fn lit_to_const<'tcx>(
         (ast::LitKind::Float(n, _), ty::Float(fty)) => {
             let bits = parse_float_into_scalar(*n, *fty, neg)
                 .ok_or_else(|| {
-                    LitToConstError::Reported(tcx.sess.span_delayed_bug(
+                    LitToConstError::Reported(tcx.dcx().span_delayed_bug(
                         DUMMY_SP,
                         format!("couldn't parse float literal: {:?}", lit_input.lit),
                     ))
@@ -73,7 +73,7 @@ pub(crate) fn lit_to_const<'tcx>(
         (ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
         (ast::LitKind::Err, _) => {
             return Err(LitToConstError::Reported(
-                tcx.sess.span_delayed_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
+                tcx.dcx().span_delayed_bug(DUMMY_SP, "encountered LitKind::Err during mir build"),
             ));
         }
         _ => return Err(LitToConstError::TypeError),
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index ab88463826a2b..01f4678fa0963 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -293,7 +293,7 @@ impl<'tcx> Cx<'tcx> {
                     let attrs = tcx.hir().attrs(expr.hir_id);
                     if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_box) {
                         if attrs.len() != 1 {
-                            tcx.sess.emit_err(errors::RustcBoxAttributeError {
+                            tcx.dcx().emit_err(errors::RustcBoxAttributeError {
                                 span: attrs[0].span,
                                 reason: errors::RustcBoxAttrReason::Attributes,
                             });
@@ -312,13 +312,13 @@ impl<'tcx> Cx<'tcx> {
                                     kind: ExprKind::Box { value: self.mirror_expr(value) },
                                 };
                             } else {
-                                tcx.sess.emit_err(errors::RustcBoxAttributeError {
+                                tcx.dcx().emit_err(errors::RustcBoxAttributeError {
                                     span: expr.span,
                                     reason: errors::RustcBoxAttrReason::NotBoxNew,
                                 });
                             }
                         } else {
-                            tcx.sess.emit_err(errors::RustcBoxAttributeError {
+                            tcx.dcx().emit_err(errors::RustcBoxAttributeError {
                                 span: attrs[0].span,
                                 reason: errors::RustcBoxAttrReason::MissingBox,
                             });
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index fcccdf105f649..666b535e20963 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -55,7 +55,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err
 }
 
 fn create_e0004(sess: &Session, sp: Span, error_message: String) -> DiagnosticBuilder<'_> {
-    struct_span_err!(sess, sp, E0004, "{}", &error_message)
+    struct_span_err!(sess.dcx(), sp, E0004, "{}", &error_message)
 }
 
 #[derive(Debug, Copy, Clone, PartialEq)]
@@ -650,7 +650,7 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> {
             false
         };
 
-        self.error = Err(self.tcx.sess.emit_err(PatternNotCovered {
+        self.error = Err(self.tcx.dcx().emit_err(PatternNotCovered {
             span: pat.span,
             origin,
             uncovered: Uncovered::new(pat.span, &cx, witnesses),
@@ -697,7 +697,7 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>,
                 BindingMode::ByRef(_) => conflicts_ref.push(span),
             });
             if !conflicts_ref.is_empty() {
-                sess.emit_err(BorrowOfMovedValue {
+                sess.dcx().emit_err(BorrowOfMovedValue {
                     binding_span: pat.span,
                     conflicts_ref,
                     name,
@@ -754,20 +754,20 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, '_, 'tcx>,
     // Report errors if any.
     if report_mut_mut {
         // Report mutability conflicts for e.g. `ref mut x @ Some(ref mut y)`.
-        sess.emit_err(MultipleMutBorrows { span: pat.span, occurrences });
+        sess.dcx().emit_err(MultipleMutBorrows { span: pat.span, occurrences });
     } else if report_mut_ref {
         // Report mutability conflicts for e.g. `ref x @ Some(ref mut y)` or the converse.
         match mut_outer {
             Mutability::Mut => {
-                sess.emit_err(AlreadyMutBorrowed { span: pat.span, occurrences });
+                sess.dcx().emit_err(AlreadyMutBorrowed { span: pat.span, occurrences });
             }
             Mutability::Not => {
-                sess.emit_err(AlreadyBorrowed { span: pat.span, occurrences });
+                sess.dcx().emit_err(AlreadyBorrowed { span: pat.span, occurrences });
             }
         };
     } else if report_move_conflict {
         // Report by-ref and by-move conflicts, e.g. `ref x @ y`.
-        sess.emit_err(MovedWhileBorrowed { span: pat.span, occurrences });
+        sess.dcx().emit_err(MovedWhileBorrowed { span: pat.span, occurrences });
     }
 }
 
@@ -905,7 +905,7 @@ fn report_non_exhaustive_match<'p, 'tcx>(
     let pattern;
     let patterns_len;
     if is_empty_match && !non_empty_enum {
-        return cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
+        return cx.tcx.dcx().emit_err(NonExhaustivePatternsTypeNotEmpty {
             cx,
             expr_span,
             span: sp,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index a7f2377219304..5631a38d0f0db 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -185,16 +185,16 @@ impl<'tcx> ConstToPat<'tcx> {
                     let e = if let ty::Adt(def, ..) = non_sm_ty.kind() {
                         if def.is_union() {
                             let err = UnionPattern { span: self.span };
-                            self.tcx().sess.emit_err(err)
+                            self.tcx().dcx().emit_err(err)
                         } else {
                             // fatal avoids ICE from resolution of nonexistent method (rare case).
                             self.tcx()
-                                .sess
+                                .dcx()
                                 .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty })
                         }
                     } else {
                         let err = InvalidPattern { span: self.span, non_sm_ty };
-                        self.tcx().sess.emit_err(err)
+                        self.tcx().dcx().emit_err(err)
                     };
                     // All branches above emitted an error. Don't print any more lints.
                     // We errored. Signal that in the pattern, so that follow up errors can be silenced.
@@ -207,7 +207,7 @@ impl<'tcx> ConstToPat<'tcx> {
                     // This is because `mir::Const::ty` has already been handled by `Self::recur`
                     // and the invalid types may be ignored.
                     let err = TypeNotStructural { span: self.span, non_sm_ty };
-                    let e = self.tcx().sess.emit_err(err);
+                    let e = self.tcx().dcx().emit_err(err);
                     let kind = PatKind::Error(e);
                     return Box::new(Pat { span: self.span, ty: cv.ty(), kind });
                 } else if !self.saw_const_match_lint.get() {
@@ -352,7 +352,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 return Err(FallbackToOpaqueConst);
             }
             ty::FnDef(..) => {
-                let e = tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty });
+                let e = tcx.dcx().emit_err(InvalidPattern { span, non_sm_ty: ty });
                 self.saw_const_match_error.set(Some(e));
                 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
                 PatKind::Error(e)
@@ -360,7 +360,7 @@ impl<'tcx> ConstToPat<'tcx> {
             ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
                 debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,);
                 let err = TypeNotStructural { span, non_sm_ty: ty };
-                let e = tcx.sess.emit_err(err);
+                let e = tcx.dcx().emit_err(err);
                 self.saw_const_match_error.set(Some(e));
                 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
                 PatKind::Error(e)
@@ -449,7 +449,7 @@ impl<'tcx> ConstToPat<'tcx> {
                             PatKind::Error(e)
                         } else {
                             let err = TypeNotStructural { span, non_sm_ty: *pointee_ty };
-                            let e = tcx.sess.emit_err(err);
+                            let e = tcx.dcx().emit_err(err);
                             self.saw_const_match_error.set(Some(e));
                             // We errored. Signal that in the pattern, so that follow up errors can be silenced.
                             PatKind::Error(e)
@@ -462,7 +462,7 @@ impl<'tcx> ConstToPat<'tcx> {
                 _ => {
                     if !pointee_ty.is_sized(tcx, param_env) && !pointee_ty.is_slice() {
                         let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
-                        let e = tcx.sess.emit_err(err);
+                        let e = tcx.dcx().emit_err(err);
                         // We errored. Signal that in the pattern, so that follow up errors can be silenced.
                         PatKind::Error(e)
                     } else {
@@ -498,7 +498,7 @@ impl<'tcx> ConstToPat<'tcx> {
             }
             _ => {
                 let err = InvalidPattern { span, non_sm_ty: ty };
-                let e = tcx.sess.emit_err(err);
+                let e = tcx.dcx().emit_err(err);
                 self.saw_const_match_error.set(Some(e));
                 // We errored. Signal that in the pattern, so that follow up errors can be silenced.
                 PatKind::Error(e)
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index c7762f8ce4e32..c4987634b78b3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -105,7 +105,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     let msg = format!(
                         "found bad range pattern endpoint `{expr:?}` outside of error recovery"
                     );
-                    return Err(self.tcx.sess.span_delayed_bug(expr.span, msg));
+                    return Err(self.tcx.dcx().span_delayed_bug(expr.span, msg));
                 };
                 Ok((Some(PatRangeBoundary::Finite(value)), ascr, inline_const))
             }
@@ -160,7 +160,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         // Detect literal value out of range `[min, max]` inclusive, avoiding use of `-min` to
         // prevent overflow/panic.
         if (negated && lit_val > max + 1) || (!negated && lit_val > max) {
-            return Err(self.tcx.sess.emit_err(LiteralOutOfRange { span, ty, min, max }));
+            return Err(self.tcx.dcx().emit_err(LiteralOutOfRange { span, ty, min, max }));
         }
         Ok(())
     }
@@ -175,7 +175,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     ) -> Result<PatKind<'tcx>, ErrorGuaranteed> {
         if lo_expr.is_none() && hi_expr.is_none() {
             let msg = "found twice-open range pattern (`..`) outside of error recovery";
-            return Err(self.tcx.sess.span_delayed_bug(span, msg));
+            return Err(self.tcx.dcx().span_delayed_bug(span, msg));
         }
 
         let (lo, lo_ascr, lo_inline) = self.lower_pattern_range_endpoint(lo_expr)?;
@@ -207,13 +207,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 self.error_on_literal_overflow(hi_expr, ty)?;
                 let e = match end {
                     RangeEnd::Included => {
-                        self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
+                        self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanOrEqualToUpper {
                             span,
                             teach: self.tcx.sess.teach(&error_code!(E0030)).then_some(()),
                         })
                     }
                     RangeEnd::Excluded => {
-                        self.tcx.sess.emit_err(LowerRangeBoundMustBeLessThanUpper { span })
+                        self.tcx.dcx().emit_err(LowerRangeBoundMustBeLessThanUpper { span })
                     }
                 };
                 return Err(e);
@@ -454,12 +454,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             _ => {
                 let e = match res {
                     Res::Def(DefKind::ConstParam, _) => {
-                        self.tcx.sess.emit_err(ConstParamInPattern { span })
+                        self.tcx.dcx().emit_err(ConstParamInPattern { span })
                     }
                     Res::Def(DefKind::Static(_), _) => {
-                        self.tcx.sess.emit_err(StaticInPattern { span })
+                        self.tcx.dcx().emit_err(StaticInPattern { span })
                     }
-                    _ => self.tcx.sess.emit_err(NonConstPath { span }),
+                    _ => self.tcx.dcx().emit_err(NonConstPath { span }),
                 };
                 PatKind::Error(e)
             }
@@ -513,12 +513,12 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 // It should be assoc consts if there's no error but we cannot resolve it.
                 debug_assert!(is_associated_const);
 
-                let e = self.tcx.sess.emit_err(AssocConstInPattern { span });
+                let e = self.tcx.dcx().emit_err(AssocConstInPattern { span });
                 return pat_from_kind(PatKind::Error(e));
             }
 
             Err(_) => {
-                let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
+                let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span });
                 return pat_from_kind(PatKind::Error(e));
             }
         };
@@ -573,11 +573,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
             Err(ErrorHandled::TooGeneric(_)) => {
                 // While `Reported | Linted` cases will have diagnostics emitted already
                 // it is not true for TooGeneric case, so we need to give user more information.
-                let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
+                let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span });
                 pat_from_kind(PatKind::Error(e))
             }
             Err(_) => {
-                let e = self.tcx.sess.emit_err(CouldNotEvalConstPattern { span });
+                let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span });
                 pat_from_kind(PatKind::Error(e))
             }
         }
@@ -646,7 +646,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                 Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind,
                 Err(ErrorHandled::TooGeneric(_)) => {
                     // If we land here it means the const can't be evaluated because it's `TooGeneric`.
-                    let e = self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
+                    let e = self.tcx.dcx().emit_err(ConstPatternDependsOnGenericParameter { span });
                     PatKind::Error(e)
                 }
                 Err(ErrorHandled::Reported(err, ..)) => PatKind::Error(err.into()),
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 784872c7ed7d8..44a7dcc82775b 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -344,7 +344,7 @@ impl RustcMirAttrs {
                     match path.file_name() {
                         Some(_) => Ok(path),
                         None => {
-                            tcx.sess.emit_err(PathMustEndInFilename { span: attr.span() });
+                            tcx.dcx().emit_err(PathMustEndInFilename { span: attr.span() });
                             Err(())
                         }
                     }
@@ -353,7 +353,7 @@ impl RustcMirAttrs {
                 Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
                     sym::gen_kill | sym::two_phase => Ok(s),
                     _ => {
-                        tcx.sess.emit_err(UnknownFormatter { span: attr.span() });
+                        tcx.dcx().emit_err(UnknownFormatter { span: attr.span() });
                         Err(())
                     }
                 })
@@ -374,7 +374,8 @@ impl RustcMirAttrs {
         mapper: impl FnOnce(Symbol) -> Result<T, ()>,
     ) -> Result<(), ()> {
         if field.is_some() {
-            tcx.sess.emit_err(DuplicateValuesFor { span: attr.span(), name: attr.name_or_empty() });
+            tcx.dcx()
+                .emit_err(DuplicateValuesFor { span: attr.span(), name: attr.name_or_empty() });
 
             return Err(());
         }
@@ -383,7 +384,8 @@ impl RustcMirAttrs {
             *field = Some(mapper(s)?);
             Ok(())
         } else {
-            tcx.sess.emit_err(RequiresAnArgument { span: attr.span(), name: attr.name_or_empty() });
+            tcx.dcx()
+                .emit_err(RequiresAnArgument { span: attr.span(), name: attr.name_or_empty() });
             Err(())
         }
     }
diff --git a/compiler/rustc_mir_dataflow/src/rustc_peek.rs b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
index 448128b6993fc..5373876d1c2c7 100644
--- a/compiler/rustc_mir_dataflow/src/rustc_peek.rs
+++ b/compiler/rustc_mir_dataflow/src/rustc_peek.rs
@@ -80,7 +80,7 @@ impl<'tcx> MirPass<'tcx> for SanityCheck {
         }
 
         if has_rustc_mir_with(tcx, def_id, sym::stop_after_dataflow).is_some() {
-            tcx.sess.emit_fatal(StopAfterDataFlowEndedCompilation);
+            tcx.dcx().emit_fatal(StopAfterDataFlowEndedCompilation);
         }
     }
 }
@@ -145,7 +145,7 @@ where
             }
 
             _ => {
-                tcx.sess.emit_err(PeekMustBePlaceOrRefPlace { span: call.span });
+                tcx.dcx().emit_err(PeekMustBePlaceOrRefPlace { span: call.span });
             }
         }
     }
@@ -214,12 +214,12 @@ impl PeekCall {
                         if let Some(local) = place.as_local() {
                             local
                         } else {
-                            tcx.sess.emit_err(PeekMustBeNotTemporary { span });
+                            tcx.dcx().emit_err(PeekMustBeNotTemporary { span });
                             return None;
                         }
                     }
                     _ => {
-                        tcx.sess.emit_err(PeekMustBeNotTemporary { span });
+                        tcx.dcx().emit_err(PeekMustBeNotTemporary { span });
                         return None;
                     }
                 };
@@ -259,12 +259,12 @@ where
                 let bit_state = flow_state.contains(peek_mpi);
                 debug!("rustc_peek({:?} = &{:?}) bit_state: {}", call.arg, place, bit_state);
                 if !bit_state {
-                    tcx.sess.emit_err(PeekBitNotSet { span: call.span });
+                    tcx.dcx().emit_err(PeekBitNotSet { span: call.span });
                 }
             }
 
             LookupResult::Parent(..) => {
-                tcx.sess.emit_err(PeekArgumentUntracked { span: call.span });
+                tcx.dcx().emit_err(PeekArgumentUntracked { span: call.span });
             }
         }
     }
@@ -280,12 +280,12 @@ impl<'tcx> RustcPeekAt<'tcx> for MaybeLiveLocals {
     ) {
         info!(?place, "peek_at");
         let Some(local) = place.as_local() else {
-            tcx.sess.emit_err(PeekArgumentNotALocal { span: call.span });
+            tcx.dcx().emit_err(PeekArgumentNotALocal { span: call.span });
             return;
         };
 
         if !flow_state.contains(local) {
-            tcx.sess.emit_err(PeekBitNotSet { span: call.span });
+            tcx.dcx().emit_err(PeekBitNotSet { span: call.span });
         }
     }
 }
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index 77bcba50a3cd4..a405ed6088d82 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -52,7 +52,7 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
                     );
                 } else {
                     self.tcx
-                        .sess
+                        .dcx()
                         .emit_err(errors::UnalignedPackedRef { span: self.source_info.span });
                 }
             }
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index f246de55ca894..23726e49f4dd6 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -242,7 +242,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
                     let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty;
                     if assigned_ty.needs_drop(self.tcx, self.param_env) {
                         // This would be unsafe, but should be outright impossible since we reject such unions.
-                        self.tcx.sess.span_delayed_bug(
+                        self.tcx.dcx().span_delayed_bug(
                             self.source_info.span,
                             format!("union fields that need dropping should be impossible: {assigned_ty}")
                         );
@@ -568,7 +568,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                 } else {
                     None
                 };
-                tcx.sess.emit_err(errors::RequiresUnsafe {
+                tcx.dcx().emit_err(errors::RequiresUnsafe {
                     span: source_info.span,
                     enclosing,
                     details,
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 6da102dcb1c61..d1d5b72af7063 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -1604,7 +1604,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
                 (args.discr_ty(tcx), movability == hir::Movability::Movable)
             }
             _ => {
-                tcx.sess.span_delayed_bug(
+                tcx.dcx().span_delayed_bug(
                     body.span,
                     format!("unexpected coroutine type {coroutine_ty}"),
                 );
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index c45badbc559cd..8575f552f0ae7 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -315,7 +315,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                     self.init_data.seek_before(self.body.terminator_loc(bb));
                     let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent);
                     if maybe_dead {
-                        self.tcx.sess.span_delayed_bug(
+                        self.tcx.dcx().span_delayed_bug(
                             terminator.source_info.span,
                             format!(
                                 "drop of untracked, uninitialized value {bb:?}, place {place:?} ({path:?})"
@@ -380,7 +380,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
                 LookupResult::Parent(None) => {}
                 LookupResult::Parent(Some(_)) => {
                     if !replace {
-                        self.tcx.sess.span_delayed_bug(
+                        self.tcx.dcx().span_delayed_bug(
                             terminator.source_info.span,
                             format!("drop of untracked value {bb:?}"),
                         );
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 98d4d96d0c76c..9d03bab48448d 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -267,7 +267,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
     let body = &tcx.mir_const(def).borrow();
 
     if body.return_ty().references_error() {
-        tcx.sess.span_delayed_bug(body.span, "mir_const_qualif: MIR had errors");
+        tcx.dcx().span_delayed_bug(body.span, "mir_const_qualif: MIR had errors");
         return Default::default();
     }
 
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index a68bfcd06d505..54464600d99a8 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -371,7 +371,7 @@ fn collect_items_rec<'tcx>(
     // current step of mono items collection.
     //
     // FIXME: don't rely on global state, instead bubble up errors. Note: this is very hard to do.
-    let error_count = tcx.sess.dcx().err_count();
+    let error_count = tcx.dcx().err_count();
 
     match starting_item.node {
         MonoItem::Static(def_id) => {
@@ -459,12 +459,12 @@ fn collect_items_rec<'tcx>(
 
     // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the
     // mono item graph.
-    if tcx.sess.dcx().err_count() > error_count
+    if tcx.dcx().err_count() > error_count
         && starting_item.node.is_generic_fn(tcx)
         && starting_item.node.is_user_defined()
     {
         let formatted_item = with_no_trimmed_paths!(starting_item.node.to_string());
-        tcx.sess.emit_note(EncounteredErrorWhileInstantiating {
+        tcx.dcx().emit_note(EncounteredErrorWhileInstantiating {
             span: starting_item.span,
             formatted_item,
         });
@@ -541,7 +541,7 @@ fn check_recursion_limit<'tcx>(
         } else {
             None
         };
-        tcx.sess.emit_fatal(RecursionLimit {
+        tcx.dcx().emit_fatal(RecursionLimit {
             span,
             shrunk,
             def_span,
@@ -584,7 +584,7 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
         } else {
             None
         };
-        tcx.sess.emit_fatal(TypeLengthLimit { span, shrunk, was_written, path, type_length });
+        tcx.dcx().emit_fatal(TypeLengthLimit { span, shrunk, was_written, path, type_length });
     }
 }
 
@@ -997,7 +997,7 @@ fn should_codegen_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) ->
     }
 
     if !tcx.is_mir_available(def_id) {
-        tcx.sess.emit_fatal(NoOptimizedMir {
+        tcx.dcx().emit_fatal(NoOptimizedMir {
             span: tcx.def_span(def_id),
             crate_name: tcx.crate_name(def_id.krate),
         });
diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs
index d47d3e5e7d3b5..08e628408394e 100644
--- a/compiler/rustc_monomorphize/src/partitioning.rs
+++ b/compiler/rustc_monomorphize/src/partitioning.rs
@@ -1079,7 +1079,7 @@ where
                 (span1, span2) => span1.or(span2),
             };
 
-            tcx.sess.emit_fatal(SymbolAlreadyDefined { span, symbol: sym1.to_string() });
+            tcx.dcx().emit_fatal(SymbolAlreadyDefined { span, symbol: sym1.to_string() });
         }
     }
 }
@@ -1093,7 +1093,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co
                 MonoItemCollectionMode::Eager
             } else {
                 if mode != "lazy" {
-                    tcx.sess.emit_warning(UnknownCguCollectionMode { mode });
+                    tcx.dcx().emit_warning(UnknownCguCollectionMode { mode });
                 }
 
                 MonoItemCollectionMode::Lazy
@@ -1110,7 +1110,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co
 
     let (items, usage_map) = collector::collect_crate_mono_items(tcx, collection_mode);
 
-    tcx.sess.abort_if_errors();
+    tcx.dcx().abort_if_errors();
 
     let (codegen_units, _) = tcx.sess.time("partition_and_assert_distinct_symbols", || {
         sync::join(
@@ -1148,7 +1148,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co
         if let Err(err) =
             dump_mono_items_stats(tcx, codegen_units, path, tcx.crate_name(LOCAL_CRATE))
         {
-            tcx.sess.emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
+            tcx.dcx().emit_fatal(CouldntDumpMonoStats { error: err.to_string() });
         }
     }
 
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 91abbb216d662..009bd0b97b605 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -215,7 +215,7 @@ fn emit_unused_generic_params_error<'tcx>(
         next_generics = generics.parent.map(|did| tcx.generics_of(did));
     }
 
-    tcx.sess.emit_err(UnusedGenericParamsHint { span: fn_span, param_spans, param_names });
+    tcx.dcx().emit_err(UnusedGenericParamsHint { span: fn_span, param_spans, param_names });
 }
 
 /// Visitor used to aggregate generic parameter uses.
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 59bc0eeb1c5b6..083d1984e0031 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -8,7 +8,7 @@ use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
 use rustc_ast::tokenstream::TokenStream;
 use rustc_ast::util::unicode::contains_text_flow_control_chars;
 use rustc_errors::{
-    error_code, Applicability, Diagnostic, DiagnosticBuilder, FatalAbort, StashKey,
+    error_code, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, FatalAbort, StashKey,
 };
 use rustc_lexer::unescape::{self, EscapeError, Mode};
 use rustc_lexer::{Base, DocStyle, RawStrError};
@@ -110,6 +110,10 @@ struct StringReader<'a> {
 }
 
 impl<'a> StringReader<'a> {
+    pub fn dcx(&self) -> &'a DiagCtxt {
+        &self.sess.dcx
+    }
+
     fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span {
         self.override_span.unwrap_or_else(|| Span::with_root_ctxt(lo, hi))
     }
@@ -176,7 +180,7 @@ impl<'a> StringReader<'a> {
                     let span = self.mk_sp(start, self.pos);
                     self.sess.symbol_gallery.insert(sym, span);
                     if !sym.can_be_raw() {
-                        self.sess.emit_err(errors::CannotBeRawIdent { span, ident: sym });
+                        self.dcx().emit_err(errors::CannotBeRawIdent { span, ident: sym });
                     }
                     self.sess.raw_identifier_spans.push(span);
                     token::Ident(sym, true)
@@ -247,7 +251,7 @@ impl<'a> StringReader<'a> {
                     let lifetime_name = self.str_from(start);
                     if starts_with_number {
                         let span = self.mk_sp(start, self.pos);
-                        let mut diag = self.sess.struct_err("lifetimes cannot start with a number");
+                        let mut diag = self.dcx().struct_err("lifetimes cannot start with a number");
                         diag.set_span(span);
                         diag.stash(span, StashKey::LifetimeIsChar);
                     }
@@ -308,7 +312,7 @@ impl<'a> StringReader<'a> {
                     // fancier error recovery to it, as there will be less overall work to do this
                     // way.
                     let (token, sugg) = unicode_chars::check_for_substitution(self, start, c, repeats+1);
-                    self.sess.emit_err(errors::UnknownTokenStart {
+                    self.dcx().emit_err(errors::UnknownTokenStart {
                         span: self.mk_sp(start, self.pos + Pos::from_usize(repeats * c.len_utf8())),
                         escaped: escaped_char(c),
                         sugg,
@@ -384,7 +388,7 @@ impl<'a> StringReader<'a> {
                     content_start + BytePos(idx as u32 + 1),
                 );
                 let block = matches!(comment_kind, CommentKind::Block);
-                self.sess.emit_err(errors::CrDocComment { span, block });
+                self.dcx().emit_err(errors::CrDocComment { span, block });
             }
         }
 
@@ -405,7 +409,7 @@ impl<'a> StringReader<'a> {
         match kind {
             rustc_lexer::LiteralKind::Char { terminated } => {
                 if !terminated {
-                    self.sess.dcx.span_fatal_with_code(
+                    self.dcx().span_fatal_with_code(
                         self.mk_sp(start, end),
                         "unterminated character literal",
                         error_code!(E0762),
@@ -415,7 +419,7 @@ impl<'a> StringReader<'a> {
             }
             rustc_lexer::LiteralKind::Byte { terminated } => {
                 if !terminated {
-                    self.sess.dcx.span_fatal_with_code(
+                    self.dcx().span_fatal_with_code(
                         self.mk_sp(start + BytePos(1), end),
                         "unterminated byte constant",
                         error_code!(E0763),
@@ -425,7 +429,7 @@ impl<'a> StringReader<'a> {
             }
             rustc_lexer::LiteralKind::Str { terminated } => {
                 if !terminated {
-                    self.sess.dcx.span_fatal_with_code(
+                    self.dcx().span_fatal_with_code(
                         self.mk_sp(start, end),
                         "unterminated double quote string",
                         error_code!(E0765),
@@ -435,7 +439,7 @@ impl<'a> StringReader<'a> {
             }
             rustc_lexer::LiteralKind::ByteStr { terminated } => {
                 if !terminated {
-                    self.sess.dcx.span_fatal_with_code(
+                    self.dcx().span_fatal_with_code(
                         self.mk_sp(start + BytePos(1), end),
                         "unterminated double quote byte string",
                         error_code!(E0766),
@@ -445,7 +449,7 @@ impl<'a> StringReader<'a> {
             }
             rustc_lexer::LiteralKind::CStr { terminated } => {
                 if !terminated {
-                    self.sess.dcx.span_fatal_with_code(
+                    self.dcx().span_fatal_with_code(
                         self.mk_sp(start + BytePos(1), end),
                         "unterminated C string",
                         error_code!(E0767),
@@ -483,7 +487,7 @@ impl<'a> StringReader<'a> {
             rustc_lexer::LiteralKind::Int { base, empty_int } => {
                 if empty_int {
                     let span = self.mk_sp(start, end);
-                    self.sess.emit_err(errors::NoDigitsLiteral { span });
+                    self.dcx().emit_err(errors::NoDigitsLiteral { span });
                     (token::Integer, sym::integer(0))
                 } else {
                     if matches!(base, Base::Binary | Base::Octal) {
@@ -495,7 +499,7 @@ impl<'a> StringReader<'a> {
                                 start + BytePos::from_usize(2 + idx + c.len_utf8()),
                             );
                             if c != '_' && c.to_digit(base).is_none() {
-                                self.sess.emit_err(errors::InvalidDigitLiteral { span, base });
+                                self.dcx().emit_err(errors::InvalidDigitLiteral { span, base });
                             }
                         }
                     }
@@ -505,7 +509,7 @@ impl<'a> StringReader<'a> {
             rustc_lexer::LiteralKind::Float { base, empty_exponent } => {
                 if empty_exponent {
                     let span = self.mk_sp(start, self.pos);
-                    self.sess.emit_err(errors::EmptyExponentFloat { span });
+                    self.dcx().emit_err(errors::EmptyExponentFloat { span });
                 }
                 let base = match base {
                     Base::Hexadecimal => Some("hexadecimal"),
@@ -515,7 +519,7 @@ impl<'a> StringReader<'a> {
                 };
                 if let Some(base) = base {
                     let span = self.mk_sp(start, end);
-                    self.sess.emit_err(errors::FloatLiteralUnsupportedBase { span, base });
+                    self.dcx().emit_err(errors::FloatLiteralUnsupportedBase { span, base });
                 }
                 (token::Float, self.symbol_from_to(start, end))
             }
@@ -580,7 +584,7 @@ impl<'a> StringReader<'a> {
         possible_offset: Option<u32>,
         found_terminators: u32,
     ) -> ! {
-        let mut err = self.sess.dcx.struct_span_fatal_with_code(
+        let mut err = self.dcx().struct_span_fatal_with_code(
             self.mk_sp(start, start),
             "unterminated raw string",
             error_code!(E0748),
@@ -616,7 +620,7 @@ impl<'a> StringReader<'a> {
             None => "unterminated block comment",
         };
         let last_bpos = self.pos;
-        let mut err = self.sess.dcx.struct_span_fatal_with_code(
+        let mut err = self.dcx().struct_span_fatal_with_code(
             self.mk_sp(start, last_bpos),
             msg,
             error_code!(E0758),
@@ -678,7 +682,7 @@ impl<'a> StringReader<'a> {
             } else {
                 None
             };
-            self.sess.emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg });
+            self.dcx().emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg });
         } else {
             // Before Rust 2021, only emit a lint for migration.
             self.sess.buffer_lint_with_diagnostic(
@@ -692,7 +696,7 @@ impl<'a> StringReader<'a> {
     }
 
     fn report_too_many_hashes(&self, start: BytePos, num: u32) -> ! {
-        self.sess.emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num });
+        self.dcx().emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num });
     }
 
     fn cook_common(
@@ -721,7 +725,7 @@ impl<'a> StringReader<'a> {
                     has_fatal_err = true;
                 }
                 emit_unescape_error(
-                    &self.sess.dcx,
+                    self.dcx(),
                     lit_content,
                     span_with_quotes,
                     span,
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index 2bc2789a4f761..b6cccd275ee65 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -257,7 +257,7 @@ impl<'a> TokenTreesReader<'a> {
                     // This might be the beginning of the `if`/`while` body (i.e., the end of the condition)
                     in_cond = false;
                 } else if maybe_andand == token::AndAnd && maybe_let.is_keyword(kw::Let) {
-                    let mut err = parser.struct_span_err(
+                    let mut err = parser.dcx().struct_span_err(
                         parser.token.span,
                         "found a `{` in the middle of a let-chain",
                     );
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 82b0ff70c162c..f06aeed8628b8 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -263,5 +263,5 @@ const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
     #the-cfg_attr-attribute>";
 
 fn error_malformed_cfg_attr_missing(span: Span, parse_sess: &ParseSess) {
-    parse_sess.emit_err(errors::MalformedCfgAttr { span, sugg: CFG_ATTR_GRAMMAR_HELP });
+    parse_sess.dcx.emit_err(errors::MalformedCfgAttr { span, sugg: CFG_ATTR_GRAMMAR_HELP });
 }
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 53b29eccc2cd5..fb8ad05f25df7 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -200,7 +200,7 @@ impl<'a> Parser<'a> {
         if let InnerAttrPolicy::Forbidden(reason) = policy {
             let mut diag = match reason.as_ref().copied() {
                 Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => {
-                    let mut diag = self.struct_span_err(
+                    let mut diag = self.dcx().struct_span_err(
                         attr_sp,
                         fluent::parse_inner_attr_not_permitted_after_outer_doc_comment,
                     );
@@ -209,7 +209,7 @@ impl<'a> Parser<'a> {
                     diag
                 }
                 Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => {
-                    let mut diag = self.struct_span_err(
+                    let mut diag = self.dcx().struct_span_err(
                         attr_sp,
                         fluent::parse_inner_attr_not_permitted_after_outer_attr,
                     );
@@ -218,7 +218,7 @@ impl<'a> Parser<'a> {
                     diag
                 }
                 Some(InnerAttrForbiddenReason::InCodeBlock) | None => {
-                    self.struct_span_err(attr_sp, fluent::parse_inner_attr_not_permitted)
+                    self.dcx().struct_span_err(attr_sp, fluent::parse_inner_attr_not_permitted)
                 }
             };
 
@@ -323,7 +323,7 @@ impl<'a> Parser<'a> {
         debug!("checking if {:?} is unsuffixed", lit);
 
         if !lit.kind.is_unsuffixed() {
-            self.sess.emit_err(SuffixedLiteralInAttribute { span: lit.span });
+            self.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span });
         }
 
         Ok(lit)
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 4d557e495d8d4..226bf60c45e46 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -34,8 +34,8 @@ use rustc_ast::{
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
-    pluralize, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder,
-    DiagnosticMessage, FatalError, MultiSpan, PResult,
+    pluralize, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder, FatalError,
+    PResult,
 };
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
@@ -239,21 +239,7 @@ impl<'a> DerefMut for SnapshotParser<'a> {
 }
 
 impl<'a> Parser<'a> {
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_span_err<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        m: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'a> {
-        self.dcx().struct_span_err(sp, m)
-    }
-
-    pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.dcx().span_bug(sp, msg)
-    }
-
-    pub(super) fn dcx(&self) -> &'a DiagCtxt {
+    pub fn dcx(&self) -> &'a DiagCtxt {
         &self.sess.dcx
     }
 
@@ -538,7 +524,7 @@ impl<'a> Parser<'a> {
                 //
                 //   let x = 32:
                 //   let y = 42;
-                self.sess.emit_err(ExpectedSemi {
+                self.dcx().emit_err(ExpectedSemi {
                     span: self.token.span,
                     token: self.token.clone(),
                     unexpected_token_label: None,
@@ -563,7 +549,7 @@ impl<'a> Parser<'a> {
                 //   let x = 32
                 //   let y = 42;
                 let span = self.prev_token.span.shrink_to_hi();
-                self.sess.emit_err(ExpectedSemi {
+                self.dcx().emit_err(ExpectedSemi {
                     span,
                     token: self.token.clone(),
                     unexpected_token_label: Some(self.token.span),
@@ -578,13 +564,13 @@ impl<'a> Parser<'a> {
             && expected.iter().any(|tok| matches!(tok, TokenType::Token(TokenKind::Eq)))
         {
             // Likely typo: `=` → `==` in let expr or enum item
-            return Err(self.sess.create_err(UseEqInstead { span: self.token.span }));
+            return Err(self.dcx().create_err(UseEqInstead { span: self.token.span }));
         }
 
         if self.token.is_keyword(kw::Move) && self.prev_token.is_keyword(kw::Async) {
             // The 2015 edition is in use because parsing of `async move` has failed.
             let span = self.prev_token.span.to(self.token.span);
-            return Err(self.sess.create_err(AsyncMoveBlockIn2015 { span }));
+            return Err(self.dcx().create_err(AsyncMoveBlockIn2015 { span }));
         }
 
         let expect = tokens_to_string(&expected);
@@ -610,7 +596,7 @@ impl<'a> Parser<'a> {
         };
         self.last_unexpected_token_span = Some(self.token.span);
         // FIXME: translation requires list formatting (for `expect`)
-        let mut err = self.struct_span_err(self.token.span, msg_exp);
+        let mut err = self.dcx().struct_span_err(self.token.span, msg_exp);
 
         if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
             if ["def", "fun", "func", "function"].contains(&symbol.as_str()) {
@@ -738,7 +724,7 @@ impl<'a> Parser<'a> {
     pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) {
         // Missing semicolon typo error.
         let span = self.prev_token.span.shrink_to_hi();
-        let mut err = self.sess.create_err(ExpectedSemi {
+        let mut err = self.dcx().create_err(ExpectedSemi {
             span,
             token: self.token.clone(),
             unexpected_token_label: Some(self.token.span),
@@ -915,7 +901,7 @@ impl<'a> Parser<'a> {
                         if let Ok(extend_before) = sm.span_extend_prev_while(before, |t| {
                             t.is_alphanumeric() || t == ':' || t == '_'
                         }) {
-                            Err(self.sess.create_err(StructLiteralNeedingParens {
+                            Err(self.dcx().create_err(StructLiteralNeedingParens {
                                 span: maybe_struct_name.span.to(expr.span),
                                 sugg: StructLiteralNeedingParensSugg {
                                     before: extend_before.shrink_to_lo(),
@@ -926,7 +912,7 @@ impl<'a> Parser<'a> {
                             return None;
                         }
                     } else {
-                        self.sess.emit_err(StructLiteralBodyWithoutPath {
+                        self.dcx().emit_err(StructLiteralBodyWithoutPath {
                             span: expr.span,
                             sugg: StructLiteralBodyWithoutPathSugg {
                                 before: expr.span.shrink_to_lo(),
@@ -1131,7 +1117,7 @@ impl<'a> Parser<'a> {
             let span = lo.until(self.token.span);
 
             let num_extra_brackets = number_of_gt + number_of_shr * 2;
-            self.sess.emit_err(UnmatchedAngleBrackets { span, num_extra_brackets });
+            self.dcx().emit_err(UnmatchedAngleBrackets { span, num_extra_brackets });
             return true;
         }
         false
@@ -1163,7 +1149,7 @@ impl<'a> Parser<'a> {
                         // Recover from bad turbofish: `foo.collect::Vec<_>()`.
                         segment.args = Some(AngleBracketedArgs { args, span }.into());
 
-                        self.sess.emit_err(GenericParamsWithoutAngleBrackets {
+                        self.dcx().emit_err(GenericParamsWithoutAngleBrackets {
                             span,
                             sugg: GenericParamsWithoutAngleBracketsSugg {
                                 left: span.shrink_to_lo(),
@@ -1417,7 +1403,7 @@ impl<'a> Parser<'a> {
                         match self.parse_expr() {
                             Ok(_) => {
                                 // 99% certain that the suggestion is correct, continue parsing.
-                                self.sess.emit_err(err);
+                                self.dcx().emit_err(err);
                                 // FIXME: actually check that the two expressions in the binop are
                                 // paths and resynthesize new fn call expression instead of using
                                 // `ExprKind::Err` placeholder.
@@ -1445,7 +1431,7 @@ impl<'a> Parser<'a> {
                         match self.consume_fn_args() {
                             Err(()) => Err(self.dcx().create_err(err)),
                             Ok(()) => {
-                                self.sess.emit_err(err);
+                                self.dcx().emit_err(err);
                                 // FIXME: actually check that the two expressions in the binop are
                                 // paths and resynthesize new fn call expression instead of using
                                 // `ExprKind::Err` placeholder.
@@ -1465,7 +1451,7 @@ impl<'a> Parser<'a> {
                         // misformatted turbofish, for instance), suggest a correct form.
                         if self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op)
                         {
-                            self.sess.emit_err(err);
+                            self.dcx().emit_err(err);
                             mk_err_expr(self, inner_op.span.to(self.prev_token.span))
                         } else {
                             // These cases cause too many knock-down errors, bail out (#61329).
@@ -1475,7 +1461,7 @@ impl<'a> Parser<'a> {
                 }
                 let recover =
                     self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
-                self.sess.emit_err(err);
+                self.dcx().emit_err(err);
                 if recover {
                     return mk_err_expr(self, inner_op.span.to(self.prev_token.span));
                 }
@@ -1508,7 +1494,7 @@ impl<'a> Parser<'a> {
 
     pub(super) fn maybe_report_ambiguous_plus(&mut self, impl_dyn_multi: bool, ty: &Ty) {
         if impl_dyn_multi {
-            self.sess.emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(ty), span: ty.span });
+            self.dcx().emit_err(AmbiguousPlus { sum_ty: pprust::ty_to_string(ty), span: ty.span });
         }
     }
 
@@ -1516,7 +1502,7 @@ impl<'a> Parser<'a> {
     pub(super) fn maybe_recover_from_question_mark(&mut self, ty: P<Ty>) -> P<Ty> {
         if self.token == token::Question {
             self.bump();
-            self.sess.emit_err(QuestionMarkInType {
+            self.dcx().emit_err(QuestionMarkInType {
                 span: self.prev_token.span,
                 sugg: QuestionMarkInTypeSugg {
                     left: ty.span.shrink_to_lo(),
@@ -1553,7 +1539,7 @@ impl<'a> Parser<'a> {
                 match self.parse_expr() {
                     Ok(_) => {
                         return Err(self
-                            .sess
+                            .dcx()
                             .create_err(TernaryOperator { span: self.token.span.with_lo(lo) }));
                     }
                     Err(err) => {
@@ -1597,7 +1583,7 @@ impl<'a> Parser<'a> {
             _ => BadTypePlusSub::ExpectPath { span: sum_span },
         };
 
-        self.sess.emit_err(BadTypePlus { ty: pprust::ty_to_string(ty), span: sum_span, sub });
+        self.dcx().emit_err(BadTypePlus { ty: pprust::ty_to_string(ty), span: sum_span, sub });
 
         Ok(())
     }
@@ -1647,7 +1633,7 @@ impl<'a> Parser<'a> {
         kind: IncDecRecovery,
         op_span: Span,
     ) -> PResult<'a, P<Expr>> {
-        let mut err = self.struct_span_err(
+        let mut err = self.dcx().struct_span_err(
             op_span,
             format!("Rust has no {} {} operator", kind.fixity, kind.op.name()),
         );
@@ -1775,7 +1761,7 @@ impl<'a> Parser<'a> {
         self.parse_path_segments(&mut path.segments, T::PATH_STYLE, None)?;
         path.span = ty_span.to(self.prev_token.span);
 
-        self.sess.emit_err(BadQPathStage2 {
+        self.dcx().emit_err(BadQPathStage2 {
             span: ty_span,
             wrap: WrapType { lo: ty_span.shrink_to_lo(), hi: ty_span.shrink_to_hi() },
         });
@@ -1807,7 +1793,7 @@ impl<'a> Parser<'a> {
                     err.name = name;
                 }
             }
-            self.sess.emit_err(err);
+            self.dcx().emit_err(err);
             true
         } else {
             false
@@ -1843,7 +1829,7 @@ impl<'a> Parser<'a> {
                 _ => this_token_str,
             },
         );
-        let mut err = self.struct_span_err(sp, msg);
+        let mut err = self.dcx().struct_span_err(sp, msg);
         let label_exp = format!("expected `{token_str}`");
         let sm = self.sess.source_map();
         if !sm.is_multiline(prev_sp.until(sp)) {
@@ -1877,7 +1863,7 @@ impl<'a> Parser<'a> {
             && self.token == token::Colon
             && self.look_ahead(1, |next| line_idx(self.token.span) < line_idx(next.span))
         {
-            self.sess.emit_err(ColonAsSemi {
+            self.dcx().emit_err(ColonAsSemi {
                 span: self.token.span,
                 type_ascription: self.sess.unstable_features.is_nightly_build().then_some(()),
             });
@@ -1938,7 +1924,7 @@ impl<'a> Parser<'a> {
             _ => Applicability::MachineApplicable,
         };
 
-        self.sess.emit_err(IncorrectAwait {
+        self.dcx().emit_err(IncorrectAwait {
             span,
             sugg_span: (span, applicability),
             expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(expr)),
@@ -1959,7 +1945,7 @@ impl<'a> Parser<'a> {
             let span = lo.to(self.token.span);
             self.bump(); // )
 
-            self.sess.emit_err(IncorrectUseOfAwait { span });
+            self.dcx().emit_err(IncorrectUseOfAwait { span });
         }
     }
 
@@ -1978,7 +1964,7 @@ impl<'a> Parser<'a> {
             self.consume_block(Delimiter::Parenthesis, ConsumeClosingDelim::No); //eat the block
             let hi = self.token.span;
             self.bump(); //remove )
-            let mut err = self.struct_span_err(lo.to(hi), "use of deprecated `try` macro");
+            let mut err = self.dcx().struct_span_err(lo.to(hi), "use of deprecated `try` macro");
             err.note("in the 2018 edition `try` is a reserved keyword, and the `try!()` macro is deprecated");
             let prefix = if is_empty { "" } else { "alternatively, " };
             if !is_empty {
@@ -2133,7 +2119,7 @@ impl<'a> Parser<'a> {
     pub(super) fn check_for_for_in_in_typo(&mut self, in_span: Span) {
         if self.eat_keyword(kw::In) {
             // a common typo: `for _ in in bar {}`
-            self.sess.emit_err(InInTypo {
+            self.dcx().emit_err(InInTypo {
                 span: self.prev_token.span,
                 sugg_span: in_span.until(self.prev_token.span),
             });
@@ -2142,7 +2128,7 @@ impl<'a> Parser<'a> {
 
     pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
         if let token::DocComment(..) = self.token.kind {
-            self.sess.emit_err(DocCommentOnParamType { span: self.token.span });
+            self.dcx().emit_err(DocCommentOnParamType { span: self.token.span });
             self.bump();
         } else if self.token == token::Pound
             && self.look_ahead(1, |t| *t == token::OpenDelim(Delimiter::Bracket))
@@ -2154,7 +2140,7 @@ impl<'a> Parser<'a> {
             }
             let sp = lo.to(self.token.span);
             self.bump();
-            self.sess.emit_err(AttributeOnParamType { span: sp });
+            self.dcx().emit_err(AttributeOnParamType { span: sp });
         }
     }
 
@@ -2275,7 +2261,7 @@ impl<'a> Parser<'a> {
         self.expect(&token::Colon)?;
         let ty = self.parse_ty()?;
 
-        self.sess.emit_err(PatternMethodParamWithoutBody { span: pat.span });
+        self.dcx().emit_err(PatternMethodParamWithoutBody { span: pat.span });
 
         // Pretend the pattern is `_`, to avoid duplicate errors from AST validation.
         let pat =
@@ -2286,7 +2272,7 @@ impl<'a> Parser<'a> {
     pub(super) fn recover_bad_self_param(&mut self, mut param: Param) -> PResult<'a, Param> {
         let span = param.pat.span;
         param.ty.kind = TyKind::Err;
-        self.sess.emit_err(SelfParamNotFirst { span });
+        self.dcx().emit_err(SelfParamNotFirst { span });
         Ok(param)
     }
 
@@ -2328,7 +2314,7 @@ impl<'a> Parser<'a> {
                 format!("expected expression, found {}", super::token_descr(&self.token)),
             ),
         };
-        let mut err = self.struct_span_err(span, msg);
+        let mut err = self.dcx().struct_span_err(span, msg);
         let sp = self.sess.source_map().start_point(self.token.span);
         if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
             err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
@@ -2450,7 +2436,7 @@ impl<'a> Parser<'a> {
         // We are causing this error here exclusively in case that a `const` expression
         // could be recovered from the current parser state, even if followed by more
         // arguments after a comma.
-        let mut err = self.struct_span_err(
+        let mut err = self.dcx().struct_span_err(
             self.token.span,
             format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
         );
@@ -2488,7 +2474,7 @@ impl<'a> Parser<'a> {
             err
         })?;
         if !self.expr_is_valid_const_arg(&expr) {
-            self.sess.emit_err(ConstGenericWithoutBraces {
+            self.dcx().emit_err(ConstGenericWithoutBraces {
                 span: expr.span,
                 sugg: ConstGenericWithoutBracesSugg {
                     left: expr.span.shrink_to_lo(),
@@ -2530,7 +2516,7 @@ impl<'a> Parser<'a> {
             }
             _ => None,
         };
-        self.sess.emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg });
+        self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg });
 
         let value = self.mk_expr_err(param.span());
         Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }))
@@ -2553,7 +2539,7 @@ impl<'a> Parser<'a> {
         let mut err = UnexpectedConstInGenericParam { span: start, to_remove: None };
         if self.check_const_arg() {
             err.to_remove = Some(start.until(self.token.span));
-            self.sess.emit_err(err);
+            self.dcx().emit_err(err);
             Ok(Some(GenericArg::Const(self.parse_const_arg()?)))
         } else {
             let after_kw_const = self.token.span;
@@ -2840,7 +2826,7 @@ impl<'a> Parser<'a> {
         let label = self.eat_label().expect("just checked if a label exists");
         self.bump(); // eat `:`
         let span = label.ident.span.to(self.prev_token.span);
-        let mut err = self.struct_span_err(span, "block label not supported here");
+        let mut err = self.dcx().struct_span_err(span, "block label not supported here");
         err.span_label(span, "not supported here");
         err.tool_only_span_suggestion(
             label.ident.span.until(self.token.span),
@@ -2875,7 +2861,7 @@ impl<'a> Parser<'a> {
             err.cancel();
         }
         let seq_span = lo.to(self.prev_token.span);
-        let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
+        let mut err = self.dcx().struct_span_err(comma_span, "unexpected `,` in pattern");
         if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
             err.multipart_suggestion(
                 format!(
@@ -2970,7 +2956,7 @@ impl<'a> Parser<'a> {
             }
             self.bump();
         }
-        let mut err = self.struct_span_err(spans, "encountered diff marker");
+        let mut err = self.dcx().struct_span_err(spans, "encountered diff marker");
         err.span_label(start, "after this is the code before the merge");
         if let Some(middle) = middlediff3 {
             err.span_label(middle, "");
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index a6783eaf8d41d..b76d67cf71554 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -237,7 +237,7 @@ impl<'a> Parser<'a> {
                 }
                 .into();
                 let invalid = format!("{sugg}=");
-                self.sess.emit_err(errors::InvalidComparisonOperator {
+                self.dcx().emit_err(errors::InvalidComparisonOperator {
                     span: sp,
                     invalid: invalid.clone(),
                     sub: errors::InvalidComparisonOperatorSub::Correctable {
@@ -255,7 +255,7 @@ impl<'a> Parser<'a> {
                 && self.prev_token.span.hi() == self.token.span.lo()
             {
                 let sp = op.span.to(self.token.span);
-                self.sess.emit_err(errors::InvalidComparisonOperator {
+                self.dcx().emit_err(errors::InvalidComparisonOperator {
                     span: sp,
                     invalid: "<>".into(),
                     sub: errors::InvalidComparisonOperatorSub::Correctable {
@@ -273,7 +273,7 @@ impl<'a> Parser<'a> {
                 && self.prev_token.span.hi() == self.token.span.lo()
             {
                 let sp = op.span.to(self.token.span);
-                self.sess.emit_err(errors::InvalidComparisonOperator {
+                self.dcx().emit_err(errors::InvalidComparisonOperator {
                     span: sp,
                     invalid: "<=>".into(),
                     sub: errors::InvalidComparisonOperatorSub::Spaceship(sp),
@@ -370,7 +370,7 @@ impl<'a> Parser<'a> {
                     self.mk_expr(span, aopexpr)
                 }
                 AssocOp::As | AssocOp::DotDot | AssocOp::DotDotEq => {
-                    self.span_bug(span, "AssocOp should have been handled by special case")
+                    self.dcx().span_bug(span, "AssocOp should have been handled by special case")
                 }
             };
 
@@ -420,7 +420,7 @@ impl<'a> Parser<'a> {
     /// but the next token implies this should be parsed as an expression.
     /// For example: `if let Some(x) = x { x } else { 0 } / 2`.
     fn error_found_expr_would_be_stmt(&self, lhs: &Expr) {
-        self.sess.emit_err(errors::FoundExprWouldBeStmt {
+        self.dcx().emit_err(errors::FoundExprWouldBeStmt {
             span: self.token.span,
             token: self.token.clone(),
             suggestion: ExprParenthesesNeeded::surrounding(lhs.span),
@@ -447,7 +447,7 @@ impl<'a> Parser<'a> {
             }
             (Some(op), _) => (op, self.token.span),
             (None, Some((Ident { name: sym::and, span }, false))) if self.may_recover() => {
-                self.sess.emit_err(errors::InvalidLogicalOperator {
+                self.dcx().emit_err(errors::InvalidLogicalOperator {
                     span: self.token.span,
                     incorrect: "and".into(),
                     sub: errors::InvalidLogicalOperatorSub::Conjunction(self.token.span),
@@ -455,7 +455,7 @@ impl<'a> Parser<'a> {
                 (AssocOp::LAnd, span)
             }
             (None, Some((Ident { name: sym::or, span }, false))) if self.may_recover() => {
-                self.sess.emit_err(errors::InvalidLogicalOperator {
+                self.dcx().emit_err(errors::InvalidLogicalOperator {
                     span: self.token.span,
                     incorrect: "or".into(),
                     sub: errors::InvalidLogicalOperatorSub::Disjunction(self.token.span),
@@ -593,7 +593,7 @@ impl<'a> Parser<'a> {
                 } else {
                     err.remove_plus = Some(lo);
                 }
-                this.sess.emit_err(err);
+                this.dcx().emit_err(err);
 
                 this.bump();
                 this.parse_expr_prefix(None)
@@ -636,7 +636,7 @@ impl<'a> Parser<'a> {
 
     /// Recover on `~expr` in favor of `!expr`.
     fn recover_tilde_expr(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
-        self.sess.emit_err(errors::TildeAsUnaryOperator(lo));
+        self.dcx().emit_err(errors::TildeAsUnaryOperator(lo));
 
         self.parse_expr_unary(lo, UnOp::Not)
     }
@@ -646,7 +646,7 @@ impl<'a> Parser<'a> {
     fn parse_expr_box(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
         let (span, expr) = self.parse_expr_prefix_common(lo)?;
         let code = self.sess.source_map().span_to_snippet(span.with_lo(lo.hi())).unwrap();
-        self.sess.emit_err(errors::BoxSyntaxRemoved { span, code: code.trim() });
+        self.dcx().emit_err(errors::BoxSyntaxRemoved { span, code: code.trim() });
         // So typechecking works, parse `box <expr>` as `::std::boxed::Box::new(expr)`
         let path = Path {
             span,
@@ -687,7 +687,7 @@ impl<'a> Parser<'a> {
             errors::NotAsNegationOperatorSub::SuggestNotDefault
         };
 
-        self.sess.emit_err(errors::NotAsNegationOperator {
+        self.dcx().emit_err(errors::NotAsNegationOperator {
             negated: negated_token.span,
             negated_desc: super::token_descr(&negated_token),
             // Span the `not` plus trailing whitespace to avoid
@@ -750,7 +750,7 @@ impl<'a> Parser<'a> {
                         match self.parse_expr_labeled(label, false) {
                             Ok(expr) => {
                                 type_err.cancel();
-                                self.sess.emit_err(errors::MalformedLoopLabel {
+                                self.dcx().emit_err(errors::MalformedLoopLabel {
                                     span: label.ident.span,
                                     correct_label: label.ident,
                                 });
@@ -782,7 +782,7 @@ impl<'a> Parser<'a> {
 
                         match self.token.kind {
                             token::Lt => {
-                                self.sess.emit_err(errors::ComparisonInterpretedAsGeneric {
+                                self.dcx().emit_err(errors::ComparisonInterpretedAsGeneric {
                                     comparison: self.token.span,
                                     r#type: path,
                                     args: args_span,
@@ -790,7 +790,7 @@ impl<'a> Parser<'a> {
                                 })
                             }
                             token::BinOp(token::Shl) => {
-                                self.sess.emit_err(errors::ShiftInterpretedAsGeneric {
+                                self.dcx().emit_err(errors::ShiftInterpretedAsGeneric {
                                     shift: self.token.span,
                                     r#type: path,
                                     args: args_span,
@@ -857,7 +857,7 @@ impl<'a> Parser<'a> {
                     _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
                 }
             );
-            let mut err = self.struct_span_err(span, msg);
+            let mut err = self.dcx().struct_span_err(span, msg);
 
             let suggest_parens = |err: &mut Diagnostic| {
                 let suggestions = vec![
@@ -898,7 +898,7 @@ impl<'a> Parser<'a> {
     }
 
     fn error_remove_borrow_lifetime(&self, span: Span, lt_span: Span) {
-        self.sess.emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
+        self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
     }
 
     /// Parse `mut?` or `raw [ const | mut ]`.
@@ -1012,7 +1012,7 @@ impl<'a> Parser<'a> {
             }
             _ => (span, actual),
         };
-        self.sess.emit_err(errors::UnexpectedTokenAfterDot { span, actual });
+        self.dcx().emit_err(errors::UnexpectedTokenAfterDot { span, actual });
     }
 
     // We need an identifier or integer, but the next token is a float.
@@ -1329,7 +1329,7 @@ impl<'a> Parser<'a> {
         } else {
             // Field access `expr.f`
             if let Some(args) = seg.args {
-                self.sess.emit_err(errors::FieldExpressionWithGeneric(args.span()));
+                self.dcx().emit_err(errors::FieldExpressionWithGeneric(args.span()));
             }
 
             let span = lo.to(self.prev_token.span);
@@ -1557,7 +1557,7 @@ impl<'a> Parser<'a> {
         let (span, kind) = if self.eat(&token::Not) {
             // MACRO INVOCATION expression
             if qself.is_some() {
-                self.sess.emit_err(errors::MacroInvocationWithQualifiedPath(path.span));
+                self.dcx().emit_err(errors::MacroInvocationWithQualifiedPath(path.span));
             }
             let lo = path.span;
             let mac = P(MacCall { path, args: self.parse_delim_args()? });
@@ -1603,7 +1603,7 @@ impl<'a> Parser<'a> {
         {
             let (lit, _) =
                 self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| {
-                    self_.sess.create_err(errors::UnexpectedTokenAfterLabel {
+                    self_.dcx().create_err(errors::UnexpectedTokenAfterLabel {
                         span: self_.token.span,
                         remove_label: None,
                         enclose_in_block: None,
@@ -1615,7 +1615,7 @@ impl<'a> Parser<'a> {
             && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt))
         {
             // We're probably inside of a `Path<'a>` that needs a turbofish
-            self.sess.emit_err(errors::UnexpectedTokenAfterLabel {
+            self.dcx().emit_err(errors::UnexpectedTokenAfterLabel {
                 span: self.token.span,
                 remove_label: None,
                 enclose_in_block: None,
@@ -1670,12 +1670,12 @@ impl<'a> Parser<'a> {
                 self.mk_expr(span, ExprKind::Block(blk, label))
             });
 
-            self.sess.emit_err(err);
+            self.dcx().emit_err(err);
             expr
         }?;
 
         if !ate_colon && consume_colon {
-            self.sess.emit_err(errors::RequireColonAfterLabeledExpression {
+            self.dcx().emit_err(errors::RequireColonAfterLabeledExpression {
                 span: expr.span,
                 label: lo,
                 label_end: lo.shrink_to_hi(),
@@ -1723,7 +1723,7 @@ impl<'a> Parser<'a> {
         self.bump(); // `catch`
 
         let span = lo.to(self.prev_token.span);
-        self.sess.emit_err(errors::DoCatchSyntaxRemoved { span });
+        self.dcx().emit_err(errors::DoCatchSyntaxRemoved { span });
 
         self.parse_try_block(lo)
     }
@@ -1783,7 +1783,7 @@ impl<'a> Parser<'a> {
             // The value expression can be a labeled loop, see issue #86948, e.g.:
             // `loop { break 'label: loop { break 'label 42; }; }`
             let lexpr = self.parse_expr_labeled(label, true)?;
-            self.sess.emit_err(errors::LabeledLoopInBreak {
+            self.dcx().emit_err(errors::LabeledLoopInBreak {
                 span: lexpr.span,
                 sub: errors::WrapExpressionInParentheses {
                     left: lexpr.span.shrink_to_lo(),
@@ -1967,7 +1967,7 @@ impl<'a> Parser<'a> {
         let token = self.token.clone();
         let err = |self_: &Self| {
             let msg = format!("unexpected token: {}", super::token_descr(&token));
-            self_.struct_span_err(token.span, msg)
+            self_.dcx().struct_span_err(token.span, msg)
         };
         // On an error path, eagerly consider a lifetime to be an unclosed character lit
         if self.token.is_lifetime() {
@@ -2018,7 +2018,7 @@ impl<'a> Parser<'a> {
             });
             if let Some(token) = &recovered {
                 self.bump();
-                self.sess.emit_err(errors::FloatLiteralRequiresIntegerPart {
+                self.dcx().emit_err(errors::FloatLiteralRequiresIntegerPart {
                     span: token.span,
                     correct: pprust::token_to_string(token).into_owned(),
                 });
@@ -2077,13 +2077,13 @@ impl<'a> Parser<'a> {
         if [sym::i32, sym::u32, sym::isize, sym::usize].contains(&suffix) {
             // #59553: warn instead of reject out of hand to allow the fix to percolate
             // through the ecosystem when people fix their macros
-            self.sess.emit_warning(errors::InvalidLiteralSuffixOnTupleIndex {
+            self.dcx().emit_warning(errors::InvalidLiteralSuffixOnTupleIndex {
                 span,
                 suffix,
                 exception: Some(()),
             });
         } else {
-            self.sess.emit_err(errors::InvalidLiteralSuffixOnTupleIndex {
+            self.dcx().emit_err(errors::InvalidLiteralSuffixOnTupleIndex {
                 span,
                 suffix,
                 exception: None,
@@ -2121,7 +2121,7 @@ impl<'a> Parser<'a> {
         let mut snapshot = self.create_snapshot_for_diagnostic();
         match snapshot.parse_expr_array_or_repeat(Delimiter::Brace) {
             Ok(arr) => {
-                self.sess.emit_err(errors::ArrayBracketsInsteadOfSpaces {
+                self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces {
                     span: arr.span,
                     sub: errors::ArrayBracketsInsteadOfSpacesSugg {
                         left: lo,
@@ -2195,7 +2195,7 @@ impl<'a> Parser<'a> {
         }
 
         if self.token.is_whole_block() {
-            self.sess.emit_err(errors::InvalidBlockMacroSegment {
+            self.dcx().emit_err(errors::InvalidBlockMacroSegment {
                 span: self.token.span,
                 context: lo.to(self.token.span),
                 wrap: errors::WrapInExplicitBlock {
@@ -2399,7 +2399,7 @@ impl<'a> Parser<'a> {
                 ExprKind::Binary(Spanned { span: binop_span, .. }, _, right)
                     if let ExprKind::Block(_, None) = right.kind =>
                 {
-                    self.sess.emit_err(errors::IfExpressionMissingThenBlock {
+                    this.dcx().emit_err(errors::IfExpressionMissingThenBlock {
                         if_span: lo,
                         missing_then_block_sub:
                             errors::IfExpressionMissingThenBlockSub::UnfinishedCondition(
@@ -2410,7 +2410,7 @@ impl<'a> Parser<'a> {
                     std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi()))
                 }
                 ExprKind::Block(_, None) => {
-                    self.sess.emit_err(errors::IfExpressionMissingCondition {
+                    this.dcx().emit_err(errors::IfExpressionMissingCondition {
                         if_span: lo.shrink_to_hi(),
                         block_span: self.sess.source_map().start_point(cond_span),
                     });
@@ -2434,7 +2434,7 @@ impl<'a> Parser<'a> {
                 let let_else_sub = matches!(cond.kind, ExprKind::Let(..))
                     .then(|| errors::IfExpressionLetSomeSub { if_span: lo.until(cond_span) });
 
-                self.sess.emit_err(errors::IfExpressionMissingThenBlock {
+                self.dcx().emit_err(errors::IfExpressionMissingThenBlock {
                     if_span: lo,
                     missing_then_block_sub: errors::IfExpressionMissingThenBlockSub::AddThenBlock(
                         cond_span.shrink_to_hi(),
@@ -2513,7 +2513,7 @@ impl<'a> Parser<'a> {
                 // This was part of a closure, the that part of the parser recover.
                 return Err(self.dcx().create_err(err));
             } else {
-                Some(self.sess.emit_err(err))
+                Some(self.dcx().emit_err(err))
             }
         } else {
             None
@@ -2527,7 +2527,7 @@ impl<'a> Parser<'a> {
             CommaRecoveryMode::LikelyTuple,
         )?;
         if self.token == token::EqEq {
-            self.sess.emit_err(errors::ExpectedEqForLetExpr {
+            self.dcx().emit_err(errors::ExpectedEqForLetExpr {
                 span: self.token.span,
                 sugg_span: self.token.span,
             });
@@ -2559,7 +2559,7 @@ impl<'a> Parser<'a> {
                     if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
                         && classify::expr_requires_semi_to_be_stmt(&cond) =>
                 {
-                    self.sess.emit_err(errors::ExpectedElseBlock {
+                    self.dcx().emit_err(errors::ExpectedElseBlock {
                         first_tok_span,
                         first_tok,
                         else_span,
@@ -2599,7 +2599,7 @@ impl<'a> Parser<'a> {
             [x0 @ xn] | [x0, .., xn] => (x0.span.to(xn.span), xn.span),
         };
         let ctx = if is_ctx_else { "else" } else { "if" };
-        self.sess.emit_err(errors::OuterAttributeNotAllowedOnIfElse {
+        self.dcx().emit_err(errors::OuterAttributeNotAllowedOnIfElse {
             last,
             branch_span,
             ctx_span,
@@ -2613,7 +2613,7 @@ impl<'a> Parser<'a> {
             && let BinOpKind::And = binop
             && let ExprKind::If(cond, ..) = &right.kind
         {
-            Err(self.sess.create_err(errors::UnexpectedIfWithIf(
+            Err(self.dcx().create_err(errors::UnexpectedIfWithIf(
                 binop_span.shrink_to_hi().to(cond.span.shrink_to_lo()),
             )))
         } else {
@@ -2662,7 +2662,7 @@ impl<'a> Parser<'a> {
                     let right = self.prev_token.span.between(self.look_ahead(1, |t| t.span));
                     self.bump(); // )
                     err.cancel();
-                    self.sess.emit_err(errors::ParenthesesInForHead {
+                    self.dcx().emit_err(errors::ParenthesesInForHead {
                         span,
                         // With e.g. `for (x) in y)` this would replace `(x) in y)`
                         // with `x) in y)` which is syntactically invalid.
@@ -2701,7 +2701,7 @@ impl<'a> Parser<'a> {
             && !matches!(self.token.kind, token::OpenDelim(Delimiter::Brace))
             && self.may_recover()
         {
-            self.sess
+            self.dcx()
                 .emit_err(errors::MissingExpressionInForLoop { span: expr.span.shrink_to_lo() });
             let err_expr = self.mk_expr(expr.span, ExprKind::Err);
             let block = self.mk_block(thin_vec![], BlockCheckMode::Default, self.prev_token.span);
@@ -2726,7 +2726,7 @@ impl<'a> Parser<'a> {
             let else_span = self.token.span;
             self.bump();
             let else_clause = self.parse_expr_else()?;
-            self.sess.emit_err(errors::LoopElseNotSupported {
+            self.dcx().emit_err(errors::LoopElseNotSupported {
                 span: else_span.to(else_clause.span),
                 loop_kind,
                 loop_kw,
@@ -2745,7 +2745,7 @@ impl<'a> Parser<'a> {
             (self.prev_token.span.between(self.token.span), errors::MissingInInForLoopSub::AddIn)
         };
 
-        self.sess.emit_err(errors::MissingInInForLoop { span, sub: sub(span) });
+        self.dcx().emit_err(errors::MissingInInForLoop { span, sub: sub(span) });
     }
 
     /// Parses a `while` or `while let` expression (`while` token already eaten).
@@ -2853,7 +2853,7 @@ impl<'a> Parser<'a> {
         let err = |this: &Parser<'_>, stmts: Vec<ast::Stmt>| {
             let span = stmts[0].span.to(stmts[stmts.len() - 1].span);
 
-            this.sess.emit_err(errors::MatchArmBodyWithoutBraces {
+            this.dcx().emit_err(errors::MatchArmBodyWithoutBraces {
                 statements: span,
                 arrow: arrow_span,
                 num_statements: stmts.len(),
@@ -3060,7 +3060,7 @@ impl<'a> Parser<'a> {
                         .is_ok();
                     if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
                         err.cancel();
-                        this.sess.emit_err(errors::MissingCommaAfterMatchArm {
+                        this.dcx().emit_err(errors::MissingCommaAfterMatchArm {
                             span: arm_span.shrink_to_hi(),
                         });
                         return Ok(true);
@@ -3149,7 +3149,7 @@ impl<'a> Parser<'a> {
                     self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Parenthesis)]);
                     self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
                     let right = self.prev_token.span;
-                    self.sess.emit_err(errors::ParenthesesInMatchPat {
+                    self.dcx().emit_err(errors::ParenthesesInMatchPat {
                         span: vec![left, right],
                         sugg: errors::ParenthesesInMatchPatSugg { left, right },
                     });
@@ -3303,7 +3303,7 @@ impl<'a> Parser<'a> {
             let expr = self.parse_expr_struct(qself.clone(), path.clone(), true);
             if let (Ok(expr), false) = (&expr, struct_allowed) {
                 // This is a struct literal, but we don't can't accept them here.
-                self.sess.emit_err(errors::StructLiteralNotAllowedHere {
+                self.dcx().emit_err(errors::StructLiteralNotAllowedHere {
                     span: expr.span,
                     sub: errors::StructLiteralNotAllowedHereSugg {
                         left: path.span.shrink_to_lo(),
@@ -3487,7 +3487,7 @@ impl<'a> Parser<'a> {
         if self.token != token::Comma {
             return;
         }
-        self.sess.emit_err(errors::CommaAfterBaseStruct {
+        self.dcx().emit_err(errors::CommaAfterBaseStruct {
             span: span.to(self.prev_token.span),
             comma: self.token.span,
         });
@@ -3500,7 +3500,7 @@ impl<'a> Parser<'a> {
         {
             // recover from typo of `...`, suggest `..`
             let span = self.prev_token.span;
-            self.sess.emit_err(errors::MissingDotDot { token_span: span, sugg_span: span });
+            self.dcx().emit_err(errors::MissingDotDot { token_span: span, sugg_span: span });
             return true;
         }
         false
@@ -3513,7 +3513,7 @@ impl<'a> Parser<'a> {
         let label = format!("'{}", ident.name);
         let ident = Ident { name: Symbol::intern(&label), span: ident.span };
 
-        self.sess.emit_err(errors::ExpectedLabelFoundIdent {
+        self.dcx().emit_err(errors::ExpectedLabelFoundIdent {
             span: ident.span,
             start: ident.span.shrink_to_lo(),
         });
@@ -3581,18 +3581,18 @@ impl<'a> Parser<'a> {
             return;
         }
 
-        self.sess.emit_err(errors::EqFieldInit {
+        self.dcx().emit_err(errors::EqFieldInit {
             span: self.token.span,
             eq: field_name.span.shrink_to_hi().to(self.token.span),
         });
     }
 
     fn err_dotdotdot_syntax(&self, span: Span) {
-        self.sess.emit_err(errors::DotDotDot { span });
+        self.dcx().emit_err(errors::DotDotDot { span });
     }
 
     fn err_larrow_operator(&self, span: Span) {
-        self.sess.emit_err(errors::LeftArrowOperator { span });
+        self.dcx().emit_err(errors::LeftArrowOperator { span });
     }
 
     fn mk_assign_op(&self, binop: BinOp, lhs: P<Expr>, rhs: P<Expr>) -> ExprKind {
@@ -3729,7 +3729,7 @@ impl MutVisitor for CondChecker<'_> {
             ExprKind::Let(_, _, _, ref mut is_recovered @ None) => {
                 if let Some(reason) = self.forbid_let_reason {
                     *is_recovered =
-                        Some(self.parser.sess.emit_err(errors::ExpectedExpressionFoundLet {
+                        Some(self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
                             span,
                             reason,
                             missing_let: self.missing_let,
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index 20f67b284b275..7e243c1c32a9f 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -64,7 +64,7 @@ impl<'a> Parser<'a> {
                     Ok(p) => {
                         if let TyKind::ImplTrait(_, bounds) = &p.kind {
                             let span = impl_span.to(self.token.span.shrink_to_lo());
-                            let mut err = self.struct_span_err(
+                            let mut err = self.dcx().struct_span_err(
                                 span,
                                 "expected trait bound, found `impl Trait` type",
                             );
@@ -141,7 +141,7 @@ impl<'a> Parser<'a> {
         // Parse optional const generics default value.
         let default = if self.eat(&token::Eq) { Some(self.parse_const_arg()?) } else { None };
 
-        let mut err = self.struct_span_err(
+        let mut err = self.dcx().struct_span_err(
             mistyped_const_ident.span,
             format!("`const` keyword was mistyped as `{}`", mistyped_const_ident.as_str()),
         );
@@ -176,7 +176,7 @@ impl<'a> Parser<'a> {
                     if this.eat_keyword_noexpect(kw::SelfUpper) {
                         // `Self` as a generic param is invalid. Here we emit the diagnostic and continue parsing
                         // as if `Self` never existed.
-                        this.sess.emit_err(UnexpectedSelfInGenericParameters {
+                        this.dcx().emit_err(UnexpectedSelfInGenericParameters {
                             span: this.prev_token.span,
                         });
 
@@ -200,7 +200,7 @@ impl<'a> Parser<'a> {
                             this.bump(); // `=`
                             this.bump(); // `'lifetime`
                             let span = lo.to(this.prev_token.span);
-                            this.sess.emit_err(
+                            this.dcx().emit_err(
                                 UnexpectedDefaultValueForLifetimeInGenericParameters { span },
                             );
                         }
@@ -225,7 +225,7 @@ impl<'a> Parser<'a> {
                         let snapshot = this.create_snapshot_for_diagnostic();
                         match this.parse_ty_where_predicate() {
                             Ok(where_predicate) => {
-                                this.sess.emit_err(errors::BadAssocTypeBounds {
+                                this.dcx().emit_err(errors::BadAssocTypeBounds {
                                     span: where_predicate.span(),
                                 });
                                 // FIXME - try to continue parsing other generics?
@@ -242,10 +242,10 @@ impl<'a> Parser<'a> {
                         // Check for trailing attributes and stop parsing.
                         if !attrs.is_empty() {
                             if !params.is_empty() {
-                                this.sess
+                                this.dcx()
                                     .emit_err(errors::AttrAfterGeneric { span: attrs[0].span });
                             } else {
-                                this.sess
+                                this.dcx()
                                     .emit_err(errors::AttrWithoutGenerics { span: attrs[0].span });
                             }
                         }
@@ -334,7 +334,7 @@ impl<'a> Parser<'a> {
         // change we parse those generics now, but report an error.
         if self.choose_generics_over_qpath(0) {
             let generics = self.parse_generics()?;
-            self.sess.emit_err(errors::WhereOnGenerics { span: generics.span });
+            self.dcx().emit_err(errors::WhereOnGenerics { span: generics.span });
         }
 
         loop {
@@ -370,7 +370,7 @@ impl<'a> Parser<'a> {
             let ate_comma = self.eat(&token::Comma);
 
             if self.eat_keyword_noexpect(kw::Where) {
-                self.sess.emit_err(MultipleWhereClauses {
+                self.dcx().emit_err(MultipleWhereClauses {
                     span: self.token.span,
                     previous: pred_lo,
                     between: prev_token.shrink_to_hi().to(self.prev_token.span),
@@ -422,7 +422,7 @@ impl<'a> Parser<'a> {
                         let body_sp = pred_lo.to(snapshot.prev_token.span);
                         let map = self.sess.source_map();
 
-                        self.sess.emit_err(WhereClauseBeforeTupleStructBody {
+                        self.dcx().emit_err(WhereClauseBeforeTupleStructBody {
                             span: where_sp,
                             name: struct_name.span,
                             body: body_sp,
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 051f19f5a9d2a..0ac0b678abace 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -63,7 +63,7 @@ impl<'a> Parser<'a> {
             let token_str = super::token_descr(&self.token);
             if !self.maybe_consume_incorrect_semicolon(&items) {
                 let msg = format!("expected item, found {token_str}");
-                let mut err = self.struct_span_err(self.token.span, msg);
+                let mut err = self.dcx().struct_span_err(self.token.span, msg);
                 let span = self.token.span;
                 if self.is_kw_followed_by_ident(kw::Let) {
                     err.span_label(
@@ -162,11 +162,11 @@ impl<'a> Parser<'a> {
 
         // At this point, we have failed to parse an item.
         if !matches!(vis.kind, VisibilityKind::Inherited) {
-            self.sess.emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis });
+            self.dcx().emit_err(errors::VisibilityNotFollowedByItem { span: vis.span, vis });
         }
 
         if let Defaultness::Default(span) = def {
-            self.sess.emit_err(errors::DefaultNotFollowedByItem { span });
+            self.dcx().emit_err(errors::DefaultNotFollowedByItem { span });
         }
 
         if !attrs_allowed {
@@ -178,7 +178,7 @@ impl<'a> Parser<'a> {
     /// Error in-case `default` was parsed in an in-appropriate context.
     fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
         if let Defaultness::Default(span) = def {
-            self.sess.emit_err(errors::InappropriateDefault {
+            self.dcx().emit_err(errors::InappropriateDefault {
                 span,
                 article: kind.article(),
                 descr: kind.descr(),
@@ -318,7 +318,7 @@ impl<'a> Parser<'a> {
         self.bump();
         match self.parse_use_item() {
             Ok(u) => {
-                self.sess.emit_err(errors::RecoverImportAsUse { span, token_name });
+                self.dcx().emit_err(errors::RecoverImportAsUse { span, token_name });
                 Ok(Some(u))
             }
             Err(e) => {
@@ -484,7 +484,7 @@ impl<'a> Parser<'a> {
         } else {
             "expected item after attributes"
         };
-        let mut err = self.struct_span_err(end.span, msg);
+        let mut err = self.dcx().struct_span_err(end.span, msg);
         if end.is_doc_comment() {
             err.span_label(end.span, "this doc comment doesn't document anything");
         } else if self.token.kind == TokenKind::Semi {
@@ -560,7 +560,7 @@ impl<'a> Parser<'a> {
         let ty_first = if self.token.is_keyword(kw::For) && self.look_ahead(1, |t| t != &token::Lt)
         {
             let span = self.prev_token.span.between(self.token.span);
-            self.sess.emit_err(errors::MissingTraitInTraitImpl {
+            self.dcx().emit_err(errors::MissingTraitInTraitImpl {
                 span,
                 for_span: span.to(self.token.span),
             });
@@ -597,7 +597,7 @@ impl<'a> Parser<'a> {
             Some(ty_second) => {
                 // impl Trait for Type
                 if !has_for {
-                    self.sess.emit_err(errors::MissingForInTraitImpl { span: missing_for_span });
+                    self.dcx().emit_err(errors::MissingForInTraitImpl { span: missing_for_span });
                 }
 
                 let ty_first = ty_first.into_inner();
@@ -612,12 +612,12 @@ impl<'a> Parser<'a> {
                             // `impl<T: Default> impl Default for Wrapper<T>`
                             //                   ^^^^^
                             let extra_impl_kw = ty_first.span.until(bound.span());
-                            self.sess.emit_err(errors::ExtraImplKeywordInTraitImpl {
+                            self.dcx().emit_err(errors::ExtraImplKeywordInTraitImpl {
                                 extra_impl_kw,
                                 impl_trait_span: ty_first.span,
                             });
                         } else {
-                            self.sess.emit_err(errors::ExpectedTraitInTraitImplFoundType {
+                            self.dcx().emit_err(errors::ExpectedTraitInTraitImplFoundType {
                                 span: ty_first.span,
                             });
                         }
@@ -664,7 +664,7 @@ impl<'a> Parser<'a> {
 
         // Recover `impl Ty;` instead of `impl Ty {}`
         if self.token == TokenKind::Semi {
-            self.sess.emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span });
+            self.dcx().emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span });
             self.bump();
             return Ok(ThinVec::new());
         }
@@ -712,7 +712,8 @@ impl<'a> Parser<'a> {
                     let non_item_span = self.token.span;
                     let is_let = self.token.is_keyword(kw::Let);
 
-                    let mut err = self.struct_span_err(non_item_span, "non-item in item list");
+                    let mut err =
+                        self.dcx().struct_span_err(non_item_span, "non-item in item list");
                     self.consume_block(Delimiter::Brace, ConsumeClosingDelim::Yes);
                     if is_let {
                         err.span_suggestion(
@@ -822,7 +823,7 @@ impl<'a> Parser<'a> {
             // It's a trait alias.
             if had_colon {
                 let span = span_at_colon.to(span_before_eq);
-                self.sess.emit_err(errors::BoundsNotAllowedOnTraitAliases { span });
+                self.dcx().emit_err(errors::BoundsNotAllowedOnTraitAliases { span });
             }
 
             let bounds = self.parse_generic_bounds()?;
@@ -831,10 +832,10 @@ impl<'a> Parser<'a> {
 
             let whole_span = lo.to(self.prev_token.span);
             if is_auto == IsAuto::Yes {
-                self.sess.emit_err(errors::TraitAliasCannotBeAuto { span: whole_span });
+                self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span });
             }
             if let Unsafe::Yes(_) = unsafety {
-                self.sess.emit_err(errors::TraitAliasCannotBeUnsafe { span: whole_span });
+                self.dcx().emit_err(errors::TraitAliasCannotBeUnsafe { span: whole_span });
             }
 
             self.sess.gated_spans.gate(sym::trait_alias, whole_span);
@@ -880,7 +881,7 @@ impl<'a> Parser<'a> {
                     Ok(kind) => kind,
                     Err(kind) => match kind {
                         ItemKind::Static(box StaticItem { ty, mutability: _, expr }) => {
-                            self.sess.emit_err(errors::AssociatedStaticItemNotAllowed { span });
+                            self.dcx().emit_err(errors::AssociatedStaticItemNotAllowed { span });
                             AssocItemKind::Const(Box::new(ConstItem {
                                 defaultness: Defaultness::Final,
                                 generics: Generics::default(),
@@ -980,7 +981,7 @@ impl<'a> Parser<'a> {
             } else {
                 // Recover from using a colon as path separator.
                 while self.eat_noexpect(&token::Colon) {
-                    self.sess
+                    self.dcx()
                         .emit_err(errors::SingleColonImportPath { span: self.prev_token.span });
 
                     // We parse the rest of the path and append it to the original prefix.
@@ -1077,7 +1078,7 @@ impl<'a> Parser<'a> {
             write!(fixed_name, "_{}", part.name).unwrap();
         }
 
-        self.sess.emit_err(errors::ExternCrateNameWithDashes {
+        self.dcx().emit_err(errors::ExternCrateNameWithDashes {
             span: fixed_name_sp,
             sugg: errors::ExternCrateNameWithDashesSugg { dashes },
         });
@@ -1132,7 +1133,7 @@ impl<'a> Parser<'a> {
                         ItemKind::Const(box ConstItem { ty, expr, .. }) => {
                             let const_span = Some(span.with_hi(ident.span.lo()))
                                 .filter(|span| span.can_be_used_for_suggestions());
-                            self.sess.emit_err(errors::ExternItemCannotBeConst {
+                            self.dcx().emit_err(errors::ExternItemCannotBeConst {
                                 ident_span: ident.span,
                                 const_span,
                             });
@@ -1150,7 +1151,7 @@ impl<'a> Parser<'a> {
         // FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`)
         let span = self.sess.source_map().guess_head_span(span);
         let descr = kind.descr();
-        self.sess.emit_err(errors::BadItemKind { span, descr, ctx });
+        self.dcx().emit_err(errors::BadItemKind { span, descr, ctx });
         None
     }
 
@@ -1181,10 +1182,11 @@ impl<'a> Parser<'a> {
     fn recover_const_mut(&mut self, const_span: Span) {
         if self.eat_keyword(kw::Mut) {
             let span = self.prev_token.span;
-            self.sess.emit_err(errors::ConstGlobalCannotBeMutable { ident_span: span, const_span });
+            self.dcx()
+                .emit_err(errors::ConstGlobalCannotBeMutable { ident_span: span, const_span });
         } else if self.eat_keyword(kw::Let) {
             let span = self.prev_token.span;
-            self.sess.emit_err(errors::ConstLetMutuallyExclusive { span: const_span.to(span) });
+            self.dcx().emit_err(errors::ConstLetMutuallyExclusive { span: const_span.to(span) });
         }
     }
 
@@ -1238,7 +1240,7 @@ impl<'a> Parser<'a> {
 
         if self.token.kind == TokenKind::Lt && self.may_recover() {
             let generics = self.parse_generics()?;
-            self.sess.emit_err(errors::StaticWithGenerics { span: generics.span });
+            self.dcx().emit_err(errors::StaticWithGenerics { span: generics.span });
         }
 
         // Parse the type of a static item. That is, the `":" $ty` fragment.
@@ -1299,7 +1301,7 @@ impl<'a> Parser<'a> {
         if before_where_clause.has_where_token
             && let Some(expr) = &expr
         {
-            self.sess.emit_err(errors::WhereClauseBeforeConstBody {
+            self.dcx().emit_err(errors::WhereClauseBeforeConstBody {
                 span: before_where_clause.span,
                 name: ident.span,
                 body: expr.span,
@@ -1385,7 +1387,7 @@ impl<'a> Parser<'a> {
             let err = errors::EnumStructMutuallyExclusive { span };
             if self.look_ahead(1, |t| t.is_ident()) {
                 self.bump();
-                self.sess.emit_err(err);
+                self.dcx().emit_err(err);
             } else {
                 return Err(self.dcx().create_err(err));
             }
@@ -1398,7 +1400,7 @@ impl<'a> Parser<'a> {
 
         // Possibly recover `enum Foo;` instead of `enum Foo {}`
         let (variants, _) = if self.token == TokenKind::Semi {
-            self.sess.emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span });
+            self.dcx().emit_err(errors::UseEmptyBlockNotSemi { span: self.token.span });
             self.bump();
             (thin_vec![], false)
         } else {
@@ -1617,7 +1619,7 @@ impl<'a> Parser<'a> {
         } else {
             let token_str = super::token_descr(&self.token);
             let msg = format!("expected `where` or `{{` after union name, found {token_str}");
-            let mut err = self.struct_span_err(self.token.span, msg);
+            let mut err = self.dcx().struct_span_err(self.token.span, msg);
             err.span_label(self.token.span, "expected `where` or `{` after union name");
             return Err(err);
         };
@@ -1657,7 +1659,7 @@ impl<'a> Parser<'a> {
                 if parsed_where { "" } else { "`where`, or " },
                 token_str
             );
-            let mut err = self.struct_span_err(self.token.span, msg);
+            let mut err = self.dcx().struct_span_err(self.token.span, msg);
             err.span_label(
                 self.token.span,
                 format!(
@@ -1749,7 +1751,8 @@ impl<'a> Parser<'a> {
         }
         if self.eat(&token::Semi) {
             let sp = self.prev_token.span;
-            let mut err = self.struct_span_err(sp, format!("{adt_ty} fields are separated by `,`"));
+            let mut err =
+                self.dcx().struct_span_err(sp, format!("{adt_ty} fields are separated by `,`"));
             err.span_suggestion_short(
                 sp,
                 "replace `;` with `,`",
@@ -1777,7 +1780,7 @@ impl<'a> Parser<'a> {
                     seen_comma = true;
                 }
                 if comma_after_doc_seen || self.token == token::CloseDelim(Delimiter::Brace) {
-                    self.sess.emit_err(err);
+                    self.dcx().emit_err(err);
                 } else {
                     if !seen_comma {
                         let sp = previous_span.shrink_to_hi();
@@ -1788,7 +1791,7 @@ impl<'a> Parser<'a> {
             }
             _ => {
                 let sp = self.prev_token.span.shrink_to_hi();
-                let mut err = self.struct_span_err(
+                let mut err = self.dcx().struct_span_err(
                     sp,
                     format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
                 );
@@ -1892,13 +1895,13 @@ impl<'a> Parser<'a> {
         self.expect_field_ty_separator()?;
         let ty = self.parse_ty_for_field_def()?;
         if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
-            self.sess.emit_err(errors::SingleColonStructType { span: self.token.span });
+            self.dcx().emit_err(errors::SingleColonStructType { span: self.token.span });
         }
         if self.token.kind == token::Eq {
             self.bump();
             let const_expr = self.parse_expr_anon_const()?;
             let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
-            self.sess.emit_err(errors::EqualsStructDefault { span: sp });
+            self.dcx().emit_err(errors::EqualsStructDefault { span: sp });
         }
         Ok(FieldDef {
             span: lo.to(self.prev_token.span),
@@ -1935,7 +1938,7 @@ impl<'a> Parser<'a> {
                     Case::Insensitive,
                 ) {
                     Ok(_) => {
-                        let mut err = self.struct_span_err(
+                        let mut err = self.dcx().struct_span_err(
                             lo.to(self.prev_token.span),
                             format!("functions are not allowed in {adt_ty} definitions"),
                         );
@@ -1954,7 +1957,7 @@ impl<'a> Parser<'a> {
             } else if self.eat_keyword(kw::Struct) {
                 match self.parse_item_struct() {
                     Ok((ident, _)) => {
-                        let mut err = self.struct_span_err(
+                        let mut err = self.dcx().struct_span_err(
                             lo.with_hi(ident.span.hi()),
                             format!("structs are not allowed in {adt_ty} definitions"),
                         );
@@ -2039,7 +2042,7 @@ impl<'a> Parser<'a> {
                 return IsMacroRulesItem::Yes { has_bang: true };
             } else if self.look_ahead(1, |t| (t.is_ident())) {
                 // macro_rules foo
-                self.sess.emit_err(errors::MacroRulesMissingBang {
+                self.dcx().emit_err(errors::MacroRulesMissingBang {
                     span: macro_rules_span,
                     hi: macro_rules_span.shrink_to_hi(),
                 });
@@ -2067,7 +2070,7 @@ impl<'a> Parser<'a> {
         if self.eat(&token::Not) {
             // Handle macro_rules! foo!
             let span = self.prev_token.span;
-            self.sess.emit_err(errors::MacroNameRemoveBang { span });
+            self.dcx().emit_err(errors::MacroNameRemoveBang { span });
         }
 
         let body = self.parse_delim_args()?;
@@ -2087,9 +2090,9 @@ impl<'a> Parser<'a> {
         let vstr = pprust::vis_to_string(vis);
         let vstr = vstr.trim_end();
         if macro_rules {
-            self.sess.emit_err(errors::MacroRulesVisibility { span: vis.span, vis: vstr });
+            self.dcx().emit_err(errors::MacroRulesVisibility { span: vis.span, vis: vstr });
         } else {
-            self.sess.emit_err(errors::MacroInvocationVisibility { span: vis.span, vis: vstr });
+            self.dcx().emit_err(errors::MacroInvocationVisibility { span: vis.span, vis: vstr });
         }
     }
 
@@ -2101,7 +2104,7 @@ impl<'a> Parser<'a> {
 
     fn report_invalid_macro_expansion_item(&self, args: &DelimArgs) {
         let span = args.dspan.entire();
-        let mut err = self.struct_span_err(
+        let mut err = self.dcx().struct_span_err(
             span,
             "macros that expand to items must be delimited with braces or followed by a semicolon",
         );
@@ -2135,7 +2138,7 @@ impl<'a> Parser<'a> {
             let kw_token = self.token.clone();
             let kw_str = pprust::token_to_string(&kw_token);
             let item = self.parse_item(ForceCollect::No)?;
-            self.sess.emit_err(errors::NestedAdt {
+            self.dcx().emit_err(errors::NestedAdt {
                 span: kw_token.span,
                 item: item.unwrap().span,
                 kw_str,
@@ -2234,7 +2237,7 @@ impl<'a> Parser<'a> {
                 // If we see `for Ty ...` then user probably meant `impl` item.
                 if self.token.is_keyword(kw::For) {
                     old_err.cancel();
-                    return Err(self.sess.create_err(errors::FnTypoWithImpl { fn_span }));
+                    return Err(self.dcx().create_err(errors::FnTypoWithImpl { fn_span }));
                 } else {
                     return Err(old_err);
                 }
@@ -2279,7 +2282,7 @@ impl<'a> Parser<'a> {
             let _ = self.parse_expr()?;
             self.expect_semi()?; // `;`
             let span = eq_sp.to(self.prev_token.span);
-            self.sess.emit_err(errors::FunctionBodyEqualsExpr {
+            self.dcx().emit_err(errors::FunctionBodyEqualsExpr {
                 span,
                 sugg: errors::FunctionBodyEqualsExprSugg { eq: eq_sp, semi: self.prev_token.span },
             });
@@ -2394,7 +2397,7 @@ impl<'a> Parser<'a> {
 
         if let Some(CoroutineKind::Async { span, .. }) = coroutine_kind {
             if span.is_rust_2015() {
-                self.sess.emit_err(errors::AsyncFnIn2015 {
+                self.dcx().emit_err(errors::AsyncFnIn2015 {
                     span,
                     help: errors::HelpUseLatestEdition::new(),
                 });
@@ -2587,7 +2590,7 @@ impl<'a> Parser<'a> {
         && !self.token.is_keyword(kw::For)
         {
             // recover from missing argument list, e.g. `fn main -> () {}`
-            self.sess
+            self.dcx()
                 .emit_err(errors::MissingFnParams { span: self.prev_token.span.shrink_to_hi() });
             return Ok(ThinVec::new());
         }
@@ -2719,7 +2722,7 @@ impl<'a> Parser<'a> {
         };
         // Recover for the grammar `*self`, `*const self`, and `*mut self`.
         let recover_self_ptr = |this: &mut Self| {
-            self.sess.emit_err(errors::SelfArgumentPointer { span: this.token.span });
+            this.dcx().emit_err(errors::SelfArgumentPointer { span: this.token.span });
 
             Ok((SelfKind::Value(Mutability::Not), expect_self_ident(this), this.prev_token.span))
         };
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 47c337ad91367..1598fd19f6d3f 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -601,7 +601,7 @@ impl<'a> Parser<'a> {
             && let Some((ident, /* is_raw */ false)) = self.token.ident()
             && ident.as_str().to_lowercase() == kw.as_str().to_lowercase()
         {
-            self.sess.emit_err(errors::KwBadCase { span: ident.span, kw: kw.as_str() });
+            self.dcx().emit_err(errors::KwBadCase { span: ident.span, kw: kw.as_str() });
             self.bump();
             return true;
         }
@@ -1423,7 +1423,8 @@ impl<'a> Parser<'a> {
         self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)`
 
         let path_str = pprust::path_to_string(&path);
-        self.sess.emit_err(IncorrectVisibilityRestriction { span: path.span, inner_str: path_str });
+        self.dcx()
+            .emit_err(IncorrectVisibilityRestriction { span: path.span, inner_str: path_str });
 
         Ok(())
     }
@@ -1449,7 +1450,7 @@ impl<'a> Parser<'a> {
             Err(Some(lit)) => match lit.kind {
                 ast::LitKind::Err => None,
                 _ => {
-                    self.sess.emit_err(NonStringAbiLiteral { span: lit.span });
+                    self.dcx().emit_err(NonStringAbiLiteral { span: lit.span });
                     None
                 }
             },
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 11c4b8fae7cec..afbc253757816 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -241,7 +241,7 @@ impl<'a> Parser<'a> {
                 Some(TopLevelOrPatternNotAllowedSugg::WrapInParens { span, pat })
             };
 
-            let mut err = self.sess.create_err(match syntax_loc {
+            let mut err = self.dcx().create_err(match syntax_loc {
                 PatternLocation::LetBinding => {
                     TopLevelOrPatternNotAllowed::LetBinding { span, sub }
                 }
@@ -268,7 +268,7 @@ impl<'a> Parser<'a> {
         // a leading `||` probably doesn't indicate an or-pattern attempt, so we handle that
         // separately.
         if let token::OrOr = self.token.kind {
-            self.sess.emit_err(UnexpectedVertVertBeforeFunctionParam { span: self.token.span });
+            self.dcx().emit_err(UnexpectedVertVertBeforeFunctionParam { span: self.token.span });
             self.bump();
         }
 
@@ -286,7 +286,7 @@ impl<'a> Parser<'a> {
             EatOrResult::TrailingVert
         } else if matches!(self.token.kind, token::OrOr) {
             // Found `||`; Recover and pretend we parsed `|`.
-            self.sess.emit_err(UnexpectedVertVertInPattern { span: self.token.span, start: lo });
+            self.dcx().emit_err(UnexpectedVertVertInPattern { span: self.token.span, start: lo });
             self.bump();
             EatOrResult::AteOr
         } else if self.eat(&token::BinOp(token::Or)) {
@@ -321,7 +321,7 @@ impl<'a> Parser<'a> {
         match (is_end_ahead, &self.token.kind) {
             (true, token::BinOp(token::Or) | token::OrOr) => {
                 // A `|` or possibly `||` token shouldn't be here. Ban it.
-                self.sess.emit_err(TrailingVertNotAllowed {
+                self.dcx().emit_err(TrailingVertNotAllowed {
                     span: self.token.span,
                     start: lo,
                     token: self.token.clone(),
@@ -349,7 +349,7 @@ impl<'a> Parser<'a> {
 
         if self.token.is_keyword(kw::Let) && self.look_ahead(1, |tok| tok.can_begin_pattern()) {
             self.bump();
-            self.sess.emit_err(RemoveLet { span: lo });
+            self.dcx().emit_err(RemoveLet { span: lo });
             lo = self.token.span;
         }
 
@@ -390,7 +390,7 @@ impl<'a> Parser<'a> {
                 // Suggest `box ref`.
                 let span = self.prev_token.span.to(self.token.span);
                 self.bump();
-                self.sess.emit_err(SwitchRefBoxOrder { span });
+                self.dcx().emit_err(SwitchRefBoxOrder { span });
             }
             // Parse ref ident @ pat / ref mut ident @ pat
             let mutbl = self.parse_mutability();
@@ -459,7 +459,7 @@ impl<'a> Parser<'a> {
                         super::token_descr(&self_.token)
                     );
 
-                    let mut err = self_.struct_span_err(self_.token.span, msg);
+                    let mut err = self_.dcx().struct_span_err(self_.token.span, msg);
                     err.span_label(self_.token.span, format!("expected {expected}"));
                     err
                 });
@@ -493,7 +493,7 @@ impl<'a> Parser<'a> {
         self.bump(); // `...`
 
         // The user probably mistook `...` for a rest pattern `..`.
-        self.sess.emit_err(DotDotDotRestPattern { span: lo });
+        self.dcx().emit_err(DotDotDotRestPattern { span: lo });
         PatKind::Rest
     }
 
@@ -527,7 +527,7 @@ impl<'a> Parser<'a> {
             // The RHS is now the full pattern.
             *sub = Some(lhs);
 
-            self.sess.emit_err(PatternOnWrongSideOfAt {
+            self.dcx().emit_err(PatternOnWrongSideOfAt {
                 whole_span,
                 whole_pat: pprust::pat_to_string(&rhs),
                 pattern: lhs_span,
@@ -536,7 +536,7 @@ impl<'a> Parser<'a> {
         } else {
             // The special case above doesn't apply so we may have e.g. `A(x) @ B(y)`.
             rhs.kind = PatKind::Wild;
-            self.sess.emit_err(ExpectedBindingLeftOfAt {
+            self.dcx().emit_err(ExpectedBindingLeftOfAt {
                 whole_span,
                 lhs: lhs.span,
                 rhs: rhs.span,
@@ -558,7 +558,7 @@ impl<'a> Parser<'a> {
             _ => return,
         }
 
-        self.sess
+        self.dcx()
             .emit_err(AmbiguousRangePattern { span: pat.span, pat: pprust::pat_to_string(pat) });
     }
 
@@ -568,7 +568,7 @@ impl<'a> Parser<'a> {
         if let token::Lifetime(name) = self.token.kind {
             self.bump(); // `'a`
 
-            self.sess
+            self.dcx()
                 .emit_err(UnexpectedLifetimeInPattern { span: self.prev_token.span, symbol: name });
         }
 
@@ -602,7 +602,7 @@ impl<'a> Parser<'a> {
         let mut_span = self.prev_token.span;
 
         if self.eat_keyword(kw::Ref) {
-            self.sess.emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) });
+            self.dcx().emit_err(RefMutOrderIncorrect { span: mut_span.to(self.prev_token.span) });
             return self.parse_pat_ident(BindingAnnotation::REF_MUT, syntax_loc);
         }
 
@@ -656,7 +656,7 @@ impl<'a> Parser<'a> {
 
     /// Error on `mut $pat` where `$pat` is not an ident.
     fn ban_mut_general_pat(&self, lo: Span, pat: &Pat, changed_any_binding: bool) {
-        self.sess.emit_err(if changed_any_binding {
+        self.dcx().emit_err(if changed_any_binding {
             InvalidMutInPattern::NestedIdent {
                 span: lo.to(pat.span),
                 pat: pprust::pat_to_string(pat),
@@ -674,7 +674,7 @@ impl<'a> Parser<'a> {
             return;
         }
 
-        self.sess.emit_err(RepeatedMutInPattern { span: lo.to(self.prev_token.span) });
+        self.dcx().emit_err(RepeatedMutInPattern { span: lo.to(self.prev_token.span) });
     }
 
     /// Parse macro invocation
@@ -695,7 +695,7 @@ impl<'a> Parser<'a> {
         let expected = Expected::to_string_or_fallback(expected);
         let msg = format!("expected {}, found {}", expected, super::token_descr(&self.token));
 
-        let mut err = self.struct_span_err(self.token.span, msg);
+        let mut err = self.dcx().struct_span_err(self.token.span, msg);
         err.span_label(self.token.span, format!("expected {expected}"));
 
         let sp = self.sess.source_map().start_point(self.token.span);
@@ -760,14 +760,14 @@ impl<'a> Parser<'a> {
                     let _ = self.parse_pat_range_end().map_err(|e| e.cancel());
                 }
 
-                self.sess.emit_err(InclusiveRangeExtraEquals { span: span_with_eq });
+                self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq });
             }
             token::Gt if no_space => {
                 let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi();
-                self.sess.emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat });
+                self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat });
             }
             _ => {
-                self.sess.emit_err(InclusiveRangeNoEnd { span });
+                self.dcx().emit_err(InclusiveRangeNoEnd { span });
             }
         }
     }
@@ -780,7 +780,7 @@ impl<'a> Parser<'a> {
         let end = self.parse_pat_range_end()?;
         if let RangeEnd::Included(syn @ RangeSyntax::DotDotDot) = &mut re.node {
             *syn = RangeSyntax::DotDotEq;
-            self.sess.emit_err(DotDotDotRangeToPatternNotAllowed { span: re.span });
+            self.dcx().emit_err(DotDotDotRangeToPatternNotAllowed { span: re.span });
         }
         Ok(PatKind::Range(None, Some(end), re))
     }
@@ -854,7 +854,7 @@ impl<'a> Parser<'a> {
             && self.check_noexpect(&token::Lt)
             && self.look_ahead(1, |t| t.can_begin_type())
         {
-            return Err(self.sess.create_err(GenericArgsInPatRequireTurbofishSyntax {
+            return Err(self.dcx().create_err(GenericArgsInPatRequireTurbofishSyntax {
                 span: self.token.span,
                 suggest_turbofish: self.token.span.shrink_to_lo(),
             }));
@@ -942,7 +942,7 @@ impl<'a> Parser<'a> {
 
         if self.isnt_pattern_start() {
             let descr = super::token_descr(&self.token);
-            self.sess.emit_err(errors::BoxNotPat {
+            self.dcx().emit_err(errors::BoxNotPat {
                 span: self.token.span,
                 kw: box_span,
                 lo: box_span.shrink_to_lo(),
@@ -1029,7 +1029,7 @@ impl<'a> Parser<'a> {
                 }
                 let token_str = super::token_descr(&self.token);
                 let msg = format!("expected `}}`, found {token_str}");
-                let mut err = self.struct_span_err(self.token.span, msg);
+                let mut err = self.dcx().struct_span_err(self.token.span, msg);
 
                 err.span_label(self.token.span, "expected `}`");
                 let mut comma_sp = None;
@@ -1170,7 +1170,7 @@ impl<'a> Parser<'a> {
         }
 
         let token_str = pprust::token_to_string(&self.token);
-        self.sess.emit_err(DotDotDotForRemainingFields { span: self.token.span, token_str });
+        self.dcx().emit_err(DotDotDotForRemainingFields { span: self.token.span, token_str });
     }
 
     fn parse_pat_field(&mut self, lo: Span, attrs: AttrVec) -> PResult<'a, PatField> {
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 405531c1e4196..4253c0ae421a6 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -175,7 +175,7 @@ impl<'a> Parser<'a> {
                     .filter_map(|segment| segment.args.as_ref())
                     .map(|arg| arg.span())
                     .collect::<Vec<_>>();
-                parser.sess.emit_err(errors::GenericsInPath { span });
+                parser.dcx().emit_err(errors::GenericsInPath { span });
             }
         };
 
@@ -246,7 +246,7 @@ impl<'a> Parser<'a> {
                         && self.look_ahead(1, |token| self.token.span.hi() == token.span.lo())
                     {
                         self.bump(); // bump past the colon
-                        self.sess.emit_err(PathSingleColon {
+                        self.dcx().emit_err(PathSingleColon {
                             span: self.prev_token.span,
                             type_ascription: self
                                 .sess
@@ -350,7 +350,7 @@ impl<'a> Parser<'a> {
                     && self.look_ahead(1, |tok| tok.kind == token::DotDot)
                 {
                     self.bump();
-                    self.sess
+                    self.dcx()
                         .emit_err(errors::BadReturnTypeNotationDotDot { span: self.token.span });
                     self.bump();
                     self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
@@ -359,7 +359,7 @@ impl<'a> Parser<'a> {
                     if self.eat_noexpect(&token::RArrow) {
                         let lo = self.prev_token.span;
                         let ty = self.parse_ty()?;
-                        self.sess
+                        self.dcx()
                             .emit_err(errors::BadReturnTypeNotationOutput { span: lo.to(ty.span) });
                     }
 
@@ -535,7 +535,7 @@ impl<'a> Parser<'a> {
                     // i.e. no multibyte characters, in this range.
                     let span = lo
                         .with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count.into()));
-                    self.sess.emit_err(errors::UnmatchedAngle {
+                    self.dcx().emit_err(errors::UnmatchedAngle {
                         span,
                         plural: snapshot.unmatched_angle_bracket_count > 1,
                     });
@@ -614,7 +614,7 @@ impl<'a> Parser<'a> {
                         // FIXME(compiler-errors): this could be improved by suggesting lifting
                         // this up to the trait, at least before this becomes real syntax.
                         // e.g. `Trait<for<'a> Assoc = Ty>` -> `for<'a> Trait<Assoc = Ty>`
-                        return Err(self.struct_span_err(
+                        return Err(self.dcx().struct_span_err(
                             arg_span,
                             "`for<...>` is not allowed on associated type bounds",
                         ));
@@ -678,13 +678,14 @@ impl<'a> Parser<'a> {
                 c.into()
             }
             Some(GenericArg::Lifetime(lt)) => {
-                self.sess.emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span });
+                self.dcx().emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span });
                 self.mk_ty(span, ast::TyKind::Err).into()
             }
             None => {
                 let after_eq = eq.shrink_to_hi();
                 let before_next = self.token.span.shrink_to_lo();
                 let mut err = self
+                    .dcx()
                     .struct_span_err(after_eq.to(before_next), "missing type to the right of `=`");
                 if matches!(self.token.kind, token::Comma | token::Gt) {
                     err.span_suggestion(
@@ -783,10 +784,13 @@ impl<'a> Parser<'a> {
                         && let Some(expr) =
                             self.recover_unbraced_const_arg_that_can_begin_ty(snapshot)
                     {
-                        return Ok(Some(self.dummy_const_arg_needs_braces(
-                            self.struct_span_err(expr.span, "invalid const generic expression"),
-                            expr.span,
-                        )));
+                        return Ok(Some(
+                            self.dummy_const_arg_needs_braces(
+                                self.dcx()
+                                    .struct_span_err(expr.span, "invalid const generic expression"),
+                                expr.span,
+                            ),
+                        ));
                     }
 
                     GenericArg::Type(ty)
@@ -811,7 +815,7 @@ impl<'a> Parser<'a> {
             match self.parse_expr_res(Restrictions::CONST_EXPR, None) {
                 Ok(expr) => {
                     return Ok(Some(self.dummy_const_arg_needs_braces(
-                        self.struct_span_err(expr.span, "invalid const generic expression"),
+                        self.dcx().struct_span_err(expr.span, "invalid const generic expression"),
                         expr.span,
                     )));
                 }
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 1ac5aba212c23..831edcd88c11b 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -66,7 +66,7 @@ impl<'a> Parser<'a> {
         if self.token.is_keyword(kw::Mut) && self.is_keyword_ahead(1, &[kw::Let]) {
             self.bump();
             let mut_let_span = lo.to(self.token.span);
-            self.sess.emit_err(errors::InvalidVariableDeclaration {
+            self.dcx().emit_err(errors::InvalidVariableDeclaration {
                 span: mut_let_span,
                 sub: errors::InvalidVariableDeclarationSub::SwitchMutLetOrder(mut_let_span),
             });
@@ -140,7 +140,7 @@ impl<'a> Parser<'a> {
                 let bl = self.parse_block()?;
                 // Destructuring assignment ... else.
                 // This is not allowed, but point it out in a nice way.
-                self.sess.emit_err(errors::AssignmentElseNotAllowed { span: e.span.to(bl.span) });
+                self.dcx().emit_err(errors::AssignmentElseNotAllowed { span: e.span.to(bl.span) });
             }
             self.mk_stmt(lo.to(e.span), StmtKind::Expr(e))
         } else {
@@ -233,12 +233,12 @@ impl<'a> Parser<'a> {
             && let attrs @ [.., last] = &*attrs
         {
             if last.is_doc_comment() {
-                self.sess.emit_err(errors::DocCommentDoesNotDocumentAnything {
+                self.dcx().emit_err(errors::DocCommentDoesNotDocumentAnything {
                     span: last.span,
                     missing_comma: None,
                 });
             } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) {
-                self.sess.emit_err(errors::ExpectedStatementAfterOuterAttr { span: last.span });
+                self.dcx().emit_err(errors::ExpectedStatementAfterOuterAttr { span: last.span });
             }
         }
     }
@@ -258,7 +258,8 @@ impl<'a> Parser<'a> {
                     TrailingToken::None,
                 ))
             })?;
-        self.sess.emit_err(errors::InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
+        self.dcx()
+            .emit_err(errors::InvalidVariableDeclaration { span: lo, sub: subdiagnostic(lo) });
         Ok(stmt)
     }
 
@@ -286,7 +287,7 @@ impl<'a> Parser<'a> {
         let lo = self.prev_token.span;
 
         if self.token.is_keyword(kw::Const) && self.look_ahead(1, |t| t.is_ident()) {
-            self.sess.emit_err(errors::ConstLetMutuallyExclusive { span: lo.to(self.token.span) });
+            self.dcx().emit_err(errors::ConstLetMutuallyExclusive { span: lo.to(self.token.span) });
             self.bump();
         }
 
@@ -385,7 +386,7 @@ impl<'a> Parser<'a> {
     fn check_let_else_init_bool_expr(&self, init: &ast::Expr) {
         if let ast::ExprKind::Binary(op, ..) = init.kind {
             if op.node.is_lazy() {
-                self.sess.emit_err(errors::InvalidExpressionInLetElse {
+                self.dcx().emit_err(errors::InvalidExpressionInLetElse {
                     span: init.span,
                     operator: op.node.as_str(),
                     sugg: errors::WrapExpressionInParentheses {
@@ -399,7 +400,7 @@ impl<'a> Parser<'a> {
 
     fn check_let_else_init_trailing_brace(&self, init: &ast::Expr) {
         if let Some(trailing) = classify::expr_trailing_brace(init) {
-            self.sess.emit_err(errors::InvalidCurlyInLetElse {
+            self.dcx().emit_err(errors::InvalidCurlyInLetElse {
                 span: trailing.span.with_lo(trailing.span.hi() - BytePos(1)),
                 sugg: errors::WrapExpressionInParentheses {
                     left: trailing.span.shrink_to_lo(),
@@ -414,7 +415,7 @@ impl<'a> Parser<'a> {
         let eq_consumed = match self.token.kind {
             token::BinOpEq(..) => {
                 // Recover `let x <op>= 1` as `let x = 1`
-                self.sess
+                self.dcx()
                     .emit_err(errors::CompoundAssignmentExpressionInLet { span: self.token.span });
                 self.bump();
                 true
@@ -444,7 +445,7 @@ impl<'a> Parser<'a> {
         msg: Cow<'static, str>,
     ) -> DiagnosticBuilder<'a> {
         let sp = self.token.span;
-        let mut e = self.struct_span_err(sp, msg);
+        let mut e = self.dcx().struct_span_err(sp, msg);
         let do_not_suggest_help = self.token.is_keyword(kw::In) || self.token == token::Colon;
 
         // Check to see if the user has written something like
@@ -698,7 +699,7 @@ impl<'a> Parser<'a> {
                                         match self.parse_expr_labeled(label, false) {
                                             Ok(labeled_expr) => {
                                                 e.delay_as_bug();
-                                                self.sess.emit_err(MalformedLoopLabel {
+                                                self.dcx().emit_err(MalformedLoopLabel {
                                                     span: label.ident.span,
                                                     correct_label: label.ident,
                                                 });
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index f89d6d1d9659c..42ab23d62923a 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -213,7 +213,7 @@ impl<'a> Parser<'a> {
             // Don't `eat` to prevent `=>` from being added as an expected token which isn't
             // actually expected and could only confuse users
             self.bump();
-            self.sess.emit_err(ReturnTypesUseThinArrow { span: self.prev_token.span });
+            self.dcx().emit_err(ReturnTypesUseThinArrow { span: self.prev_token.span });
             let ty = self.parse_ty_common(
                 allow_plus,
                 AllowCVariadic::No,
@@ -288,7 +288,7 @@ impl<'a> Parser<'a> {
                     let parse_plus = allow_plus == AllowPlus::Yes && self.check_plus();
                     let kind =
                         self.parse_remaining_bounds_path(lifetime_defs, path, lo, parse_plus)?;
-                    let mut err = self.sess.create_err(errors::TransposeDynOrImpl {
+                    let mut err = self.dcx().create_err(errors::TransposeDynOrImpl {
                         span: kw.span,
                         kw: kw.name.as_str(),
                         sugg: errors::TransposeDynOrImplSugg {
@@ -335,13 +335,13 @@ impl<'a> Parser<'a> {
                 AllowCVariadic::No => {
                     // FIXME(Centril): Should we just allow `...` syntactically
                     // anywhere in a type and use semantic restrictions instead?
-                    self.sess.emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) });
+                    self.dcx().emit_err(NestedCVariadicType { span: lo.to(self.prev_token.span) });
                     TyKind::Err
                 }
             }
         } else {
             let msg = format!("expected type, found {}", super::token_descr(&self.token));
-            let mut err = self.struct_span_err(self.token.span, msg);
+            let mut err = self.dcx().struct_span_err(self.token.span, msg);
             err.span_label(self.token.span, "expected type");
             return Err(err);
         };
@@ -426,7 +426,7 @@ impl<'a> Parser<'a> {
         let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus());
         let bounds = self.parse_generic_bounds_common(allow_plus)?;
         if lt_no_plus {
-            self.sess.emit_err(NeedPlusAfterTraitObjectLifetime { span: lo });
+            self.dcx().emit_err(NeedPlusAfterTraitObjectLifetime { span: lo });
         }
         Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
     }
@@ -460,7 +460,7 @@ impl<'a> Parser<'a> {
     fn parse_ty_ptr(&mut self) -> PResult<'a, TyKind> {
         let mutbl = self.parse_const_or_mut().unwrap_or_else(|| {
             let span = self.prev_token.span;
-            self.sess.emit_err(ExpectedMutOrConstInRawPointerType {
+            self.dcx().emit_err(ExpectedMutOrConstInRawPointerType {
                 span,
                 after_asterisk: span.shrink_to_hi(),
             });
@@ -523,7 +523,7 @@ impl<'a> Parser<'a> {
                     } else {
                         (None, String::new())
                     };
-                self.sess.emit_err(LifetimeAfterMut { span, suggest_lifetime, snippet });
+                self.dcx().emit_err(LifetimeAfterMut { span, suggest_lifetime, snippet });
 
                 opt_lifetime = Some(self.expect_lifetime());
             }
@@ -533,7 +533,7 @@ impl<'a> Parser<'a> {
         {
             // We have `&dyn mut ...`, which is invalid and should be `&mut dyn ...`.
             let span = and_span.to(self.look_ahead(1, |t| t.span));
-            self.sess.emit_err(DynAfterMut { span });
+            self.dcx().emit_err(DynAfterMut { span });
 
             // Recovery
             mutbl = Mutability::Mut;
@@ -587,10 +587,10 @@ impl<'a> Parser<'a> {
             // If we ever start to allow `const fn()`, then update
             // feature gating for `#![feature(const_extern_fn)]` to
             // cover it.
-            self.sess.emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span });
+            self.dcx().emit_err(FnPointerCannotBeConst { span: whole_span, qualifier: span });
         }
         if let Some(ast::CoroutineKind::Async { span, .. }) = coroutine_kind {
-            self.sess.emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span });
+            self.dcx().emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span });
         }
         // FIXME(gen_blocks): emit a similar error for `gen fn()`
         let decl_span = span_start.to(self.token.span);
@@ -634,7 +634,7 @@ impl<'a> Parser<'a> {
             None
         };
 
-        self.sess.emit_err(FnPtrWithGenerics { span: generics.span, sugg });
+        self.dcx().emit_err(FnPtrWithGenerics { span: generics.span, sugg });
         params.append(&mut lifetimes);
         Ok(())
     }
@@ -647,7 +647,7 @@ impl<'a> Parser<'a> {
                 if let token::Ident(sym, _) = t.kind {
                     // parse pattern with "'a Sized" we're supposed to give suggestion like
                     // "'a + Sized"
-                    self.sess.emit_err(errors::MissingPlusBounds {
+                    self.dcx().emit_err(errors::MissingPlusBounds {
                         span: self.token.span,
                         hi: self.token.span.shrink_to_hi(),
                         sym,
@@ -739,7 +739,7 @@ impl<'a> Parser<'a> {
         {
             if self.token.is_keyword(kw::Dyn) {
                 // Account for `&dyn Trait + dyn Other`.
-                self.sess.emit_err(InvalidDynKeyword { span: self.token.span });
+                self.dcx().emit_err(InvalidDynKeyword { span: self.token.span });
                 self.bump();
             }
             bounds.push(self.parse_generic_bound()?);
@@ -813,14 +813,14 @@ impl<'a> Parser<'a> {
         match modifiers.constness {
             BoundConstness::Never => {}
             BoundConstness::Maybe(span) => {
-                self.sess.emit_err(errors::TildeConstLifetime { span });
+                self.dcx().emit_err(errors::TildeConstLifetime { span });
             }
         }
 
         match modifiers.polarity {
             BoundPolarity::Positive => {}
             BoundPolarity::Negative(span) | BoundPolarity::Maybe(span) => {
-                self.sess.emit_err(errors::ModifierLifetime {
+                self.dcx().emit_err(errors::ModifierLifetime {
                     span,
                     sigil: modifiers.polarity.as_str(),
                 });
@@ -839,7 +839,7 @@ impl<'a> Parser<'a> {
             (None, String::new())
         };
 
-        self.sess.emit_err(errors::ParenthesizedLifetime { span, sugg, snippet });
+        self.dcx().emit_err(errors::ParenthesizedLifetime { span, sugg, snippet });
         Ok(())
     }
 
@@ -860,7 +860,7 @@ impl<'a> Parser<'a> {
         } else if self.eat_keyword(kw::Const) {
             let span = self.prev_token.span;
             self.sess.gated_spans.gate(sym::const_trait_impl, span);
-            self.sess.emit_err(errors::ConstMissingTilde { span, start: span.shrink_to_lo() });
+            self.dcx().emit_err(errors::ConstMissingTilde { span, start: span.shrink_to_lo() });
 
             BoundConstness::Maybe(span)
         } else {
@@ -902,7 +902,7 @@ impl<'a> Parser<'a> {
         } else if !self.token.is_path_start() && self.token.can_begin_type() {
             let ty = self.parse_ty_no_plus()?;
             // Instead of finding a path (a trait), we found a type.
-            let mut err = self.struct_span_err(ty.span, "expected a trait, found type");
+            let mut err = self.dcx().struct_span_err(ty.span, "expected a trait, found type");
 
             // If we can recover, try to extract a path from the type. Note
             // that we do not use the try operator when parsing the type because
@@ -960,7 +960,7 @@ impl<'a> Parser<'a> {
                 let bounds = vec![];
                 self.parse_remaining_bounds(bounds, true)?;
                 self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
-                self.sess.emit_err(errors::IncorrectParensTraitBounds {
+                self.dcx().emit_err(errors::IncorrectParensTraitBounds {
                     span: vec![lo, self.prev_token.span],
                     sugg: errors::IncorrectParensTraitBoundsSugg {
                         wrong_span: leading_token.span.shrink_to_hi().to(lo),
@@ -984,7 +984,7 @@ impl<'a> Parser<'a> {
         let snapshot = self.create_snapshot_for_diagnostic();
         match self.parse_fn_decl(|_| false, AllowPlus::No, RecoverReturnSign::OnlyFatArrow) {
             Ok(decl) => {
-                self.sess.emit_err(ExpectedFnPathFoundFnKeyword { fn_token_span });
+                self.dcx().emit_err(ExpectedFnPathFoundFnKeyword { fn_token_span });
                 Some(ast::Path {
                     span: fn_token_span.to(self.prev_token.span),
                     segments: thin_vec![ast::PathSegment {
@@ -1096,8 +1096,9 @@ impl<'a> Parser<'a> {
         lifetime_defs.append(&mut generic_params);
 
         let generic_args_span = generic_args.span();
-        let mut err =
-            self.struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters");
+        let mut err = self
+            .dcx()
+            .struct_span_err(generic_args_span, "`Fn` traits cannot take lifetime parameters");
         let snippet = format!(
             "for<{}> ",
             lifetimes.iter().map(|lt| lt.ident.as_str()).intersperse(", ").collect::<String>(),
@@ -1123,7 +1124,7 @@ impl<'a> Parser<'a> {
             self.bump();
             Lifetime { ident, id: ast::DUMMY_NODE_ID }
         } else {
-            self.span_bug(self.token.span, "not a lifetime")
+            self.dcx().span_bug(self.token.span, "not a lifetime")
         }
     }
 
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 9fea3826652c6..4efb1be03bee0 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -105,7 +105,7 @@ pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: Delimiter)
     if let Delimiter::Parenthesis = delim {
         return;
     }
-    sess.emit_err(errors::MetaBadDelim {
+    sess.dcx.emit_err(errors::MetaBadDelim {
         span: span.entire(),
         sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close },
     });
@@ -115,7 +115,7 @@ pub fn check_cfg_attr_bad_delim(sess: &ParseSess, span: DelimSpan, delim: Delimi
     if let Delimiter::Parenthesis = delim {
         return;
     }
-    sess.emit_err(errors::CfgAttrBadDelim {
+    sess.dcx.emit_err(errors::CfgAttrBadDelim {
         span: span.entire(),
         sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close },
     });
diff --git a/compiler/rustc_passes/src/abi_test.rs b/compiler/rustc_passes/src/abi_test.rs
index 153c39977bb44..986ef69ad8849 100644
--- a/compiler/rustc_passes/src/abi_test.rs
+++ b/compiler/rustc_passes/src/abi_test.rs
@@ -25,7 +25,7 @@ pub fn test_abi(tcx: TyCtxt<'_>) {
                     dump_abi_of_fn_type(tcx, id, attr);
                 }
                 _ => {
-                    tcx.sess.emit_err(AbiInvalidAttribute { span: tcx.def_span(id) });
+                    tcx.dcx().emit_err(AbiInvalidAttribute { span: tcx.def_span(id) });
                 }
             }
         }
@@ -40,7 +40,7 @@ fn unwrap_fn_abi<'tcx>(
     match abi {
         Ok(abi) => abi,
         Err(FnAbiError::Layout(layout_error)) => {
-            tcx.sess.emit_fatal(Spanned {
+            tcx.dcx().emit_fatal(Spanned {
                 node: layout_error.into_diagnostic(),
                 span: tcx.def_span(item_def_id),
             });
@@ -65,7 +65,7 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
         Ok(None) => {
             // Not sure what to do here, but `LayoutError::Unknown` seems reasonable?
             let ty = tcx.type_of(item_def_id).instantiate_identity();
-            tcx.sess.emit_fatal(Spanned {
+            tcx.dcx().emit_fatal(Spanned {
                 node: LayoutError::Unknown(ty).into_diagnostic(),
 
                 span: tcx.def_span(item_def_id),
@@ -86,7 +86,7 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
         match meta_item.name_or_empty() {
             sym::debug => {
                 let fn_name = tcx.item_name(item_def_id.into());
-                tcx.sess.emit_err(AbiOf {
+                tcx.dcx().emit_err(AbiOf {
                     span: tcx.def_span(item_def_id),
                     fn_name,
                     // FIXME: using the `Debug` impl here isn't ideal.
@@ -95,7 +95,7 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
             }
 
             name => {
-                tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
+                tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name });
             }
         }
     }
@@ -139,7 +139,7 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
                 );
 
                 let fn_name = tcx.item_name(item_def_id.into());
-                tcx.sess.emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) });
+                tcx.dcx().emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) });
             }
             sym::assert_eq => {
                 let ty::Tuple(fields) = ty.kind() else {
@@ -182,7 +182,7 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
                 );
 
                 if !test_abi_eq(abi1, abi2) {
-                    tcx.sess.emit_err(AbiNe {
+                    tcx.dcx().emit_err(AbiNe {
                         span,
                         left: format!("{:#?}", abi1),
                         right: format!("{:#?}", abi2),
@@ -190,7 +190,7 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
                 }
             }
             name => {
-                tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
+                tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name });
             }
         }
     }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index c5073048be3e8..edce99db7050c 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -7,7 +7,7 @@
 use crate::{errors, fluent_generated as fluent};
 use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{Applicability, IntoDiagnosticArg, MultiSpan};
+use rustc_errors::{Applicability, DiagCtxt, IntoDiagnosticArg, MultiSpan};
 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_hir as hir;
 use rustc_hir::def_id::LocalModDefId;
@@ -95,7 +95,11 @@ struct CheckAttrVisitor<'tcx> {
     abort: Cell<bool>,
 }
 
-impl CheckAttrVisitor<'_> {
+impl<'tcx> CheckAttrVisitor<'tcx> {
+    pub fn dcx(&self) -> &'tcx DiagCtxt {
+        self.tcx.dcx()
+    }
+
     /// Checks any attribute.
     fn check_attributes(
         &self,
@@ -292,7 +296,7 @@ impl CheckAttrVisitor<'_> {
         if let Target::Impl = target {
             true
         } else {
-            self.tcx.sess.emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span });
+            self.dcx().emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span });
             false
         }
     }
@@ -343,7 +347,7 @@ impl CheckAttrVisitor<'_> {
                 true
             }
             _ => {
-                self.tcx.sess.emit_err(errors::InlineNotFnOrClosure {
+                self.dcx().emit_err(errors::InlineNotFnOrClosure {
                     attr_span: attr.span,
                     defn_span: span,
                 });
@@ -392,7 +396,7 @@ impl CheckAttrVisitor<'_> {
             }
 
             _ => {
-                self.tcx.sess.emit_err(errors::IgnoredCoverageNotCoverable {
+                self.dcx().emit_err(errors::IgnoredCoverageNotCoverable {
                     attr_span: attr.span,
                     defn_span: span,
                 });
@@ -435,7 +439,7 @@ impl CheckAttrVisitor<'_> {
                 true
             }
             _ => {
-                self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
+                self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
                     attr_span: attr.span,
                     defn_span: span,
                     on_crate: hir_id == CRATE_HIR_ID,
@@ -457,7 +461,7 @@ impl CheckAttrVisitor<'_> {
             Target::Fn
             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
             _ => {
-                self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
+                self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
                     attr_span: attr.span,
                     defn_span: span,
                     on_crate: hir_id == CRATE_HIR_ID,
@@ -482,7 +486,7 @@ impl CheckAttrVisitor<'_> {
                     ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
                     ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
                 };
-                tcx.sess.emit_err(errors::ObjectLifetimeErr { span: p.span, repr });
+                tcx.dcx().emit_err(errors::ObjectLifetimeErr { span: p.span, repr });
             }
         }
     }
@@ -493,7 +497,7 @@ impl CheckAttrVisitor<'_> {
             Target::MacroDef => true,
             _ => {
                 self.tcx
-                    .sess
+                    .dcx()
                     .emit_err(errors::CollapseDebuginfo { attr_span: attr.span, defn_span: span });
                 false
             }
@@ -511,7 +515,7 @@ impl CheckAttrVisitor<'_> {
     ) -> bool {
         match target {
             _ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => {
-                self.tcx.sess.emit_err(errors::NakedTrackedCaller { attr_span });
+                self.dcx().emit_err(errors::NakedTrackedCaller { attr_span });
                 false
             }
             Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
@@ -526,7 +530,7 @@ impl CheckAttrVisitor<'_> {
                 true
             }
             _ => {
-                self.tcx.sess.emit_err(errors::TrackedCallerWrongLocation {
+                self.dcx().emit_err(errors::TrackedCallerWrongLocation {
                     attr_span,
                     defn_span: span,
                     on_crate: hir_id == CRATE_HIR_ID,
@@ -555,7 +559,7 @@ impl CheckAttrVisitor<'_> {
                 true
             }
             _ => {
-                self.tcx.sess.emit_err(errors::NonExhaustiveWrongLocation {
+                self.dcx().emit_err(errors::NonExhaustiveWrongLocation {
                     attr_span: attr.span,
                     defn_span: span,
                 });
@@ -577,7 +581,7 @@ impl CheckAttrVisitor<'_> {
                 true
             }
             _ => {
-                self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait {
+                self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
                     attr_span: attr.span,
                     defn_span: span,
                 });
@@ -612,7 +616,7 @@ impl CheckAttrVisitor<'_> {
                         unreachable!();
                     };
 
-                    self.tcx.sess.emit_err(errors::LangItemWithTargetFeature {
+                    self.dcx().emit_err(errors::LangItemWithTargetFeature {
                         attr_span: attr.span,
                         name: lang_item,
                         sig_span: sig.span,
@@ -643,7 +647,7 @@ impl CheckAttrVisitor<'_> {
                 true
             }
             _ => {
-                self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
+                self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
                     attr_span: attr.span,
                     defn_span: span,
                     on_crate: hir_id == CRATE_HIR_ID,
@@ -658,7 +662,7 @@ impl CheckAttrVisitor<'_> {
         match target {
             Target::ForeignStatic | Target::Static => true,
             _ => {
-                self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToStatic {
+                self.dcx().emit_err(errors::AttrShouldBeAppliedToStatic {
                     attr_span: attr.span,
                     defn_span: span,
                 });
@@ -668,7 +672,7 @@ impl CheckAttrVisitor<'_> {
     }
 
     fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) {
-        self.tcx.sess.emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name });
+        self.dcx().emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name });
     }
 
     fn check_doc_alias_value(
@@ -685,7 +689,7 @@ impl CheckAttrVisitor<'_> {
         let attr_str =
             &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" });
         if doc_alias == kw::Empty {
-            tcx.sess.emit_err(errors::DocAliasEmpty { span, attr_str });
+            tcx.dcx().emit_err(errors::DocAliasEmpty { span, attr_str });
             return false;
         }
 
@@ -694,11 +698,11 @@ impl CheckAttrVisitor<'_> {
             .chars()
             .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
         {
-            tcx.sess.emit_err(errors::DocAliasBadChar { span, attr_str, char_: c });
+            tcx.dcx().emit_err(errors::DocAliasBadChar { span, attr_str, char_: c });
             return false;
         }
         if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') {
-            tcx.sess.emit_err(errors::DocAliasStartEnd { span, attr_str });
+            tcx.dcx().emit_err(errors::DocAliasStartEnd { span, attr_str });
             return false;
         }
 
@@ -756,12 +760,12 @@ impl CheckAttrVisitor<'_> {
             | Target::PatField
             | Target::ExprField => None,
         } {
-            tcx.sess.emit_err(errors::DocAliasBadLocation { span, attr_str, location });
+            tcx.dcx().emit_err(errors::DocAliasBadLocation { span, attr_str, location });
             return false;
         }
         let item_name = self.tcx.hir().name(hir_id);
         if item_name == doc_alias {
-            tcx.sess.emit_err(errors::DocAliasNotAnAlias { span, attr_str });
+            tcx.dcx().emit_err(errors::DocAliasNotAnAlias { span, attr_str });
             return false;
         }
         if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) {
@@ -794,13 +798,15 @@ impl CheckAttrVisitor<'_> {
                         }
                         _ => {
                             self.tcx
-                                .sess
+                                .dcx()
                                 .emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
                             errors += 1;
                         }
                     },
                     None => {
-                        self.tcx.sess.emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
+                        self.tcx
+                            .dcx()
+                            .emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
                         errors += 1;
                     }
                 }
@@ -809,7 +815,7 @@ impl CheckAttrVisitor<'_> {
         } else if let Some(doc_alias) = meta.value_str() {
             self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases)
         } else {
-            self.tcx.sess.emit_err(errors::DocAliasMalformed { span: meta.span() });
+            self.dcx().emit_err(errors::DocAliasMalformed { span: meta.span() });
             false
         }
     }
@@ -826,17 +832,17 @@ impl CheckAttrVisitor<'_> {
         }) {
             Some(ItemKind::Mod(module)) => {
                 if !module.item_ids.is_empty() {
-                    self.tcx.sess.emit_err(errors::DocKeywordEmptyMod { span: meta.span() });
+                    self.dcx().emit_err(errors::DocKeywordEmptyMod { span: meta.span() });
                     return false;
                 }
             }
             _ => {
-                self.tcx.sess.emit_err(errors::DocKeywordNotMod { span: meta.span() });
+                self.dcx().emit_err(errors::DocKeywordNotMod { span: meta.span() });
                 return false;
             }
         }
         if !rustc_lexer::is_ident(doc_keyword.as_str()) {
-            self.tcx.sess.emit_err(errors::DocKeywordInvalidIdent {
+            self.dcx().emit_err(errors::DocKeywordInvalidIdent {
                 span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
                 doc_keyword,
             });
@@ -858,12 +864,12 @@ impl CheckAttrVisitor<'_> {
                         false
                     };
                 if !is_valid {
-                    self.tcx.sess.emit_err(errors::DocFakeVariadicNotValid { span: meta.span() });
+                    self.dcx().emit_err(errors::DocFakeVariadicNotValid { span: meta.span() });
                     return false;
                 }
             }
             _ => {
-                self.tcx.sess.emit_err(errors::DocKeywordOnlyImpl { span: meta.span() });
+                self.dcx().emit_err(errors::DocKeywordOnlyImpl { span: meta.span() });
                 return false;
             }
         }
@@ -898,7 +904,7 @@ impl CheckAttrVisitor<'_> {
                             meta.span(),
                             fluent::passes_doc_inline_conflict_second,
                         );
-                        self.tcx.sess.emit_err(errors::DocKeywordConflict { spans });
+                        self.dcx().emit_err(errors::DocKeywordConflict { spans });
                         return false;
                     }
                     true
@@ -969,7 +975,7 @@ impl CheckAttrVisitor<'_> {
         attr_name: &str,
     ) -> bool {
         if CRATE_HIR_ID == hir_id {
-            self.tcx.sess.emit_err(errors::DocAttrNotCrateLevel { span: meta.span(), attr_name });
+            self.dcx().emit_err(errors::DocAttrNotCrateLevel { span: meta.span(), attr_name });
             return false;
         }
         true
@@ -1243,7 +1249,7 @@ impl CheckAttrVisitor<'_> {
         match target {
             Target::Struct | Target::Enum | Target::TyAlias => true,
             _ => {
-                self.tcx.sess.emit_err(errors::PassByValue { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::PassByValue { attr_span: attr.span, span });
                 false
             }
         }
@@ -1253,7 +1259,7 @@ impl CheckAttrVisitor<'_> {
         match target {
             Target::Method(MethodKind::Inherent) => true,
             _ => {
-                self.tcx.sess.emit_err(errors::AllowIncoherentImpl { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span: attr.span, span });
                 false
             }
         }
@@ -1271,7 +1277,7 @@ impl CheckAttrVisitor<'_> {
             }
             _ => {
                 self.tcx
-                    .sess
+                    .dcx()
                     .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span, span });
                 false
             }
@@ -1280,12 +1286,12 @@ impl CheckAttrVisitor<'_> {
 
     fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute], target: Target) -> bool {
         if target != Target::ForeignFn {
-            self.tcx.sess.emit_err(errors::FfiPureInvalidTarget { attr_span });
+            self.dcx().emit_err(errors::FfiPureInvalidTarget { attr_span });
             return false;
         }
         if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
             // `#[ffi_const]` functions cannot be `#[ffi_pure]`
-            self.tcx.sess.emit_err(errors::BothFfiConstAndPure { attr_span });
+            self.dcx().emit_err(errors::BothFfiConstAndPure { attr_span });
             false
         } else {
             true
@@ -1296,7 +1302,7 @@ impl CheckAttrVisitor<'_> {
         if target == Target::ForeignFn {
             true
         } else {
-            self.tcx.sess.emit_err(errors::FfiConstInvalidTarget { attr_span });
+            self.dcx().emit_err(errors::FfiConstInvalidTarget { attr_span });
             false
         }
     }
@@ -1305,7 +1311,7 @@ impl CheckAttrVisitor<'_> {
         if target == Target::ForeignFn {
             true
         } else {
-            self.tcx.sess.emit_err(errors::FfiReturnsTwiceInvalidTarget { attr_span });
+            self.dcx().emit_err(errors::FfiReturnsTwiceInvalidTarget { attr_span });
             false
         }
     }
@@ -1354,7 +1360,7 @@ impl CheckAttrVisitor<'_> {
         match target {
             Target::Struct | Target::Enum | Target::Union | Target::Trait => true,
             _ => {
-                self.tcx.sess.emit_err(errors::MustNotSuspend { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span, span });
                 false
             }
         }
@@ -1449,7 +1455,7 @@ impl CheckAttrVisitor<'_> {
                 true
             }
             _ => {
-                self.tcx.sess.emit_err(errors::NoLink { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::NoLink { attr_span: attr.span, span });
                 false
             }
         }
@@ -1479,7 +1485,7 @@ impl CheckAttrVisitor<'_> {
                 true
             }
             _ => {
-                self.tcx.sess.emit_err(errors::ExportName { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::ExportName { attr_span: attr.span, span });
                 false
             }
         }
@@ -1492,7 +1498,7 @@ impl CheckAttrVisitor<'_> {
         target: Target,
     ) -> bool {
         if target != Target::Struct {
-            self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeNotStruct {
+            self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct {
                 attr_span: attr.span,
                 span,
             });
@@ -1506,7 +1512,9 @@ impl CheckAttrVisitor<'_> {
         if matches!(&list[..], &[NestedMetaItem::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) {
             true
         } else {
-            self.tcx.sess.emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span });
+            self.tcx
+                .dcx()
+                .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span });
             false
         }
     }
@@ -1522,7 +1530,7 @@ impl CheckAttrVisitor<'_> {
     ) -> bool {
         let is_function = matches!(target, Target::Fn);
         if !is_function {
-            self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
+            self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
                 attr_span: attr.span,
                 defn_span: span,
                 on_crate: hir_id == CRATE_HIR_ID,
@@ -1546,7 +1554,7 @@ impl CheckAttrVisitor<'_> {
             match param.kind {
                 hir::GenericParamKind::Const { .. } => {}
                 _ => {
-                    self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsOnly {
+                    self.dcx().emit_err(errors::RustcLegacyConstGenericsOnly {
                         attr_span: attr.span,
                         param_span: param.span,
                     });
@@ -1556,7 +1564,7 @@ impl CheckAttrVisitor<'_> {
         }
 
         if list.len() != generics.params.len() {
-            self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndex {
+            self.dcx().emit_err(errors::RustcLegacyConstGenericsIndex {
                 attr_span: attr.span,
                 generics_span: generics.span,
             });
@@ -1569,7 +1577,7 @@ impl CheckAttrVisitor<'_> {
             if let Some(LitKind::Int(val, _)) = meta.lit().map(|lit| &lit.kind) {
                 if *val >= arg_count {
                     let span = meta.span();
-                    self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexExceed {
+                    self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexExceed {
                         span,
                         arg_count: arg_count as usize,
                     });
@@ -1581,7 +1589,7 @@ impl CheckAttrVisitor<'_> {
         }
 
         if !invalid_args.is_empty() {
-            self.tcx.sess.emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args });
+            self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args });
             false
         } else {
             true
@@ -1599,7 +1607,7 @@ impl CheckAttrVisitor<'_> {
     ) -> bool {
         let is_function = matches!(target, Target::Fn | Target::Method(..));
         if !is_function {
-            self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToFn {
+            self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
                 attr_span: attr.span,
                 defn_span: span,
                 on_crate: hir_id == CRATE_HIR_ID,
@@ -1639,7 +1647,7 @@ impl CheckAttrVisitor<'_> {
         match target {
             Target::Struct => true,
             _ => {
-                self.tcx.sess.emit_err(errors::RustcLintOptTy { attr_span: attr.span, span });
+                self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span, span });
                 false
             }
         }
@@ -1656,7 +1664,7 @@ impl CheckAttrVisitor<'_> {
             Target::Field => true,
             _ => {
                 self.tcx
-                    .sess
+                    .dcx()
                     .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span, span });
                 false
             }
@@ -1669,7 +1677,7 @@ impl CheckAttrVisitor<'_> {
         if self.tcx.sess.opts.unstable_opts.query_dep_graph {
             true
         } else {
-            self.tcx.sess.emit_err(errors::RustcDirtyClean { span: attr.span });
+            self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span });
             false
         }
     }
@@ -1679,7 +1687,7 @@ impl CheckAttrVisitor<'_> {
         match target {
             Target::Trait => true,
             _ => {
-                self.tcx.sess.emit_err(errors::AttrShouldBeAppliedToTrait {
+                self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
                     attr_span: attr.span,
                     defn_span: span,
                 });
@@ -1782,7 +1790,7 @@ impl CheckAttrVisitor<'_> {
 
         for hint in &hints {
             if !hint.is_meta_item() {
-                self.tcx.sess.emit_err(errors::ReprIdent { span: hint.span() });
+                self.dcx().emit_err(errors::ReprIdent { span: hint.span() });
                 continue;
             }
 
@@ -1795,7 +1803,7 @@ impl CheckAttrVisitor<'_> {
                     match target {
                         Target::Struct | Target::Union | Target::Enum => continue,
                         _ => {
-                            self.tcx.sess.emit_err(errors::AttrApplication::StructEnumUnion {
+                            self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
                                 hint_span: hint.span(),
                                 span,
                             });
@@ -1822,7 +1830,7 @@ impl CheckAttrVisitor<'_> {
                         | Target::Fn
                         | Target::Method(_) => continue,
                         _ => {
-                            self.tcx.sess.emit_err(
+                            self.dcx().emit_err(
                                 errors::AttrApplication::StructEnumFunctionMethodUnion {
                                     hint_span: hint.span(),
                                     span,
@@ -1833,7 +1841,7 @@ impl CheckAttrVisitor<'_> {
                 }
                 sym::packed => {
                     if target != Target::Struct && target != Target::Union {
-                        self.tcx.sess.emit_err(errors::AttrApplication::StructUnion {
+                        self.dcx().emit_err(errors::AttrApplication::StructUnion {
                             hint_span: hint.span(),
                             span,
                         });
@@ -1844,7 +1852,7 @@ impl CheckAttrVisitor<'_> {
                 sym::simd => {
                     is_simd = true;
                     if target != Target::Struct {
-                        self.tcx.sess.emit_err(errors::AttrApplication::Struct {
+                        self.dcx().emit_err(errors::AttrApplication::Struct {
                             hint_span: hint.span(),
                             span,
                         });
@@ -1857,7 +1865,7 @@ impl CheckAttrVisitor<'_> {
                     match target {
                         Target::Struct | Target::Union | Target::Enum => continue,
                         _ => {
-                            self.tcx.sess.emit_err(errors::AttrApplication::StructEnumUnion {
+                            self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
                                 hint_span: hint.span(),
                                 span,
                             });
@@ -1878,7 +1886,7 @@ impl CheckAttrVisitor<'_> {
                 | sym::usize => {
                     int_reprs += 1;
                     if target != Target::Enum {
-                        self.tcx.sess.emit_err(errors::AttrApplication::Enum {
+                        self.dcx().emit_err(errors::AttrApplication::Enum {
                             hint_span: hint.span(),
                             span,
                         });
@@ -1887,7 +1895,7 @@ impl CheckAttrVisitor<'_> {
                     }
                 }
                 _ => {
-                    self.tcx.sess.emit_err(errors::UnrecognizedReprHint { span: hint.span() });
+                    self.dcx().emit_err(errors::UnrecognizedReprHint { span: hint.span() });
                     continue;
                 }
             };
@@ -1900,14 +1908,14 @@ impl CheckAttrVisitor<'_> {
         // Error on repr(transparent, <anything else>).
         if is_transparent && hints.len() > 1 {
             let hint_spans = hint_spans.clone().collect();
-            self.tcx.sess.emit_err(errors::TransparentIncompatible {
+            self.dcx().emit_err(errors::TransparentIncompatible {
                 hint_spans,
                 target: target.to_string(),
             });
         }
         if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) {
             let hint_spans = hint_spans.clone().collect();
-            self.tcx.sess.emit_err(errors::ReprConflicting { hint_spans });
+            self.dcx().emit_err(errors::ReprConflicting { hint_spans });
         }
         // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
         if (int_reprs > 1)
@@ -1935,7 +1943,7 @@ impl CheckAttrVisitor<'_> {
         let mut used_compiler_span = None;
         for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) {
             if target != Target::Static {
-                self.tcx.sess.emit_err(errors::UsedStatic { span: attr.span });
+                self.dcx().emit_err(errors::UsedStatic { span: attr.span });
             }
             let inner = attr.meta_item_list();
             match inner.as_deref() {
@@ -1962,7 +1970,7 @@ impl CheckAttrVisitor<'_> {
         }
         if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
             self.tcx
-                .sess
+                .dcx()
                 .emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] });
         }
     }
@@ -2004,7 +2012,7 @@ impl CheckAttrVisitor<'_> {
             }
             _ => {
                 self.tcx
-                    .sess
+                    .dcx()
                     .emit_err(errors::AllowInternalUnstable { attr_span: attr.span, span });
                 false
             }
@@ -2020,7 +2028,7 @@ impl CheckAttrVisitor<'_> {
         match target {
             Target::Mod => {}
             _ => {
-                self.tcx.sess.emit_err(errors::DebugVisualizerPlacement { span: attr.span });
+                self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span });
                 return false;
             }
         }
@@ -2053,7 +2061,7 @@ impl CheckAttrVisitor<'_> {
             }
             _ => {
                 self.tcx
-                    .sess
+                    .dcx()
                     .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span, span });
                 false
             }
@@ -2079,7 +2087,7 @@ impl CheckAttrVisitor<'_> {
             return true;
         }
 
-        self.tcx.sess.emit_err(errors::RustcSafeIntrinsic { attr_span: attr.span, span });
+        self.dcx().emit_err(errors::RustcSafeIntrinsic { attr_span: attr.span, span });
         false
     }
 
@@ -2093,7 +2101,7 @@ impl CheckAttrVisitor<'_> {
             Target::Fn | Target::Static => true,
             _ => {
                 self.tcx
-                    .sess
+                    .dcx()
                     .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span, span });
                 false
             }
@@ -2103,7 +2111,7 @@ impl CheckAttrVisitor<'_> {
     fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
         match target {
             Target::Expression => {
-                self.tcx.sess.emit_err(errors::StabilityPromotable { attr_span: attr.span });
+                self.dcx().emit_err(errors::StabilityPromotable { attr_span: attr.span });
                 false
             }
             _ => true,
@@ -2114,7 +2122,7 @@ impl CheckAttrVisitor<'_> {
         match target {
             Target::ForeignFn | Target::ForeignStatic => true,
             _ => {
-                self.tcx.sess.emit_err(errors::LinkOrdinal { attr_span: attr.span });
+                self.dcx().emit_err(errors::LinkOrdinal { attr_span: attr.span });
                 false
             }
         }
@@ -2134,7 +2142,7 @@ impl CheckAttrVisitor<'_> {
 
                 for meta in metas {
                     let NestedMetaItem::Lit(meta_lit) = meta else {
-                        self.tcx.sess.emit_err(errors::IncorrectMetaItem {
+                        self.dcx().emit_err(errors::IncorrectMetaItem {
                             span: meta.span(),
                             suggestion: errors::IncorrectMetaItemSuggestion {
                                 lo: meta.span().shrink_to_lo(),
@@ -2147,14 +2155,14 @@ impl CheckAttrVisitor<'_> {
                 }
 
                 if candidates.is_empty() {
-                    self.tcx.sess.emit_err(errors::EmptyConfusables { span: attr.span });
+                    self.dcx().emit_err(errors::EmptyConfusables { span: attr.span });
                     return false;
                 }
 
                 true
             }
             _ => {
-                self.tcx.sess.emit_err(errors::Confusables { attr_span: attr.span });
+                self.dcx().emit_err(errors::Confusables { attr_span: attr.span });
                 false
             }
         }
@@ -2326,7 +2334,7 @@ impl CheckAttrVisitor<'_> {
         );
 
         if let Err(terr) = ocx.eq(&cause, param_env, expected_sig, sig) {
-            let mut diag = tcx.sess.create_err(errors::ProcMacroBadSig { span, kind });
+            let mut diag = tcx.dcx().create_err(errors::ProcMacroBadSig { span, kind });
 
             let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id);
             if let Some(hir_sig) = hir_sig {
@@ -2531,7 +2539,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
                             span: item.ident.span,
                             kind: item.kind.descr(),
                         });
-                    tcx.sess.emit_err(errors::InvalidAttrAtCrateLevel {
+                    tcx.dcx().emit_err(errors::InvalidAttrAtCrateLevel {
                         span: attr.span,
                         sugg_span: tcx
                             .sess
@@ -2558,7 +2566,7 @@ fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>)
 
     for attr in attrs {
         if attr.has_name(sym::inline) {
-            tcx.sess.emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span });
+            tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span });
         }
     }
 }
@@ -2571,7 +2579,7 @@ fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
         check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
     }
     if check_attr_visitor.abort.get() {
-        tcx.sess.abort_if_errors()
+        tcx.dcx().abort_if_errors()
     }
 }
 
@@ -2629,7 +2637,7 @@ fn check_duplicates(
                 } else {
                     (attr.span, *entry.get())
                 };
-                tcx.sess.emit_err(errors::UnusedMultiple {
+                tcx.dcx().emit_err(errors::UnusedMultiple {
                     this,
                     other,
                     name: attr.name_or_empty(),
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 76c7467346d37..3e5fb1a6b472e 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -122,7 +122,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
             // corresponding feature gate. This encourages nightly users to use feature gates when
             // possible.
             None if tcx.sess.opts.unstable_opts.unleash_the_miri_inside_of_you => {
-                tcx.sess.emit_warning(SkippingConstChecks { span });
+                tcx.dcx().emit_warning(SkippingConstChecks { span });
                 return;
             }
 
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index 3483f7da528ba..f4cd2fbc91fcb 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -17,19 +17,19 @@ impl DebuggerVisualizerCollector<'_> {
     fn check_for_debugger_visualizer(&mut self, attr: &Attribute) {
         if attr.has_name(sym::debugger_visualizer) {
             let Some(hints) = attr.meta_item_list() else {
-                self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
+                self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
                 return;
             };
 
             let hint = if hints.len() == 1 {
                 &hints[0]
             } else {
-                self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
+                self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
                 return;
             };
 
             let Some(meta_item) = hint.meta_item() else {
-                self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
+                self.sess.dcx().emit_err(DebugVisualizerInvalid { span: attr.span });
                 return;
             };
 
@@ -40,7 +40,7 @@ impl DebuggerVisualizerCollector<'_> {
                         (DebuggerVisualizerType::GdbPrettyPrinter, value)
                     }
                     (_, _) => {
-                        self.sess.emit_err(DebugVisualizerInvalid { span: meta_item.span });
+                        self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span });
                         return;
                     }
                 };
@@ -63,7 +63,7 @@ impl DebuggerVisualizerCollector<'_> {
                     ));
                 }
                 Err(error) => {
-                    self.sess.emit_err(DebugVisualizerUnreadable {
+                    self.sess.dcx().emit_err(DebugVisualizerUnreadable {
                         span: meta_item.span,
                         file: &file,
                         error,
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index d8b9f4fae87fe..906ecdfe5abae 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -45,7 +45,7 @@ fn report_duplicate_item(
 ) {
     let orig_span = tcx.hir().span_if_local(original_def_id);
     let duplicate_span = tcx.hir().span_if_local(item_def_id);
-    tcx.sess.emit_err(DuplicateDiagnosticItemInCrate {
+    tcx.dcx().emit_err(DuplicateDiagnosticItemInCrate {
         duplicate_span,
         orig_span,
         crate_name: tcx.crate_name(item_def_id.krate),
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index 7667fc21eee05..ed26b45a936b0 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -69,20 +69,20 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
     match entry_point_type {
         EntryPointType::None => {
             if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
-                ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
+                ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
             }
         }
         _ if !matches!(ctxt.tcx.def_kind(id.owner_id), DefKind::Fn) => {
             for attr in [sym::start, sym::rustc_main] {
                 if let Some(span) = attr_span_by_symbol(ctxt, id, attr) {
-                    ctxt.tcx.sess.emit_err(AttrOnlyInFunctions { span, attr });
+                    ctxt.tcx.dcx().emit_err(AttrOnlyInFunctions { span, attr });
                 }
             }
         }
         EntryPointType::MainNamed => (),
         EntryPointType::OtherMain => {
             if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
-                ctxt.tcx.sess.emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe });
+                ctxt.tcx.dcx().emit_err(AttrOnlyOnRootMain { span, attr: sym::unix_sigpipe });
             }
             ctxt.non_main_fns.push(ctxt.tcx.def_span(id.owner_id));
         }
@@ -90,7 +90,7 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
             if ctxt.attr_main_fn.is_none() {
                 ctxt.attr_main_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
             } else {
-                ctxt.tcx.sess.emit_err(MultipleRustcMain {
+                ctxt.tcx.dcx().emit_err(MultipleRustcMain {
                     span: ctxt.tcx.def_span(id.owner_id.to_def_id()),
                     first: ctxt.attr_main_fn.unwrap().1,
                     additional: ctxt.tcx.def_span(id.owner_id.to_def_id()),
@@ -99,12 +99,12 @@ fn find_item(id: ItemId, ctxt: &mut EntryContext<'_>) {
         }
         EntryPointType::Start => {
             if let Some(span) = attr_span_by_symbol(ctxt, id, sym::unix_sigpipe) {
-                ctxt.tcx.sess.emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
+                ctxt.tcx.dcx().emit_err(AttrOnlyOnMain { span, attr: sym::unix_sigpipe });
             }
             if ctxt.start_fn.is_none() {
                 ctxt.start_fn = Some((id.owner_id.def_id, ctxt.tcx.def_span(id.owner_id)));
             } else {
-                ctxt.tcx.sess.emit_err(MultipleStartFunctions {
+                ctxt.tcx.dcx().emit_err(MultipleStartFunctions {
                     span: ctxt.tcx.def_span(id.owner_id),
                     labeled: ctxt.tcx.def_span(id.owner_id.to_def_id()),
                     previous: ctxt.start_fn.unwrap().1,
@@ -128,7 +128,7 @@ fn configure_main(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) -> Option<(DefId,
             if let Some(def_id) = def_id.as_local()
                 && matches!(tcx.opt_hir_node_by_def_id(def_id), Some(Node::ForeignItem(_)))
             {
-                tcx.sess.emit_err(ExternMain { span: tcx.def_span(def_id) });
+                tcx.dcx().emit_err(ExternMain { span: tcx.def_span(def_id) });
                 return None;
             }
 
@@ -161,7 +161,7 @@ fn sigpipe(tcx: TyCtxt<'_>, def_id: DefId) -> u8 {
                 sigpipe::DEFAULT
             }
             _ => {
-                tcx.sess.emit_err(UnixSigpipeValues { span: attr.span });
+                tcx.dcx().emit_err(UnixSigpipeValues { span: attr.span });
                 sigpipe::DEFAULT
             }
         }
@@ -187,7 +187,7 @@ fn no_main_err(tcx: TyCtxt<'_>, visitor: &EntryContext<'_>) {
     // note instead.
     let file_empty = tcx.sess.source_map().lookup_line(sp.hi()).is_err();
 
-    tcx.sess.emit_err(NoMainErr {
+    tcx.dcx().emit_err(NoMainErr {
         sp,
         crate_name: tcx.crate_name(LOCAL_CRATE),
         has_filename,
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 18a80aa34f84f..0727bad7c5a1d 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -31,7 +31,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
 
         if !errors.is_empty() {
             let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2);
-            tcx.sess.span_delayed_bug(rustc_span::DUMMY_SP, message);
+            tcx.dcx().span_delayed_bug(rustc_span::DUMMY_SP, message);
         }
     }
 }
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index 6d14a14096d0b..647f4d0e08419 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -78,7 +78,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> {
                 }
                 // Known lang item with attribute on incorrect target.
                 Some(lang_item) => {
-                    self.tcx.sess.emit_err(LangItemOnIncorrectTarget {
+                    self.tcx.dcx().emit_err(LangItemOnIncorrectTarget {
                         span: attr_span,
                         name,
                         expected_target: lang_item.target(),
@@ -87,7 +87,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> {
                 }
                 // Unknown lang item.
                 _ => {
-                    self.tcx.sess.emit_err(UnknownLangItem { span: attr_span, name });
+                    self.tcx.dcx().emit_err(UnknownLangItem { span: attr_span, name });
                 }
             }
         }
@@ -149,7 +149,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> {
                 }
             };
 
-            self.tcx.sess.emit_err(DuplicateLangItem {
+            self.tcx.dcx().emit_err(DuplicateLangItem {
                 local_span: item_span,
                 lang_item_name,
                 crate_name,
@@ -220,7 +220,7 @@ impl<'ast, 'tcx> LanguageItemCollector<'ast, 'tcx> {
                 // We are issuing E0718 "incorrect target" here, because while the
                 // item kind of the target is correct, the target is still wrong
                 // because of the wrong number of generic arguments.
-                self.tcx.sess.emit_err(IncorrectTarget {
+                self.tcx.dcx().emit_err(IncorrectTarget {
                     span: attr_span,
                     generics_span: generics.span,
                     name: name.as_str(),
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 2129a98cda3f9..8d223c23363bb 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -27,7 +27,7 @@ pub fn test_layout(tcx: TyCtxt<'_>) {
                     dump_layout_of(tcx, id, attr);
                 }
                 _ => {
-                    tcx.sess.emit_err(LayoutInvalidAttribute { span: tcx.def_span(id) });
+                    tcx.dcx().emit_err(LayoutInvalidAttribute { span: tcx.def_span(id) });
                 }
             }
         }
@@ -80,23 +80,23 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
             for meta_item in meta_items {
                 match meta_item.name_or_empty() {
                     sym::abi => {
-                        tcx.sess.emit_err(LayoutAbi { span, abi: format!("{:?}", ty_layout.abi) });
+                        tcx.dcx().emit_err(LayoutAbi { span, abi: format!("{:?}", ty_layout.abi) });
                     }
 
                     sym::align => {
-                        tcx.sess.emit_err(LayoutAlign {
+                        tcx.dcx().emit_err(LayoutAlign {
                             span,
                             align: format!("{:?}", ty_layout.align),
                         });
                     }
 
                     sym::size => {
-                        tcx.sess
+                        tcx.dcx()
                             .emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) });
                     }
 
                     sym::homogeneous_aggregate => {
-                        tcx.sess.emit_err(LayoutHomogeneousAggregate {
+                        tcx.dcx().emit_err(LayoutHomogeneousAggregate {
                             span,
                             homogeneous_aggregate: format!(
                                 "{:?}",
@@ -115,18 +115,18 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
                         );
                         // FIXME: using the `Debug` impl here isn't ideal.
                         let ty_layout = format!("{:#?}", *ty_layout);
-                        tcx.sess.emit_err(LayoutOf { span, normalized_ty, ty_layout });
+                        tcx.dcx().emit_err(LayoutOf { span, normalized_ty, ty_layout });
                     }
 
                     name => {
-                        tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name });
+                        tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name });
                     }
                 }
             }
         }
 
         Err(layout_error) => {
-            tcx.sess.emit_fatal(Spanned { node: layout_error.into_diagnostic(), span });
+            tcx.dcx().emit_fatal(Spanned { node: layout_error.into_diagnostic(), span });
         }
     }
 }
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index 6c0412beda296..e60985ba16fbf 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -97,11 +97,16 @@ impl<'tcx> LibFeatureCollector<'tcx> {
                 Some((FeatureStability::AcceptedSince(prev_since), _)),
             ) => {
                 if prev_since != since {
-                    self.tcx.sess.emit_err(FeatureStableTwice { span, feature, since, prev_since });
+                    self.tcx.dcx().emit_err(FeatureStableTwice {
+                        span,
+                        feature,
+                        since,
+                        prev_since,
+                    });
                 }
             }
             (FeatureStability::AcceptedSince(_), Some((FeatureStability::Unstable, _))) => {
-                self.tcx.sess.emit_err(FeaturePreviouslyDeclared {
+                self.tcx.dcx().emit_err(FeaturePreviouslyDeclared {
                     span,
                     feature,
                     declared: "stable",
@@ -109,7 +114,7 @@ impl<'tcx> LibFeatureCollector<'tcx> {
                 });
             }
             (FeatureStability::Unstable, Some((FeatureStability::AcceptedSince(_), _))) => {
-                self.tcx.sess.emit_err(FeaturePreviouslyDeclared {
+                self.tcx.dcx().emit_err(FeaturePreviouslyDeclared {
                     span,
                     feature,
                     declared: "unstable",
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index c9e5eb50b3a3d..a8ba9838780a2 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -592,7 +592,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
         match self.successors[ln] {
             Some(successor) => self.assigned_on_entry(successor, var),
             None => {
-                self.ir.tcx.sess.span_delayed_bug(DUMMY_SP, "no successor");
+                self.ir.tcx.dcx().span_delayed_bug(DUMMY_SP, "no successor");
                 true
             }
         }
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index bfaf4a5a95717..24db708196b85 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -126,7 +126,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                     Ok(loop_id) => Some(loop_id),
                     Err(hir::LoopIdError::OutsideLoopScope) => None,
                     Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
-                        self.sess.emit_err(UnlabeledCfInWhileCondition {
+                        self.sess.dcx().emit_err(UnlabeledCfInWhileCondition {
                             span: e.span,
                             cf_type: "break",
                         });
@@ -161,7 +161,7 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                                     .label
                                     .map_or_else(String::new, |l| format!(" {}", l.ident))
                             );
-                            self.sess.emit_err(BreakNonLoop {
+                            self.sess.dcx().emit_err(BreakNonLoop {
                                 span: e.span,
                                 head,
                                 kind: kind.name(),
@@ -188,14 +188,14 @@ impl<'a, 'hir> Visitor<'hir> for CheckLoopVisitor<'a, 'hir> {
                 match destination.target_id {
                     Ok(loop_id) => {
                         if let Node::Block(block) = self.tcx.opt_hir_node(loop_id).unwrap() {
-                            self.sess.emit_err(ContinueLabeledBlock {
+                            self.sess.dcx().emit_err(ContinueLabeledBlock {
                                 span: e.span,
                                 block_span: block.span,
                             });
                         }
                     }
                     Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
-                        self.sess.emit_err(UnlabeledCfInWhileCondition {
+                        self.sess.dcx().emit_err(UnlabeledCfInWhileCondition {
                             span: e.span,
                             cf_type: "continue",
                         });
@@ -225,17 +225,17 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
         match self.cx {
             LabeledBlock | Loop(_) => {}
             Closure(closure_span) => {
-                self.sess.emit_err(BreakInsideClosure { span, closure_span, name });
+                self.sess.dcx().emit_err(BreakInsideClosure { span, closure_span, name });
             }
             AsyncClosure(closure_span) => {
-                self.sess.emit_err(BreakInsideAsyncBlock { span, closure_span, name });
+                self.sess.dcx().emit_err(BreakInsideAsyncBlock { span, closure_span, name });
             }
             UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => {
                 let suggestion = Some(OutsideLoopSuggestion { block_span, break_span });
-                self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion });
+                self.sess.dcx().emit_err(OutsideLoop { span, name, is_break, suggestion });
             }
             Normal | Constant | Fn | UnlabeledBlock(_) => {
-                self.sess.emit_err(OutsideLoop { span, name, is_break, suggestion: None });
+                self.sess.dcx().emit_err(OutsideLoop { span, name, is_break, suggestion: None });
             }
         }
     }
@@ -250,7 +250,7 @@ impl<'a, 'hir> CheckLoopVisitor<'a, 'hir> {
             && self.cx == LabeledBlock
             && label.label.is_none()
         {
-            self.sess.emit_err(UnlabeledInLabeledBlock { span, cf_type });
+            self.sess.dcx().emit_err(UnlabeledInLabeledBlock { span, cf_type });
             return true;
         }
         false
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index 25637f935fbdf..d2cfdb7bf4774 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -61,7 +61,7 @@ fn check_mod_naked_functions(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
 fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let attrs = tcx.get_attrs(def_id, sym::inline);
     for attr in attrs {
-        tcx.sess.emit_err(CannotInlineNakedFunction { span: attr.span });
+        tcx.dcx().emit_err(CannotInlineNakedFunction { span: attr.span });
     }
 }
 
@@ -86,7 +86,7 @@ fn check_no_patterns(tcx: TyCtxt<'_>, params: &[hir::Param<'_>]) {
             hir::PatKind::Wild
             | hir::PatKind::Binding(hir::BindingAnnotation::NONE, _, _, None) => {}
             _ => {
-                tcx.sess.emit_err(NoPatterns { span: param.pat.span });
+                tcx.dcx().emit_err(NoPatterns { span: param.pat.span });
             }
         }
     }
@@ -116,7 +116,7 @@ impl<'tcx> Visitor<'tcx> for CheckParameters<'tcx> {
         )) = expr.kind
         {
             if self.params.contains(var_hir_id) {
-                self.tcx.sess.emit_err(ParamsNotAllowed { span: expr.span });
+                self.tcx.dcx().emit_err(ParamsNotAllowed { span: expr.span });
                 return;
             }
         }
@@ -155,7 +155,7 @@ fn check_asm<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'tcx hir::Body<
         // errors, then don't show an additional error. This allows for appending/prepending
         // `compile_error!("...")` statements and reduces error noise.
         if must_show_error || !has_err {
-            tcx.sess.emit_err(NakedFunctionsAsmBlock {
+            tcx.dcx().emit_err(NakedFunctionsAsmBlock {
                 span: tcx.def_span(def_id),
                 multiple_asms,
                 non_asms,
@@ -241,7 +241,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
             })
             .collect();
         if !unsupported_operands.is_empty() {
-            self.tcx.sess.emit_err(NakedFunctionsOperands { unsupported_operands });
+            self.tcx.dcx().emit_err(NakedFunctionsOperands { unsupported_operands });
         }
 
         let unsupported_options: Vec<&'static str> = [
@@ -257,7 +257,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
         .collect();
 
         if !unsupported_options.is_empty() {
-            self.tcx.sess.emit_err(NakedFunctionsAsmOptions {
+            self.tcx.dcx().emit_err(NakedFunctionsAsmOptions {
                 span,
                 unsupported_options: unsupported_options.join(", "),
             });
@@ -270,7 +270,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
                 .map_or_else(|| asm.template_strs.last().unwrap().2, |op| op.1)
                 .shrink_to_hi();
 
-            self.tcx.sess.emit_err(NakedFunctionsMustUseNoreturn { span, last_span });
+            self.tcx.dcx().emit_err(NakedFunctionsMustUseNoreturn { span, last_span });
         }
     }
 }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 676622cef45c5..87fdedc15ba09 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -180,7 +180,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
                     || (self.in_trait_impl && !self.tcx.is_const_fn_raw(def_id.to_def_id()))
                 {
                     self.tcx
-                        .sess
+                        .dcx()
                         .emit_err(errors::MissingConstErr { fn_sig_span: fn_sig.span, const_span });
                 }
             }
@@ -201,7 +201,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             && depr.is_since_rustc_version()
             && stab.is_none()
         {
-            self.tcx.sess.emit_err(errors::DeprecatedAttribute { span: *span });
+            self.tcx.dcx().emit_err(errors::DeprecatedAttribute { span: *span });
         }
 
         if let Some((body_stab, _span)) = body_stab {
@@ -216,7 +216,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             if kind == AnnotationKind::Prohibited
                 || (kind == AnnotationKind::Container && stab.level.is_stable() && is_deprecated)
             {
-                self.tcx.sess.emit_err(errors::UselessStability { span, item_sp });
+                self.tcx.dcx().emit_err(errors::UselessStability { span, item_sp });
             }
 
             debug!("annotate: found {:?}", stab);
@@ -230,12 +230,14 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
             {
                 match stab_since {
                     StableSince::Current => {
-                        self.tcx.sess.emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
+                        self.tcx
+                            .dcx()
+                            .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
                     }
                     StableSince::Version(stab_since) => {
                         if dep_since < stab_since {
                             self.tcx
-                                .sess
+                                .dcx()
                                 .emit_err(errors::CannotStabilizeDeprecated { span, item_sp });
                         }
                     }
@@ -520,7 +522,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
             && self.effective_visibilities.is_reachable(def_id)
         {
             let descr = self.tcx.def_descr(def_id.to_def_id());
-            self.tcx.sess.emit_err(errors::MissingStabilityAttr { span, descr });
+            self.tcx.dcx().emit_err(errors::MissingStabilityAttr { span, descr });
         }
     }
 
@@ -546,7 +548,7 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
 
         if is_const && is_stable && missing_const_stability_attribute && is_reachable {
             let descr = self.tcx.def_descr(def_id.to_def_id());
-            self.tcx.sess.emit_err(errors::MissingConstStabAttr { span, descr });
+            self.tcx.dcx().emit_err(errors::MissingConstStabAttr { span, descr });
         }
     }
 }
@@ -751,7 +753,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
                         && self.tcx.is_const_trait_impl_raw(item.owner_id.to_def_id())
                         && const_stab.is_some_and(|(stab, _)| stab.is_const_stable())
                     {
-                        self.tcx.sess.emit_err(errors::TraitImplConstStable { span: item.span });
+                        self.tcx.dcx().emit_err(errors::TraitImplConstStable { span: item.span });
                     }
                 }
 
@@ -929,7 +931,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
         }
         if !lang_features.insert(feature) {
             // Warn if the user enables a lang feature multiple times.
-            tcx.sess.emit_err(errors::DuplicateFeatureErr { span, feature });
+            tcx.dcx().emit_err(errors::DuplicateFeatureErr { span, feature });
         }
     }
 
@@ -937,14 +939,14 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     let mut remaining_lib_features = FxIndexMap::default();
     for (feature, span) in declared_lib_features {
         if !tcx.sess.opts.unstable_features.is_nightly_build() {
-            tcx.sess.emit_err(errors::FeatureOnlyOnNightly {
+            tcx.dcx().emit_err(errors::FeatureOnlyOnNightly {
                 span: *span,
                 release_channel: env!("CFG_RELEASE_CHANNEL"),
             });
         }
         if remaining_lib_features.contains_key(&feature) {
             // Warn if the user enables a lib feature multiple times.
-            tcx.sess.emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature });
+            tcx.dcx().emit_err(errors::DuplicateFeatureErr { span: *span, feature: *feature });
         }
         remaining_lib_features.insert(feature, *span);
     }
@@ -1045,7 +1047,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
     }
 
     for (feature, span) in remaining_lib_features {
-        tcx.sess.emit_err(errors::UnknownFeature { span, feature: *feature });
+        tcx.dcx().emit_err(errors::UnknownFeature { span, feature: *feature });
     }
 
     // We only use the hash map contents to emit errors, and the order of
@@ -1058,7 +1060,7 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) {
             .get(&feature)
             .expect("feature that implied another does not exist")
             .1;
-        tcx.sess.emit_err(errors::ImpliedFeatureNotExist { span, feature, implied_by });
+        tcx.dcx().emit_err(errors::ImpliedFeatureNotExist { span, feature, implied_by });
     }
 
     // FIXME(#44232): the `used_features` table no longer exists, so we
diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs
index b226c65e96c88..db3d442676eb1 100644
--- a/compiler/rustc_passes/src/weak_lang_items.rs
+++ b/compiler/rustc_passes/src/weak_lang_items.rs
@@ -44,7 +44,7 @@ impl<'ast> visit::Visitor<'ast> for WeakLangItemVisitor<'_, '_> {
                     self.items.missing.push(item);
                 }
             } else {
-                self.tcx.sess.emit_err(UnknownExternLangItem { span: i.span, lang_item });
+                self.tcx.dcx().emit_err(UnknownExternLangItem { span: i.span, lang_item });
             }
         }
     }
@@ -75,9 +75,9 @@ fn verify(tcx: TyCtxt<'_>, items: &lang_items::LanguageItems) {
     for &item in WEAK_LANG_ITEMS.iter() {
         if missing.contains(&item) && required(tcx, item) && items.get(item).is_none() {
             if item == LangItem::PanicImpl {
-                tcx.sess.emit_err(MissingPanicHandler);
+                tcx.dcx().emit_err(MissingPanicHandler);
             } else {
-                tcx.sess.emit_err(MissingLangItem { name: item.name() });
+                tcx.dcx().emit_err(MissingLangItem { name: item.name() });
             }
         }
     }
diff --git a/compiler/rustc_pattern_analysis/src/lints.rs b/compiler/rustc_pattern_analysis/src/lints.rs
index 2be6e8e3db346..bba1f406056bb 100644
--- a/compiler/rustc_pattern_analysis/src/lints.rs
+++ b/compiler/rustc_pattern_analysis/src/lints.rs
@@ -203,7 +203,7 @@ pub(crate) fn lint_nonexhaustive_missing_variants<'a, 'p, 'tcx>(
                 };
 
                 use rustc_errors::DecorateLint;
-                let mut err = rcx.tcx.sess.struct_span_warn(*arm.pat.data().unwrap(), "");
+                let mut err = rcx.tcx.dcx().struct_span_warn(*arm.pat.data().unwrap(), "");
                 err.set_primary_message(decorator.msg());
                 decorator.decorate_lint(&mut err);
                 err.emit();
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index be9c6b7258330..519303fc3aa96 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -881,7 +881,7 @@ impl<'tcx, 'a> TestReachabilityVisitor<'tcx, 'a> {
             } else {
                 error_msg.push_str("not in the table");
             }
-            self.tcx.sess.emit_err(ReportEffectiveVisibility { span, descr: error_msg });
+            self.tcx.dcx().emit_err(ReportEffectiveVisibility { span, descr: error_msg });
         }
     }
 }
@@ -966,7 +966,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> {
         let hir_id = self.tcx.local_def_id_to_hir_id(self.current_item);
         let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1;
         if !field.vis.is_accessible_from(def_id, self.tcx) {
-            self.tcx.sess.emit_err(FieldIsPrivate {
+            self.tcx.dcx().emit_err(FieldIsPrivate {
                 span,
                 field_name: field.name,
                 variant_descr: def.variant_descr(),
@@ -1100,7 +1100,7 @@ impl<'tcx> TypePrivacyVisitor<'tcx> {
     fn check_def_id(&mut self, def_id: DefId, kind: &str, descr: &dyn fmt::Display) -> bool {
         let is_error = !self.item_is_accessible(def_id);
         if is_error {
-            self.tcx.sess.emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
+            self.tcx.dcx().emit_err(ItemIsPrivate { span: self.span, kind, descr: descr.into() });
         }
         is_error
     }
@@ -1229,7 +1229,7 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
                     }
                 } else {
                     self.tcx
-                        .sess
+                        .dcx()
                         .span_delayed_bug(expr.span, "no type-dependent def for method call");
                 }
             }
@@ -1276,9 +1276,9 @@ impl<'tcx> Visitor<'tcx> for TypePrivacyVisitor<'tcx> {
                 let sess = self.tcx.sess;
                 let _ = match name {
                     Some(name) => {
-                        sess.emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
+                        sess.dcx().emit_err(ItemIsPrivate { span, kind, descr: (&name).into() })
                     }
-                    None => sess.emit_err(UnnamedItemIsPrivate { span, kind }),
+                    None => sess.dcx().emit_err(UnnamedItemIsPrivate { span, kind }),
                 };
                 return;
             }
@@ -1434,7 +1434,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
                 }
             };
 
-            self.tcx.sess.emit_err(InPublicInterface {
+            self.tcx.dcx().emit_err(InPublicInterface {
                 span,
                 vis_descr,
                 kind,
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index acd3d71e63683..0971f2d75da0f 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -167,7 +167,7 @@ impl QueryContext for QueryCtxt<'_> {
             limit => limit * 2,
         };
 
-        self.sess.emit_fatal(QueryOverflow {
+        self.sess.dcx().emit_fatal(QueryOverflow {
             span,
             layout_of_depth,
             suggested_limit,
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 3556a5ec1d17f..9b06823dfbafb 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -818,7 +818,7 @@ impl<D: Deps> DepGraphData<D> {
             None => {}
         }
 
-        if let None = qcx.dep_context().sess().has_errors_or_span_delayed_bugs() {
+        if let None = qcx.dep_context().sess().dcx().has_errors_or_span_delayed_bugs() {
             panic!("try_mark_previous_green() - Forcing the DepNode should have set its color")
         }
 
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 3e29574c87107..34f2c01f89098 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -126,7 +126,7 @@ where
         }
         Fatal => {
             error.emit();
-            qcx.dep_context().sess().abort_if_errors();
+            qcx.dep_context().sess().dcx().abort_if_errors();
             unreachable!()
         }
         DelayBug => {
@@ -138,7 +138,7 @@ where
                 && let Some(span) = root.query.span
             {
                 error.stash(span, StashKey::Cycle);
-                qcx.dep_context().sess().span_delayed_bug(span, "delayed cycle error")
+                qcx.dep_context().sess().dcx().span_delayed_bug(span, "delayed cycle error")
             } else {
                 error.emit()
             };
@@ -421,7 +421,7 @@ where
                 // We have an inconsistency. This can happen if one of the two
                 // results is tainted by errors. In this case, delay a bug to
                 // ensure compilation is doomed.
-                qcx.dep_context().sess().span_delayed_bug(
+                qcx.dep_context().sess().dcx().span_delayed_bug(
                     DUMMY_SP,
                     format!(
                         "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\
@@ -705,7 +705,7 @@ fn incremental_verify_ich_failed<Tcx>(
     let old_in_panic = INSIDE_VERIFY_PANIC.with(|in_panic| in_panic.replace(true));
 
     if old_in_panic {
-        tcx.sess().emit_err(crate::error::Reentrant);
+        tcx.sess().dcx().emit_err(crate::error::Reentrant);
     } else {
         let run_cmd = if let Some(crate_name) = &tcx.sess().opts.crate_name {
             format!("`cargo clean -p {crate_name}` or `cargo clean`")
@@ -714,7 +714,7 @@ fn incremental_verify_ich_failed<Tcx>(
         };
 
         let dep_node = tcx.dep_graph().data().unwrap().prev_node_of(prev_index);
-        tcx.sess().emit_err(crate::error::IncrementCompilation {
+        tcx.sess().dcx().emit_err(crate::error::IncrementCompilation {
             run_cmd,
             dep_node: format!("{dep_node:?}"),
         });
diff --git a/compiler/rustc_query_system/src/values.rs b/compiler/rustc_query_system/src/values.rs
index 8848fda9da3d0..4f1c182cdb8eb 100644
--- a/compiler/rustc_query_system/src/values.rs
+++ b/compiler/rustc_query_system/src/values.rs
@@ -9,7 +9,7 @@ pub trait Value<Tcx: DepContext>: Sized {
 
 impl<Tcx: DepContext, T> Value<Tcx> for T {
     default fn from_cycle_error(tcx: Tcx, cycle: &[QueryInfo], _guar: ErrorGuaranteed) -> T {
-        tcx.sess().abort_if_errors();
+        tcx.sess().dcx().abort_if_errors();
         // Ideally we would use `bug!` here. But bug! is only defined in rustc_middle, and it's
         // non-trivial to define it earlier.
         panic!(
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 98a9d0ba4c2f6..4e1fda5479c88 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -524,12 +524,12 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                             ident.name = crate_name;
                         }
 
-                        self.r.tcx.sess.emit_err(errors::CrateImported { span: item.span });
+                        self.r.dcx().emit_err(errors::CrateImported { span: item.span });
                     }
                 }
 
                 if ident.name == kw::Crate {
-                    self.r.tcx.sess.span_err(
+                    self.r.dcx().span_err(
                         ident.span,
                         "crate root imports need to be explicitly named: \
                          `use crate as name;`",
@@ -816,8 +816,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
 
         let (used, module, binding) = if orig_name.is_none() && ident.name == kw::SelfLower {
             self.r
-                .tcx
-                .sess
+                .dcx()
                 .struct_span_err(item.span, "`extern crate self;` requires renaming")
                 .span_suggestion(
                     item.span,
@@ -867,7 +866,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                 if expansion != LocalExpnId::ROOT && orig_name.is_some() && !entry.is_import() {
                     let msg = "macro-expanded `extern crate` items cannot \
                                        shadow names passed with `--extern`";
-                    self.r.tcx.sess.span_err(item.span, msg);
+                    self.r.dcx().span_err(item.span, msg);
                     // `return` is intended to discard this binding because it's an
                     // unregistered ambiguity error which would result in a panic
                     // caused by inconsistency `path_res`
@@ -1000,7 +999,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             let msg = format!("`{name}` is already in scope");
             let note =
                 "macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
-            self.r.tcx.sess.struct_span_err(span, msg).note(note).emit();
+            self.r.dcx().struct_span_err(span, msg).note(note).emit();
         }
     }
 
@@ -1012,7 +1011,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             if attr.has_name(sym::macro_use) {
                 if self.parent_scope.module.parent.is_some() {
                     struct_span_err!(
-                        self.r.tcx.sess,
+                        self.r.dcx(),
                         item.span,
                         E0468,
                         "an `extern crate` loading macros must be at the crate root"
@@ -1021,14 +1020,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                 }
                 if let ItemKind::ExternCrate(Some(orig_name)) = item.kind {
                     if orig_name == kw::SelfLower {
-                        self.r
-                            .tcx
-                            .sess
-                            .emit_err(errors::MacroUseExternCrateSelf { span: attr.span });
+                        self.r.dcx().emit_err(errors::MacroUseExternCrateSelf { span: attr.span });
                     }
                 }
                 let ill_formed = |span| {
-                    struct_span_err!(self.r.tcx.sess, span, E0466, "bad macro import").emit();
+                    struct_span_err!(self.r.dcx(), span, E0466, "bad macro import").emit();
                 };
                 match attr.meta() {
                     Some(meta) => match meta.kind {
@@ -1099,13 +1095,8 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
                         allow_shadowing,
                     );
                 } else {
-                    struct_span_err!(
-                        self.r.tcx.sess,
-                        ident.span,
-                        E0469,
-                        "imported macro not found"
-                    )
-                    .emit();
+                    struct_span_err!(self.r.dcx(), ident.span, E0469, "imported macro not found")
+                        .emit();
                 }
             }
         }
@@ -1117,7 +1108,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
         for attr in attrs {
             if attr.has_name(sym::macro_escape) {
                 let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`";
-                let mut err = self.r.tcx.sess.struct_span_warn(attr.span, msg);
+                let mut err = self.r.dcx().struct_span_warn(attr.span, msg);
                 if let ast::AttrStyle::Inner = attr.style {
                     err.help("try an outer attribute: `#[macro_use]`").emit();
                 } else {
@@ -1128,10 +1119,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
             }
 
             if !attr.is_word() {
-                self.r
-                    .tcx
-                    .sess
-                    .span_err(attr.span, "arguments to `macro_use` are not allowed here");
+                self.r.dcx().span_err(attr.span, "arguments to `macro_use` are not allowed here");
             }
             return true;
         }
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index af0c5b56d7343..8743b73492649 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -5,8 +5,10 @@ use rustc_ast::{self as ast, Crate, ItemKind, ModKind, NodeId, Path, CRATE_NODE_
 use rustc_ast::{MetaItemKind, NestedMetaItem};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{pluralize, report_ambiguity_error, struct_span_err, SuggestionStyle};
-use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{
+    pluralize, report_ambiguity_error, struct_span_err, Applicability, DiagCtxt, Diagnostic,
+    DiagnosticBuilder, ErrorGuaranteed, MultiSpan, SuggestionStyle,
+};
 use rustc_feature::BUILTIN_ATTRIBUTES;
 use rustc_hir::def::Namespace::{self, *};
 use rustc_hir::def::{self, CtorKind, CtorOf, DefKind, NonMacroAttrKind, PerNS};
@@ -116,6 +118,10 @@ fn reduce_impl_span_to_impl_keyword(sm: &SourceMap, impl_span: Span) -> Span {
 }
 
 impl<'a, 'tcx> Resolver<'a, 'tcx> {
+    pub(crate) fn dcx(&self) -> &'tcx DiagCtxt {
+        self.tcx.dcx()
+    }
+
     pub(crate) fn report_errors(&mut self, krate: &Crate) {
         self.report_with_use_injections(krate);
 
@@ -145,7 +151,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     BuiltinLintDiagnostics::AmbiguousGlobImports { diag },
                 );
             } else {
-                let mut err = struct_span_err!(self.tcx.sess, diag.span, E0659, "{}", &diag.msg);
+                let mut err = struct_span_err!(self.dcx(), diag.span, E0659, "{}", &diag.msg);
                 report_ambiguity_error(&mut err, diag);
                 err.emit();
             }
@@ -246,15 +252,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let msg = format!("the name `{name}` is defined multiple times");
 
         let mut err = match (old_binding.is_extern_crate(), new_binding.is_extern_crate()) {
-            (true, true) => struct_span_err!(self.tcx.sess, span, E0259, "{}", msg),
+            (true, true) => struct_span_err!(self.dcx(), span, E0259, "{}", msg),
             (true, _) | (_, true) => match new_binding.is_import() && old_binding.is_import() {
-                true => struct_span_err!(self.tcx.sess, span, E0254, "{}", msg),
-                false => struct_span_err!(self.tcx.sess, span, E0260, "{}", msg),
+                true => struct_span_err!(self.dcx(), span, E0254, "{}", msg),
+                false => struct_span_err!(self.dcx(), span, E0260, "{}", msg),
             },
             _ => match (old_binding.is_import_user_facing(), new_binding.is_import_user_facing()) {
-                (false, false) => struct_span_err!(self.tcx.sess, span, E0428, "{}", msg),
-                (true, true) => struct_span_err!(self.tcx.sess, span, E0252, "{}", msg),
-                _ => struct_span_err!(self.tcx.sess, span, E0255, "{}", msg),
+                (false, false) => struct_span_err!(self.dcx(), span, E0428, "{}", msg),
+                (true, true) => struct_span_err!(self.dcx(), span, E0252, "{}", msg),
+                _ => struct_span_err!(self.dcx(), span, E0255, "{}", msg),
             },
         };
 
@@ -566,7 +572,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 let def_id = match outer_res {
                     Res::SelfTyParam { .. } => {
                         err.label = Some(Label::SelfTyParam(span));
-                        return self.tcx.sess.create_err(err);
+                        return self.dcx().create_err(err);
                     }
                     Res::SelfTyAlias { alias_to: def_id, .. } => {
                         err.label = Some(Label::SelfTyAlias(reduce_impl_span_to_impl_keyword(
@@ -574,7 +580,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                             self.def_span(def_id),
                         )));
                         err.refer_to_type_directly = Some(span);
-                        return self.tcx.sess.create_err(err);
+                        return self.dcx().create_err(err);
                     }
                     Res::Def(DefKind::TyParam, def_id) => {
                         err.label = Some(Label::TyParam(self.def_span(def_id)));
@@ -606,14 +612,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     err.sugg = Some(errs::GenericParamsFromOuterItemSugg { span, snippet });
                 }
 
-                self.tcx.sess.create_err(err)
+                self.dcx().create_err(err)
             }
             ResolutionError::NameAlreadyUsedInParameterList(name, first_use_span) => self
-                .tcx
-                .sess
+                .dcx()
                 .create_err(errs::NameAlreadyUsedInParameterList { span, first_use_span, name }),
             ResolutionError::MethodNotMemberOfTrait(method, trait_, candidate) => {
-                self.tcx.sess.create_err(errs::MethodNotMemberOfTrait {
+                self.dcx().create_err(errs::MethodNotMemberOfTrait {
                     span,
                     method,
                     trait_,
@@ -624,7 +629,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 })
             }
             ResolutionError::TypeNotMemberOfTrait(type_, trait_, candidate) => {
-                self.tcx.sess.create_err(errs::TypeNotMemberOfTrait {
+                self.dcx().create_err(errs::TypeNotMemberOfTrait {
                     span,
                     type_,
                     trait_,
@@ -635,7 +640,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 })
             }
             ResolutionError::ConstNotMemberOfTrait(const_, trait_, candidate) => {
-                self.tcx.sess.create_err(errs::ConstNotMemberOfTrait {
+                self.dcx().create_err(errs::ConstNotMemberOfTrait {
                     span,
                     const_,
                     trait_,
@@ -653,7 +658,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
                 let msp = MultiSpan::from_spans(target_sp.clone());
                 let mut err = struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     msp,
                     E0408,
                     "variable `{}` is not bound in all patterns",
@@ -706,19 +711,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 err
             }
             ResolutionError::VariableBoundWithDifferentMode(variable_name, first_binding_span) => {
-                self.tcx.sess.create_err(errs::VariableBoundWithDifferentMode {
+                self.dcx().create_err(errs::VariableBoundWithDifferentMode {
                     span,
                     first_binding_span,
                     variable_name,
                 })
             }
             ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => self
-                .tcx
-                .sess
+                .dcx()
                 .create_err(errs::IdentifierBoundMoreThanOnceInParameterList { span, identifier }),
             ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => self
-                .tcx
-                .sess
+                .dcx()
                 .create_err(errs::IdentifierBoundMoreThanOnceInSamePattern { span, identifier }),
             ResolutionError::UndeclaredLabel { name, suggestion } => {
                 let ((sub_reachable, sub_reachable_suggestion), sub_unreachable) = match suggestion
@@ -744,7 +747,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     // No similarly-named labels exist.
                     None => ((None, None), None),
                 };
-                self.tcx.sess.create_err(errs::UndeclaredLabel {
+                self.dcx().create_err(errs::UndeclaredLabel {
                     span,
                     name,
                     sub_reachable,
@@ -769,22 +772,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     };
                     (Some(suggestion), Some(mpart_suggestion))
                 };
-                self.tcx.sess.create_err(errs::SelfImportsOnlyAllowedWithin {
+                self.dcx().create_err(errs::SelfImportsOnlyAllowedWithin {
                     span,
                     suggestion,
                     mpart_suggestion,
                 })
             }
             ResolutionError::SelfImportCanOnlyAppearOnceInTheList => {
-                self.tcx.sess.create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span })
+                self.dcx().create_err(errs::SelfImportCanOnlyAppearOnceInTheList { span })
+            }
+            ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => {
+                self.dcx().create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span })
             }
-            ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => self
-                .tcx
-                .sess
-                .create_err(errs::SelfImportOnlyInImportListWithNonEmptyPrefix { span }),
             ResolutionError::FailedToResolve { last_segment, label, suggestion, module } => {
                 let mut err =
-                    struct_span_err!(self.tcx.sess, span, E0433, "failed to resolve: {}", &label);
+                    struct_span_err!(self.dcx(), span, E0433, "failed to resolve: {}", &label);
                 err.span_label(span, label);
 
                 if let Some((suggestions, msg, applicability)) = suggestion {
@@ -805,7 +807,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 err
             }
             ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => {
-                self.tcx.sess.create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
+                self.dcx().create_err(errs::CannotCaptureDynamicEnvironmentInFnItem { span })
             }
             ResolutionError::AttemptToUseNonConstantValueInConstant(ident, suggestion, current) => {
                 // let foo =...
@@ -844,7 +846,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     ),
                 };
 
-                self.tcx.sess.create_err(errs::AttemptToUseNonConstantValueInConstant {
+                self.dcx().create_err(errs::AttemptToUseNonConstantValueInConstant {
                     span,
                     with,
                     with_label,
@@ -858,7 +860,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 article,
                 shadowed_binding,
                 shadowed_binding_span,
-            } => self.tcx.sess.create_err(errs::BindingShadowsSomethingUnacceptable {
+            } => self.dcx().create_err(errs::BindingShadowsSomethingUnacceptable {
                 span,
                 shadowing_binding,
                 shadowed_binding,
@@ -875,14 +877,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 name,
             }),
             ResolutionError::ForwardDeclaredGenericParam => {
-                self.tcx.sess.create_err(errs::ForwardDeclaredGenericParam { span })
+                self.dcx().create_err(errs::ForwardDeclaredGenericParam { span })
             }
             ResolutionError::ParamInTyOfConstParam { name, param_kind: is_type } => self
-                .tcx
-                .sess
+                .dcx()
                 .create_err(errs::ParamInTyOfConstParam { span, name, param_kind: is_type }),
             ResolutionError::ParamInNonTrivialAnonConst { name, param_kind: is_type } => {
-                self.tcx.sess.create_err(errs::ParamInNonTrivialAnonConst {
+                self.dcx().create_err(errs::ParamInNonTrivialAnonConst {
                     span,
                     name,
                     param_kind: is_type,
@@ -894,11 +895,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 })
             }
             ResolutionError::ParamInEnumDiscriminant { name, param_kind: is_type } => self
-                .tcx
-                .sess
+                .dcx()
                 .create_err(errs::ParamInEnumDiscriminant { span, name, param_kind: is_type }),
             ResolutionError::SelfInGenericParamDefault => {
-                self.tcx.sess.create_err(errs::SelfInGenericParamDefault { span })
+                self.dcx().create_err(errs::SelfInGenericParamDefault { span })
             }
             ResolutionError::UnreachableLabel { name, definition_span, suggestion } => {
                 let ((sub_suggestion_label, sub_suggestion), sub_unreachable_label) =
@@ -926,7 +926,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         // No similarly-named labels exist.
                         None => ((None, None), None),
                     };
-                self.tcx.sess.create_err(errs::UnreachableLabel {
+                self.dcx().create_err(errs::UnreachableLabel {
                     span,
                     name,
                     definition_span,
@@ -942,7 +942,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 trait_item_span,
                 trait_path,
             } => {
-                let mut err = self.tcx.sess.struct_span_err_with_code(
+                let mut err = self.dcx().struct_span_err_with_code(
                     span,
                     format!(
                         "item `{name}` is an associated {kind}, which doesn't match its trait `{trait_path}`",
@@ -954,15 +954,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 err
             }
             ResolutionError::TraitImplDuplicate { name, trait_item_span, old_span } => self
-                .tcx
-                .sess
+                .dcx()
                 .create_err(errs::TraitImplDuplicate { span, name, trait_item_span, old_span }),
-            ResolutionError::InvalidAsmSym => {
-                self.tcx.sess.create_err(errs::InvalidAsmSym { span })
-            }
-            ResolutionError::LowercaseSelf => {
-                self.tcx.sess.create_err(errs::LowercaseSelf { span })
-            }
+            ResolutionError::InvalidAsmSym => self.dcx().create_err(errs::InvalidAsmSym { span }),
+            ResolutionError::LowercaseSelf => self.dcx().create_err(errs::LowercaseSelf { span }),
         }
     }
 
@@ -972,7 +967,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
     ) -> ErrorGuaranteed {
         match vis_resolution_error {
             VisResolutionError::Relative2018(span, path) => {
-                self.tcx.sess.create_err(errs::Relative2018 {
+                self.dcx().create_err(errs::Relative2018 {
                     span,
                     path_span: path.span,
                     // intentionally converting to String, as the text would also be used as
@@ -981,7 +976,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 })
             }
             VisResolutionError::AncestorOnly(span) => {
-                self.tcx.sess.create_err(errs::AncestorOnly(span))
+                self.dcx().create_err(errs::AncestorOnly(span))
             }
             VisResolutionError::FailedToResolve(span, label, suggestion) => self.into_struct_error(
                 span,
@@ -993,14 +988,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 },
             ),
             VisResolutionError::ExpectedFound(span, path_str, res) => {
-                self.tcx.sess.create_err(errs::ExpectedFound { span, res, path_str })
+                self.dcx().create_err(errs::ExpectedFound { span, res, path_str })
             }
             VisResolutionError::Indeterminate(span) => {
-                self.tcx.sess.create_err(errs::Indeterminate(span))
-            }
-            VisResolutionError::ModuleOnly(span) => {
-                self.tcx.sess.create_err(errs::ModuleOnly(span))
+                self.dcx().create_err(errs::Indeterminate(span))
             }
+            VisResolutionError::ModuleOnly(span) => self.dcx().create_err(errs::ModuleOnly(span)),
         }
         .emit()
     }
@@ -1699,7 +1692,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // Print the primary message.
         let descr = get_descr(binding);
         let mut err =
-            struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident);
+            struct_span_err!(self.dcx(), ident.span, E0603, "{} `{}` is private", descr, ident);
         err.span_label(ident.span, format!("private {descr}"));
 
         let mut not_publicly_reexported = false;
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index a9f7002e564d7..e559ca8e7ccac 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -1201,7 +1201,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                             }
                                         };
                                         self.report_error(span, error);
-                                        self.tcx.sess.span_delayed_bug(span, CG_BUG_STR);
+                                        self.dcx().span_delayed_bug(span, CG_BUG_STR);
                                     }
 
                                     return Res::Err;
@@ -1496,7 +1496,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         record_segment_res(self, res);
                     } else if res == Res::ToolMod && !is_last && opt_ns.is_some() {
                         if binding.is_import() {
-                            self.tcx.sess.emit_err(errors::ToolModuleImported {
+                            self.dcx().emit_err(errors::ToolModuleImported {
                                 span: ident.span,
                                 import: binding.span,
                             });
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 39e82da6d9dd0..9729766220022 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -686,7 +686,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             .collect::<Vec<_>>();
         let msg = format!("unresolved import{} {}", pluralize!(paths.len()), paths.join(", "),);
 
-        let mut diag = struct_span_err!(self.tcx.sess, span, E0432, "{}", &msg);
+        let mut diag = struct_span_err!(self.dcx(), span, E0432, "{}", &msg);
 
         if let Some((_, UnresolvedImportError { note: Some(note), .. })) = errors.iter().last() {
             diag.note(note.clone());
@@ -826,8 +826,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                     source_binding @ (Ok(..) | Err(Determined)) => {
                         if source_binding.is_ok() {
-                            this.tcx
-                                .sess
+                            this.dcx()
                                 .create_err(IsNotDirectlyImportable { span: import.span, target })
                                 .emit();
                         }
@@ -877,8 +876,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         span_bug!(import.span, "inconsistent resolution for an import");
                     }
                 } else if self.privacy_errors.is_empty() {
-                    self.tcx
-                        .sess
+                    self.dcx()
                         .create_err(CannotDetermineImportResolution { span: import.span })
                         .emit();
                 }
@@ -1066,8 +1064,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                         let has_ambiguity_error =
                             this.ambiguity_errors.iter().any(|error| !error.warning);
                         if res == Res::Err || has_ambiguity_error {
-                            this.tcx
-                                .sess
+                            this.dcx()
                                 .span_delayed_bug(import.span, "some error happened for an import");
                             return;
                         }
@@ -1076,8 +1073,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                                 span_bug!(import.span, "inconsistent resolution for an import");
                             }
                         } else if this.privacy_errors.is_empty() {
-                            this.tcx
-                                .sess
+                            this.dcx()
                                 .create_err(CannotDetermineImportResolution { span: import.span })
                                 .emit();
                         }
@@ -1238,24 +1234,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             } else {
                 if ns == TypeNS {
                     let mut err = if crate_private_reexport {
-                        self.tcx.sess.create_err(CannotBeReexportedCratePublicNS {
+                        self.dcx().create_err(CannotBeReexportedCratePublicNS {
                             span: import.span,
                             ident,
                         })
                     } else {
-                        self.tcx
-                            .sess
+                        self.dcx()
                             .create_err(CannotBeReexportedPrivateNS { span: import.span, ident })
                     };
                     err.emit();
                 } else {
                     let mut err = if crate_private_reexport {
-                        self.tcx
-                            .sess
+                        self.dcx()
                             .create_err(CannotBeReexportedCratePublic { span: import.span, ident })
                     } else {
-                        self.tcx
-                            .sess
+                        self.dcx()
                             .create_err(CannotBeReexportedPrivate { span: import.span, ident })
                     };
 
@@ -1378,12 +1371,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         let ImportKind::Glob { id, is_prelude, .. } = import.kind else { unreachable!() };
 
         let ModuleOrUniformRoot::Module(module) = import.imported_module.get().unwrap() else {
-            self.tcx.sess.create_err(CannotGlobImportAllCrates { span: import.span }).emit();
+            self.dcx().create_err(CannotGlobImportAllCrates { span: import.span }).emit();
             return;
         };
 
         if module.is_trait() {
-            self.tcx.sess.create_err(ItemsInTraitsAreNotImportable { span: import.span }).emit();
+            self.dcx().create_err(ItemsInTraitsAreNotImportable { span: import.span }).emit();
             return;
         } else if module == import.parent_scope.module {
             return;
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 4bef67be3ef24..c3026e52430e1 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1665,7 +1665,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                         ("`'_` cannot be used here", "`'_` is a reserved lifetime name")
                     };
                     let mut diag = rustc_errors::struct_span_err!(
-                        self.r.tcx.sess,
+                        self.r.dcx(),
                         lifetime.ident.span,
                         E0637,
                         "{}",
@@ -1854,7 +1854,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
                     | LifetimeRibKind::AnonymousWarn(_) => {
                         let sess = self.r.tcx.sess;
                         let mut err = rustc_errors::struct_span_err!(
-                            sess,
+                            sess.dcx(),
                             path_span,
                             E0726,
                             "implicit elided lifetime not allowed here"
@@ -2301,11 +2301,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             let report_error = |this: &Self, ns| {
                 if this.should_report_errs() {
                     let what = if ns == TypeNS { "type parameters" } else { "local variables" };
-                    this.r
-                        .tcx
-                        .sess
-                        .create_err(ImportsCannotReferTo { span: ident.span, what })
-                        .emit();
+                    this.r.dcx().create_err(ImportsCannotReferTo { span: ident.span, what }).emit();
                 }
             };
 
@@ -2599,7 +2595,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
             if param.ident.name == kw::UnderscoreLifetime {
                 rustc_errors::struct_span_err!(
-                    self.r.tcx.sess,
+                    self.r.dcx(),
                     param.ident.span,
                     E0637,
                     "`'_` cannot be used here"
@@ -2613,7 +2609,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
 
             if param.ident.name == kw::StaticLifetime {
                 rustc_errors::struct_span_err!(
-                    self.r.tcx.sess,
+                    self.r.dcx(),
                     param.ident.span,
                     E0262,
                     "invalid lifetime parameter name: `{}`",
@@ -3559,7 +3555,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
             Res::SelfCtor(_) => {
                 // We resolve `Self` in pattern position as an ident sometimes during recovery,
                 // so delay a bug instead of ICEing.
-                self.r.tcx.sess.span_delayed_bug(
+                self.r.dcx().span_delayed_bug(
                     ident.span,
                     "unexpected `SelfCtor` in pattern, expected identifier"
                 );
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index e410e76abf473..9bd58dfe82be5 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -429,11 +429,8 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         let base_error = self.make_base_error(path, span, source, res);
 
         let code = source.error_code(res.is_some());
-        let mut err = self.r.tcx.sess.struct_span_err_with_code(
-            base_error.span,
-            base_error.msg.clone(),
-            code,
-        );
+        let mut err =
+            self.r.dcx().struct_span_err_with_code(base_error.span, base_error.msg.clone(), code);
 
         self.suggest_at_operator_in_slice_pat_with_range(&mut err, path);
         self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
@@ -2602,7 +2599,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         debug_assert_ne!(lifetime_ref.ident.name, kw::UnderscoreLifetime);
         let mut err = if let Some(outer) = outer_lifetime_ref {
             let mut err = struct_span_err!(
-                self.r.tcx.sess,
+                self.r.dcx(),
                 lifetime_ref.ident.span,
                 E0401,
                 "can't use generic parameters from outer item",
@@ -2612,7 +2609,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             err
         } else {
             let mut err = struct_span_err!(
-                self.r.tcx.sess,
+                self.r.dcx(),
                 lifetime_ref.ident.span,
                 E0261,
                 "use of undeclared lifetime name `{}`",
@@ -2721,8 +2718,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
 
     pub(crate) fn emit_non_static_lt_in_const_param_ty_error(&self, lifetime_ref: &ast::Lifetime) {
         self.r
-            .tcx
-            .sess
+            .dcx()
             .create_err(errors::ParamInTyOfConstParam {
                 span: lifetime_ref.ident.span,
                 name: lifetime_ref.ident.name,
@@ -2742,8 +2738,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         match cause {
             NoConstantGenericsReason::IsEnumDiscriminant => {
                 self.r
-                    .tcx
-                    .sess
+                    .dcx()
                     .create_err(errors::ParamInEnumDiscriminant {
                         span: lifetime_ref.ident.span,
                         name: lifetime_ref.ident.name,
@@ -2754,8 +2749,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
             NoConstantGenericsReason::NonTrivialConstArg => {
                 assert!(!self.r.tcx.features().generic_const_exprs);
                 self.r
-                    .tcx
-                    .sess
+                    .dcx()
                     .create_err(errors::ParamInNonTrivialAnonConst {
                         span: lifetime_ref.ident.span,
                         name: lifetime_ref.ident.name,
@@ -2781,7 +2775,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
         let spans: Vec<_> = lifetime_refs.iter().map(|lt| lt.span).collect();
 
         let mut err = struct_span_err!(
-            self.r.tcx.sess,
+            self.r.dcx(),
             spans,
             E0106,
             "missing lifetime specifier{}",
@@ -3286,7 +3280,7 @@ fn mk_where_bound_predicate(
 /// Report lifetime/lifetime shadowing as an error.
 pub(super) fn signal_lifetime_shadowing(sess: &Session, orig: Ident, shadower: Ident) {
     let mut err = struct_span_err!(
-        sess,
+        sess.dcx(),
         shadower.span,
         E0496,
         "lifetime name `{}` shadows a lifetime name that is already in scope",
@@ -3320,7 +3314,7 @@ impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> {
 pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident) {
     let name = shadower.name;
     let shadower = shadower.span;
-    let mut err = sess.struct_span_warn(
+    let mut err = sess.dcx().struct_span_warn(
         shadower,
         format!("label name `{name}` shadows a label name that is already in scope"),
     );
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 1001286b6c2d7..0f7294cdad09c 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -126,7 +126,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
                 Some(ident) => {
                     if let Some(old_ident) = registered_tools.replace(ident) {
                         let msg = format!("{} `{}` was already registered", "tool", ident);
-                        tcx.sess
+                        tcx.dcx()
                             .struct_span_err(ident.span, msg)
                             .span_label(old_ident.span, "already registered here")
                             .emit();
@@ -135,7 +135,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
                 None => {
                     let msg = format!("`{}` only accepts identifiers", sym::register_tool);
                     let span = nested_meta.span();
-                    tcx.sess
+                    tcx.dcx()
                         .struct_span_err(span, msg)
                         .span_label(span, "not an identifier")
                         .emit();
@@ -205,7 +205,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
 
     fn register_builtin_macro(&mut self, name: Symbol, ext: SyntaxExtensionKind) {
         if self.builtin_macros.insert(name, BuiltinMacroState::NotYetSeen(ext)).is_some() {
-            self.tcx.sess.dcx().bug(format!("built-in macro `{name}` was already registered"));
+            self.dcx().bug(format!("built-in macro `{name}` was already registered"));
         }
     }
 
@@ -447,7 +447,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
                 PathResult::NonModule(..) |
                 // HACK(Urgau): This shouldn't be necessary
                 PathResult::Failed { is_error_from_last_segment: false, .. } => {
-                    self.tcx.sess
+                    self.dcx()
                         .emit_err(errors::CfgAccessibleUnsure { span });
 
                     // If we get a partially resolved NonModule in one namespace, we should get the
@@ -512,10 +512,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         // Report errors for the resolved macro.
         for segment in &path.segments {
             if let Some(args) = &segment.args {
-                self.tcx.sess.span_err(args.span(), "generic arguments in macro path");
+                self.dcx().span_err(args.span(), "generic arguments in macro path");
             }
             if kind == MacroKind::Attr && segment.ident.as_str().starts_with("rustc") {
-                self.tcx.sess.span_err(
+                self.dcx().span_err(
                     segment.ident.span,
                     "attributes starting with `rustc` are reserved for use by the `rustc` compiler",
                 );
@@ -527,7 +527,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 if let Some(def_id) = def_id.as_local() {
                     self.unused_macros.remove(&def_id);
                     if self.proc_macro_stubs.contains(&def_id) {
-                        self.tcx.sess.emit_err(errors::ProcMacroSameCrate {
+                        self.dcx().emit_err(errors::ProcMacroSameCrate {
                             span: path.span,
                             is_test: self.tcx.sess.is_test_crate(),
                         });
@@ -576,7 +576,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 err.add_as_non_derive = Some(AddAsNonDerive { macro_path: &path_str });
             }
 
-            let mut err = self.tcx.sess.create_err(err);
+            let mut err = self.dcx().create_err(err);
             err.span_label(path.span, format!("not {article} {expected}"));
 
             err.emit();
@@ -707,7 +707,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     // Make sure compilation does not succeed if preferred macro resolution
                     // has changed after the macro had been expanded. In theory all such
                     // situations should be reported as errors, so this is a bug.
-                    this.tcx.sess.span_delayed_bug(span, "inconsistent resolution for a macro");
+                    this.dcx().span_delayed_bug(span, "inconsistent resolution for a macro");
                 }
             } else {
                 // It's possible that the macro was unresolved (indeterminate) and silently
@@ -718,7 +718,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 // even if speculative `resolve_path` returned nothing previously, so we skip this
                 // less informative error if the privacy error is reported elsewhere.
                 if this.privacy_errors.is_empty() {
-                    this.tcx.sess.emit_err(CannotDetermineMacroResolution {
+                    this.dcx().emit_err(CannotDetermineMacroResolution {
                         span,
                         kind: kind.descr(),
                         path: Segment::names_to_string(path),
@@ -825,7 +825,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 Err(..) => {
                     let expected = kind.descr_expected();
 
-                    let mut err = self.tcx.sess.create_err(CannotFindIdentInThisScope {
+                    let mut err = self.dcx().create_err(CannotFindIdentInThisScope {
                         span: ident.span,
                         expected,
                         ident,
@@ -907,7 +907,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) {
                 let msg =
                     format!("cannot use {} {} through an import", kind.article(), kind.descr());
-                let mut err = self.tcx.sess.struct_span_err(span, msg);
+                let mut err = self.dcx().struct_span_err(span, msg);
                 if let Some(binding) = binding {
                     err.span_note(binding.span, format!("the {} imported here", kind.descr()));
                 }
@@ -922,7 +922,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         if ident.name == sym::cfg || ident.name == sym::cfg_attr {
             let macro_kind = self.get_macro(res).map(|macro_data| macro_data.ext.macro_kind());
             if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
-                self.tcx.sess.span_err(
+                self.dcx().span_err(
                     ident.span,
                     format!("name `{ident}` is reserved in attribute namespace"),
                 );
@@ -950,7 +950,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                     }
                     BuiltinMacroState::AlreadySeen(span) => {
                         struct_span_err!(
-                            self.tcx.sess,
+                            self.dcx(),
                             item.span,
                             E0773,
                             "attempted to define built-in macro more than once"
@@ -961,7 +961,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
                 }
             } else {
                 let msg = format!("cannot find a built-in macro with name `{}`", item.ident);
-                self.tcx.sess.span_err(item.span, msg);
+                self.dcx().span_err(item.span, msg);
             }
         }
 
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 0d731e330f3d9..d158163f4a463 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -883,7 +883,7 @@ impl OutFileName {
             OutFileName::Stdout => print!("{content}"),
             OutFileName::Real(path) => {
                 if let Err(e) = fs::write(path, content) {
-                    sess.emit_fatal(FileWriteFail { path, err: e.to_string() });
+                    sess.dcx().emit_fatal(FileWriteFail { path, err: e.to_string() });
                 }
             }
         }
@@ -1325,7 +1325,7 @@ fn default_configuration(sess: &Session) -> Cfg {
 
     // `target_has_atomic*`
     let layout = sess.target.parse_data_layout().unwrap_or_else(|err| {
-        sess.emit_fatal(err);
+        sess.dcx().emit_fatal(err);
     });
     let mut has_atomic = false;
     for (i, align) in [
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index 9f7d918d98b9c..0f86773b73fc9 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -364,13 +364,14 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
     }
 
     let token::Lit { kind, symbol, suffix, .. } = lit;
+    let dcx = &sess.dcx;
     match err {
         // `LexerError` is an error, but it was already reported
         // by lexer, so here we don't report it the second time.
         LitError::LexerError => {}
         LitError::InvalidSuffix => {
             if let Some(suffix) = suffix {
-                sess.emit_err(InvalidLiteralSuffix { span, kind: kind.descr(), suffix });
+                dcx.emit_err(InvalidLiteralSuffix { span, kind: kind.descr(), suffix });
             }
         }
         LitError::InvalidIntSuffix => {
@@ -378,11 +379,11 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
             let suf = suf.as_str();
             if looks_like_width_suffix(&['i', 'u'], suf) {
                 // If it looks like a width, try to be helpful.
-                sess.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() });
+                dcx.emit_err(InvalidIntLiteralWidth { span, width: suf[1..].into() });
             } else if let Some(fixed) = fix_base_capitalisation(symbol.as_str(), suf) {
-                sess.emit_err(InvalidNumLiteralBasePrefix { span, fixed });
+                dcx.emit_err(InvalidNumLiteralBasePrefix { span, fixed });
             } else {
-                sess.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() });
+                dcx.emit_err(InvalidNumLiteralSuffix { span, suffix: suf.to_string() });
             }
         }
         LitError::InvalidFloatSuffix => {
@@ -390,16 +391,16 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
             let suf = suf.as_str();
             if looks_like_width_suffix(&['f'], suf) {
                 // If it looks like a width, try to be helpful.
-                sess.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() });
+                dcx.emit_err(InvalidFloatLiteralWidth { span, width: suf[1..].to_string() });
             } else {
-                sess.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() });
+                dcx.emit_err(InvalidFloatLiteralSuffix { span, suffix: suf.to_string() });
             }
         }
         LitError::NonDecimalFloat(base) => {
             match base {
-                16 => sess.emit_err(HexadecimalFloatLiteralNotSupported { span }),
-                8 => sess.emit_err(OctalFloatLiteralNotSupported { span }),
-                2 => sess.emit_err(BinaryFloatLiteralNotSupported { span }),
+                16 => dcx.emit_err(HexadecimalFloatLiteralNotSupported { span }),
+                8 => dcx.emit_err(OctalFloatLiteralNotSupported { span }),
+                2 => dcx.emit_err(BinaryFloatLiteralNotSupported { span }),
                 _ => unreachable!(),
             };
         }
@@ -411,13 +412,13 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
                 16 => format!("{max:#x}"),
                 _ => format!("{max}"),
             };
-            sess.emit_err(IntLiteralTooLarge { span, limit });
+            dcx.emit_err(IntLiteralTooLarge { span, limit });
         }
         LitError::NulInCStr(range) => {
             let lo = BytePos(span.lo().0 + range.start as u32 + 2);
             let hi = BytePos(span.lo().0 + range.end as u32 + 2);
             let span = span.with_lo(lo).with_hi(hi);
-            sess.emit_err(NulInCStr { span });
+            dcx.emit_err(NulInCStr { span });
         }
     }
 }
diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs
index 2ff32b5bb9a6f..db976b3040487 100644
--- a/compiler/rustc_session/src/output.rs
+++ b/compiler/rustc_session/src/output.rs
@@ -36,7 +36,7 @@ pub fn out_filename(
 /// read-only file. We should be consistent.
 pub fn check_file_is_writeable(file: &Path, sess: &Session) {
     if !is_writeable(file) {
-        sess.emit_fatal(FileIsNotWriteable { file });
+        sess.dcx().emit_fatal(FileIsNotWriteable { file });
     }
 }
 
@@ -64,7 +64,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol {
         let s = Symbol::intern(s);
         if let Some((attr, name)) = attr_crate_name {
             if name != s {
-                sess.emit_err(CrateNameDoesNotMatch { span: attr.span, s, name });
+                sess.dcx().emit_err(CrateNameDoesNotMatch { span: attr.span, s, name });
             }
         }
         return validate(s, None);
@@ -76,7 +76,7 @@ pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute]) -> Symbol {
     if let Input::File(ref path) = sess.io.input {
         if let Some(s) = path.file_stem().and_then(|s| s.to_str()) {
             if s.starts_with('-') {
-                sess.emit_err(CrateNameInvalid { s });
+                sess.dcx().emit_err(CrateNameInvalid { s });
             } else {
                 return validate(Symbol::intern(&s.replace('-', "_")), None);
             }
@@ -91,7 +91,7 @@ pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option<Span>) {
     {
         if s.is_empty() {
             err_count += 1;
-            sess.emit_err(CrateNameEmpty { span: sp });
+            sess.dcx().emit_err(CrateNameEmpty { span: sp });
         }
         for c in s.as_str().chars() {
             if c.is_alphanumeric() {
@@ -101,7 +101,7 @@ pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option<Span>) {
                 continue;
             }
             err_count += 1;
-            sess.emit_err(InvalidCharacterInCrateName {
+            sess.dcx().emit_err(InvalidCharacterInCrateName {
                 span: sp,
                 character: c,
                 crate_name: s,
@@ -115,7 +115,7 @@ pub fn validate_crate_name(sess: &Session, s: Symbol, sp: Option<Span>) {
     }
 
     if err_count > 0 {
-        sess.abort_if_errors();
+        sess.dcx().abort_if_errors();
     }
 }
 
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 52a637b74e7a2..439fa18b7fadc 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -14,7 +14,7 @@ use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc};
 use rustc_errors::{emitter::SilentEmitter, DiagCtxt};
 use rustc_errors::{
     fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
-    ErrorGuaranteed, FatalAbort, IntoDiagnostic, Level, MultiSpan, StashKey,
+    MultiSpan, StashKey,
 };
 use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures};
 use rustc_span::edition::Edition;
@@ -108,7 +108,7 @@ pub fn feature_err_issue(
         }
     }
 
-    let mut err = sess.create_err(FeatureGateError { span, explain: explain.into() });
+    let mut err = sess.dcx.create_err(FeatureGateError { span, explain: explain.into() });
     add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false);
     err
 }
@@ -316,74 +316,4 @@ impl ParseSess {
         // AppendOnlyVec, so we resort to this scheme.
         self.proc_macro_quoted_spans.iter_enumerated()
     }
-
-    #[track_caller]
-    pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> {
-        err.into_diagnostic(&self.dcx, Level::Error { lint: false })
-    }
-
-    #[track_caller]
-    pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
-        self.create_err(err).emit()
-    }
-
-    #[track_caller]
-    pub fn create_warning<'a>(
-        &'a self,
-        warning: impl IntoDiagnostic<'a, ()>,
-    ) -> DiagnosticBuilder<'a, ()> {
-        warning.into_diagnostic(&self.dcx, Level::Warning(None))
-    }
-
-    #[track_caller]
-    pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
-        self.create_warning(warning).emit()
-    }
-
-    #[track_caller]
-    pub fn create_note<'a>(
-        &'a self,
-        note: impl IntoDiagnostic<'a, ()>,
-    ) -> DiagnosticBuilder<'a, ()> {
-        note.into_diagnostic(&self.dcx, Level::Note)
-    }
-
-    #[track_caller]
-    pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) {
-        self.create_note(note).emit()
-    }
-
-    #[track_caller]
-    pub fn create_fatal<'a>(
-        &'a self,
-        fatal: impl IntoDiagnostic<'a, FatalAbort>,
-    ) -> DiagnosticBuilder<'a, FatalAbort> {
-        fatal.into_diagnostic(&self.dcx, Level::Fatal)
-    }
-
-    #[track_caller]
-    pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! {
-        self.create_fatal(fatal).emit()
-    }
-
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_err(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_> {
-        self.dcx.struct_err(msg)
-    }
-
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        self.dcx.struct_warn(msg)
-    }
-
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_fatal(
-        &self,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_, FatalAbort> {
-        self.dcx.struct_fatal(msg)
-    }
 }
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 272e231d3edc1..53dd48ea272f8 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -24,7 +24,7 @@ use rustc_errors::registry::Registry;
 use rustc_errors::{
     error_code, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticId,
     DiagnosticMessage, ErrorGuaranteed, FatalAbort, FluentBundle, IntoDiagnostic,
-    LazyFallbackBundle, MultiSpan, TerminalUrl,
+    LazyFallbackBundle, TerminalUrl,
 };
 use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
@@ -265,7 +265,7 @@ impl Session {
         if !unleashed_features.is_empty() {
             let mut must_err = false;
             // Create a diagnostic pointing at where things got unleashed.
-            self.emit_warning(errors::SkippingConstChecks {
+            self.dcx().emit_warning(errors::SkippingConstChecks {
                 unleashed_features: unleashed_features
                     .iter()
                     .map(|(span, gate)| {
@@ -279,9 +279,9 @@ impl Session {
             });
 
             // If we should err, make sure we did.
-            if must_err && self.has_errors().is_none() {
+            if must_err && self.dcx().has_errors().is_none() {
                 // We have skipped a feature gate, and not run into other errors... reject.
-                self.emit_err(errors::NotCircumventFeature);
+                self.dcx().emit_err(errors::NotCircumventFeature);
             }
         }
     }
@@ -310,225 +310,20 @@ impl Session {
         self.opts.test
     }
 
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_span_warn<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_, ()> {
-        self.dcx().struct_span_warn(sp, msg)
-    }
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_span_warn_with_code<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-        code: DiagnosticId,
-    ) -> DiagnosticBuilder<'_, ()> {
-        self.dcx().struct_span_warn_with_code(sp, msg, code)
-    }
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        self.dcx().struct_warn(msg)
-    }
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        self.dcx().struct_allow(msg)
-    }
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_expect(
-        &self,
-        msg: impl Into<DiagnosticMessage>,
-        id: lint::LintExpectationId,
-    ) -> DiagnosticBuilder<'_, ()> {
-        self.dcx().struct_expect(msg, id)
-    }
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_span_err<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_> {
-        self.dcx().struct_span_err(sp, msg)
-    }
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_span_err_with_code<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-        code: DiagnosticId,
-    ) -> DiagnosticBuilder<'_> {
-        self.dcx().struct_span_err_with_code(sp, msg, code)
-    }
-    // FIXME: This method should be removed (every error should have an associated error code).
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_err(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_> {
-        self.parse_sess.struct_err(msg)
-    }
-    #[track_caller]
-    #[rustc_lint_diagnostics]
-    pub fn struct_err_with_code(
-        &self,
-        msg: impl Into<DiagnosticMessage>,
-        code: DiagnosticId,
-    ) -> DiagnosticBuilder<'_> {
-        self.dcx().struct_err_with_code(msg, code)
-    }
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_warn_with_code(
-        &self,
-        msg: impl Into<DiagnosticMessage>,
-        code: DiagnosticId,
-    ) -> DiagnosticBuilder<'_, ()> {
-        self.dcx().struct_warn_with_code(msg, code)
-    }
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_span_fatal<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_, FatalAbort> {
-        self.dcx().struct_span_fatal(sp, msg)
-    }
-    #[rustc_lint_diagnostics]
-    pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-        code: DiagnosticId,
-    ) -> DiagnosticBuilder<'_, FatalAbort> {
-        self.dcx().struct_span_fatal_with_code(sp, msg, code)
-    }
-    #[rustc_lint_diagnostics]
-    pub fn struct_fatal(
-        &self,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_, FatalAbort> {
-        self.dcx().struct_fatal(msg)
-    }
-
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.dcx().span_fatal(sp, msg)
-    }
-    #[rustc_lint_diagnostics]
-    pub fn span_fatal_with_code<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-        code: DiagnosticId,
-    ) -> ! {
-        self.dcx().span_fatal_with_code(sp, msg, code)
-    }
-    #[rustc_lint_diagnostics]
-    pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.dcx().fatal(msg)
-    }
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn span_err<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> ErrorGuaranteed {
-        self.dcx().span_err(sp, msg)
-    }
-    #[rustc_lint_diagnostics]
-    pub fn span_err_with_code<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-        code: DiagnosticId,
-    ) -> ErrorGuaranteed {
-        self.dcx().span_err_with_code(sp, msg, code)
-    }
-    #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
-        self.dcx().err(msg)
-    }
-    #[track_caller]
-    pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> {
-        self.parse_sess.create_err(err)
-    }
     #[track_caller]
     pub fn create_feature_err<'a>(
         &'a self,
         err: impl IntoDiagnostic<'a>,
         feature: Symbol,
     ) -> DiagnosticBuilder<'a> {
-        let mut err = self.parse_sess.create_err(err);
+        let mut err = self.dcx().create_err(err);
         if err.code.is_none() {
             err.code(error_code!(E0658));
         }
         add_feature_diagnostics(&mut err, &self.parse_sess, feature);
         err
     }
-    #[track_caller]
-    pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
-        self.parse_sess.emit_err(err)
-    }
-    #[track_caller]
-    pub fn create_warning<'a>(
-        &'a self,
-        err: impl IntoDiagnostic<'a, ()>,
-    ) -> DiagnosticBuilder<'a, ()> {
-        self.parse_sess.create_warning(err)
-    }
-    #[track_caller]
-    pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
-        self.parse_sess.emit_warning(warning)
-    }
-    #[track_caller]
-    pub fn create_note<'a>(
-        &'a self,
-        note: impl IntoDiagnostic<'a, ()>,
-    ) -> DiagnosticBuilder<'a, ()> {
-        self.parse_sess.create_note(note)
-    }
-    #[track_caller]
-    pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) {
-        self.parse_sess.emit_note(note)
-    }
-    #[track_caller]
-    pub fn create_fatal<'a>(
-        &'a self,
-        fatal: impl IntoDiagnostic<'a, FatalAbort>,
-    ) -> DiagnosticBuilder<'a, FatalAbort> {
-        self.parse_sess.create_fatal(fatal)
-    }
-    #[track_caller]
-    pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! {
-        self.parse_sess.emit_fatal(fatal)
-    }
-    #[inline]
-    pub fn err_count(&self) -> usize {
-        self.dcx().err_count()
-    }
-    pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
-        self.dcx().has_errors()
-    }
-    pub fn has_errors_or_span_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
-        self.dcx().has_errors_or_span_delayed_bugs()
-    }
-    pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> {
-        self.dcx().is_compilation_going_to_fail()
-    }
-    pub fn abort_if_errors(&self) {
-        self.dcx().abort_if_errors();
-    }
+
     pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> {
         if let Some(reported) = self.dcx().has_errors_or_lint_errors() {
             let _ = self.dcx().emit_stashed_diagnostics();
@@ -537,75 +332,24 @@ impl Session {
             Ok(())
         }
     }
+
     // FIXME(matthewjasper) Remove this method, it should never be needed.
     pub fn track_errors<F, T>(&self, f: F) -> Result<T, ErrorGuaranteed>
     where
         F: FnOnce() -> T,
     {
-        let old_count = self.err_count();
+        let old_count = self.dcx().err_count();
         let result = f();
-        if self.err_count() == old_count {
+        if self.dcx().err_count() == old_count {
             Ok(result)
         } else {
-            Err(self.span_delayed_bug(
+            Err(self.dcx().span_delayed_bug(
                 rustc_span::DUMMY_SP,
                 "`self.err_count()` changed but an error was not emitted",
             ))
         }
     }
 
-    #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    #[track_caller]
-    pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
-        self.dcx().span_warn(sp, msg)
-    }
-
-    #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    pub fn span_warn_with_code<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-        code: DiagnosticId,
-    ) {
-        self.dcx().span_warn_with_code(sp, msg, code)
-    }
-
-    #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
-        self.dcx().warn(msg)
-    }
-
-    /// Ensures that compilation cannot succeed.
-    ///
-    /// If this function has been called but no errors have been emitted and
-    /// compilation succeeds, it will cause an internal compiler error (ICE).
-    ///
-    /// This can be used in code paths that should never run on successful compilations.
-    /// For example, it can be used to create an [`ErrorGuaranteed`]
-    /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission
-    /// directly).
-    ///
-    /// If no span is available, use [`DUMMY_SP`].
-    ///
-    /// [`DUMMY_SP`]: rustc_span::DUMMY_SP
-    ///
-    /// Note: this function used to be called `delay_span_bug`. It was renamed
-    /// to match similar functions like `span_err`, `span_warn`, etc.
-    #[track_caller]
-    pub fn span_delayed_bug<S: Into<MultiSpan>>(
-        &self,
-        sp: S,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> ErrorGuaranteed {
-        self.dcx().span_delayed_bug(sp, msg)
-    }
-
     /// Used for code paths of expensive computations that should only take place when
     /// warnings or errors are emitted. If no messages are emitted ("good path"), then
     /// it's likely a bug.
@@ -623,28 +367,6 @@ impl Session {
         self.dcx().good_path_delayed_bug(msg)
     }
 
-    #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    pub fn note(&self, msg: impl Into<DiagnosticMessage>) {
-        self.dcx().note(msg)
-    }
-
-    #[track_caller]
-    #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    pub fn span_note<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
-        self.dcx().span_note(sp, msg)
-    }
-
-    #[rustc_lint_diagnostics]
-    #[allow(rustc::untranslatable_diagnostic)]
-    #[allow(rustc::diagnostic_outside_of_impl)]
-    pub fn struct_note(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        self.dcx().struct_note(msg)
-    }
-
     #[inline]
     pub fn dcx(&self) -> &DiagCtxt {
         &self.parse_sess.dcx
@@ -854,7 +576,7 @@ impl Session {
                         // We only call `msg` in case we can actually emit warnings.
                         // Otherwise, this could cause a `good_path_delayed_bug` to
                         // trigger (issue #79546).
-                        self.emit_warning(errors::OptimisationFuelExhausted { msg: msg() });
+                        self.dcx().emit_warning(errors::OptimisationFuelExhausted { msg: msg() });
                     }
                     fuel.out_of_fuel = true;
                 } else if fuel.remaining > 0 {
@@ -1502,28 +1224,28 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         && sess.opts.cg.prefer_dynamic
         && sess.target.is_like_windows
     {
-        sess.emit_err(errors::LinkerPluginToWindowsNotSupported);
+        sess.dcx().emit_err(errors::LinkerPluginToWindowsNotSupported);
     }
 
     // Make sure that any given profiling data actually exists so LLVM can't
     // decide to silently skip PGO.
     if let Some(ref path) = sess.opts.cg.profile_use {
         if !path.exists() {
-            sess.emit_err(errors::ProfileUseFileDoesNotExist { path });
+            sess.dcx().emit_err(errors::ProfileUseFileDoesNotExist { path });
         }
     }
 
     // Do the same for sample profile data.
     if let Some(ref path) = sess.opts.unstable_opts.profile_sample_use {
         if !path.exists() {
-            sess.emit_err(errors::ProfileSampleUseFileDoesNotExist { path });
+            sess.dcx().emit_err(errors::ProfileSampleUseFileDoesNotExist { path });
         }
     }
 
     // Unwind tables cannot be disabled if the target requires them.
     if let Some(include_uwtables) = sess.opts.cg.force_unwind_tables {
         if sess.target.requires_uwtable && !include_uwtables {
-            sess.emit_err(errors::TargetRequiresUnwindTables);
+            sess.dcx().emit_err(errors::TargetRequiresUnwindTables);
         }
     }
 
@@ -1533,10 +1255,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     match unsupported_sanitizers.into_iter().count() {
         0 => {}
         1 => {
-            sess.emit_err(errors::SanitizerNotSupported { us: unsupported_sanitizers.to_string() });
+            sess.dcx()
+                .emit_err(errors::SanitizerNotSupported { us: unsupported_sanitizers.to_string() });
         }
         _ => {
-            sess.emit_err(errors::SanitizersNotSupported {
+            sess.dcx().emit_err(errors::SanitizersNotSupported {
                 us: unsupported_sanitizers.to_string(),
             });
         }
@@ -1544,7 +1267,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     // Cannot mix and match sanitizers.
     let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter();
     if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
-        sess.emit_err(errors::CannotMixAndMatchSanitizers {
+        sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
             first: first.to_string(),
             second: second.to_string(),
         });
@@ -1552,14 +1275,14 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
 
     // Cannot enable crt-static with sanitizers on Linux
     if sess.crt_static(None) && !sess.opts.unstable_opts.sanitizer.is_empty() {
-        sess.emit_err(errors::CannotEnableCrtStaticLinux);
+        sess.dcx().emit_err(errors::CannotEnableCrtStaticLinux);
     }
 
     // LLVM CFI requires LTO.
     if sess.is_sanitizer_cfi_enabled()
         && !(sess.lto() == config::Lto::Fat || sess.opts.cg.linker_plugin_lto.enabled())
     {
-        sess.emit_err(errors::SanitizerCfiRequiresLto);
+        sess.dcx().emit_err(errors::SanitizerCfiRequiresLto);
     }
 
     // LLVM CFI using rustc LTO requires a single codegen unit.
@@ -1567,12 +1290,12 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
         && sess.lto() == config::Lto::Fat
         && !(sess.codegen_units().as_usize() == 1)
     {
-        sess.emit_err(errors::SanitizerCfiRequiresSingleCodegenUnit);
+        sess.dcx().emit_err(errors::SanitizerCfiRequiresSingleCodegenUnit);
     }
 
     // LLVM CFI is incompatible with LLVM KCFI.
     if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
-        sess.emit_err(errors::CannotMixAndMatchSanitizers {
+        sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
             first: "cfi".to_string(),
             second: "kcfi".to_string(),
         });
@@ -1581,21 +1304,21 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     // Canonical jump tables requires CFI.
     if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
         if !sess.is_sanitizer_cfi_enabled() {
-            sess.emit_err(errors::SanitizerCfiCanonicalJumpTablesRequiresCfi);
+            sess.dcx().emit_err(errors::SanitizerCfiCanonicalJumpTablesRequiresCfi);
         }
     }
 
     // LLVM CFI pointer generalization requires CFI or KCFI.
     if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
         if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
-            sess.emit_err(errors::SanitizerCfiGeneralizePointersRequiresCfi);
+            sess.dcx().emit_err(errors::SanitizerCfiGeneralizePointersRequiresCfi);
         }
     }
 
     // LLVM CFI integer normalization requires CFI or KCFI.
     if sess.is_sanitizer_cfi_normalize_integers_enabled() {
         if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
-            sess.emit_err(errors::SanitizerCfiNormalizeIntegersRequiresCfi);
+            sess.dcx().emit_err(errors::SanitizerCfiNormalizeIntegersRequiresCfi);
         }
     }
 
@@ -1605,19 +1328,19 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             || sess.lto() == config::Lto::Thin
             || sess.opts.cg.linker_plugin_lto.enabled())
     {
-        sess.emit_err(errors::SplitLtoUnitRequiresLto);
+        sess.dcx().emit_err(errors::SplitLtoUnitRequiresLto);
     }
 
     // VFE requires LTO.
     if sess.lto() != config::Lto::Fat {
         if sess.opts.unstable_opts.virtual_function_elimination {
-            sess.emit_err(errors::UnstableVirtualFunctionElimination);
+            sess.dcx().emit_err(errors::UnstableVirtualFunctionElimination);
         }
     }
 
     if sess.opts.unstable_opts.stack_protector != StackProtector::None {
         if !sess.target.options.supports_stack_protector {
-            sess.emit_warning(errors::StackProtectorNotSupportedForTarget {
+            sess.dcx().emit_warning(errors::StackProtectorNotSupportedForTarget {
                 stack_protector: sess.opts.unstable_opts.stack_protector,
                 target_triple: &sess.opts.target_triple,
             });
@@ -1625,35 +1348,36 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
     }
 
     if sess.opts.unstable_opts.branch_protection.is_some() && sess.target.arch != "aarch64" {
-        sess.emit_err(errors::BranchProtectionRequiresAArch64);
+        sess.dcx().emit_err(errors::BranchProtectionRequiresAArch64);
     }
 
     if let Some(dwarf_version) = sess.opts.unstable_opts.dwarf_version {
         if dwarf_version > 5 {
-            sess.emit_err(errors::UnsupportedDwarfVersion { dwarf_version });
+            sess.dcx().emit_err(errors::UnsupportedDwarfVersion { dwarf_version });
         }
     }
 
     if !sess.target.options.supported_split_debuginfo.contains(&sess.split_debuginfo())
         && !sess.opts.unstable_opts.unstable_options
     {
-        sess.emit_err(errors::SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() });
+        sess.dcx()
+            .emit_err(errors::SplitDebugInfoUnstablePlatform { debuginfo: sess.split_debuginfo() });
     }
 
     if sess.opts.unstable_opts.instrument_xray.is_some() && !sess.target.options.supports_xray {
-        sess.emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() });
+        sess.dcx().emit_err(errors::InstrumentationNotSupported { us: "XRay".to_string() });
     }
 
     if let Some(flavor) = sess.opts.cg.linker_flavor {
         if let Some(compatible_list) = sess.target.linker_flavor.check_compatibility(flavor) {
             let flavor = flavor.desc();
-            sess.emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list });
+            sess.dcx().emit_err(errors::IncompatibleLinkerFlavor { flavor, compatible_list });
         }
     }
 
     if sess.opts.unstable_opts.function_return != FunctionReturn::default() {
         if sess.target.arch != "x86" && sess.target.arch != "x86_64" {
-            sess.emit_err(errors::FunctionReturnRequiresX86OrX8664);
+            sess.dcx().emit_err(errors::FunctionReturnRequiresX86OrX8664);
         }
     }
 
@@ -1668,7 +1392,7 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
             if let Some(code_model) = sess.code_model()
                 && code_model == CodeModel::Large
             {
-                sess.emit_err(errors::FunctionReturnThunkExternRequiresNonLargeCodeModel);
+                sess.dcx().emit_err(errors::FunctionReturnThunkExternRequiresNonLargeCodeModel);
             }
         }
     }
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index eddfd0df318e2..6766080a54f51 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -60,18 +60,18 @@ impl SymbolNamesTest<'_> {
                 tcx.erase_regions(GenericArgs::identity_for_item(tcx, def_id)),
             );
             let mangled = tcx.symbol_name(instance);
-            tcx.sess.emit_err(TestOutput {
+            tcx.dcx().emit_err(TestOutput {
                 span: attr.span,
                 kind: Kind::SymbolName,
                 content: format!("{mangled}"),
             });
             if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
-                tcx.sess.emit_err(TestOutput {
+                tcx.dcx().emit_err(TestOutput {
                     span: attr.span,
                     kind: Kind::Demangling,
                     content: format!("{demangling}"),
                 });
-                tcx.sess.emit_err(TestOutput {
+                tcx.dcx().emit_err(TestOutput {
                     span: attr.span,
                     kind: Kind::DemanglingAlt,
                     content: format!("{demangling:#}"),
@@ -80,7 +80,7 @@ impl SymbolNamesTest<'_> {
         }
 
         for attr in tcx.get_attrs(def_id, DEF_PATH) {
-            tcx.sess.emit_err(TestOutput {
+            tcx.dcx().emit_err(TestOutput {
                 span: attr.span,
                 kind: Kind::DefPath,
                 content: with_no_trimmed_paths!(tcx.def_path_str(def_id)),
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 3d673f2f1ec04..d2962b2968b37 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -557,7 +557,7 @@ fn encode_ty<'tcx>(
                             rustc::diagnostic_outside_of_impl,
                             rustc::untranslatable_diagnostic
                         )]
-                        tcx.sess
+                        tcx.dcx()
                             .struct_span_err(
                                 cfi_encoding.span,
                                 format!("invalid `cfi_encoding` for `{:?}`", ty.kind()),
@@ -609,7 +609,7 @@ fn encode_ty<'tcx>(
                             rustc::diagnostic_outside_of_impl,
                             rustc::untranslatable_diagnostic
                         )]
-                        tcx.sess
+                        tcx.dcx()
                             .struct_span_err(
                                 cfi_encoding.span,
                                 format!("invalid `cfi_encoding` for `{:?}`", ty.kind()),
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index 0e9656a1e1844..bac08f6588f1c 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -195,7 +195,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
             };
 
             let error_response = |ecx: &mut EvalCtxt<'_, 'tcx>, reason| {
-                let guar = tcx.sess.span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason);
+                let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason);
                 let error_term = match assoc_def.item.kind {
                     ty::AssocKind::Const => ty::Const::new_error(
                         tcx,
@@ -286,7 +286,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
         ecx: &mut EvalCtxt<'_, 'tcx>,
         goal: Goal<'tcx, Self>,
     ) -> QueryResult<'tcx> {
-        ecx.tcx().sess.span_delayed_bug(
+        ecx.tcx().dcx().span_delayed_bug(
             ecx.tcx().def_span(goal.predicate.def_id()),
             "associated types not allowed on auto traits",
         );
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index c6d029ddb650a..c43447585746a 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -787,7 +787,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
                                 Ok(None) => {
                                     let tcx = self.tcx;
                                     let reported =
-                                        tcx.sess.emit_err(UnableToConstructConstantValue {
+                                        tcx.dcx().emit_err(UnableToConstructConstantValue {
                                             span: tcx.def_span(unevaluated.def),
                                             unevaluated: unevaluated,
                                         });
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index aee5132079205..451e0823c2522 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -65,7 +65,7 @@ pub fn is_const_evaluatable<'tcx>(
                 // FIXME(generic_const_exprs): we have a `ConstKind::Expr` which is fully concrete, but
                 // currently it is not possible to evaluate `ConstKind::Expr` so we are unable to tell if it
                 // is evaluatable or not. For now we just ICE until this is implemented.
-                Err(NotConstEvaluatable::Error(tcx.sess.span_delayed_bug(
+                Err(NotConstEvaluatable::Error(tcx.dcx().span_delayed_bug(
                     span,
                     "evaluating `ConstKind::Expr` is not currently supported",
                 )))
@@ -74,7 +74,7 @@ pub fn is_const_evaluatable<'tcx>(
                 let concrete = infcx.const_eval_resolve(param_env, uv, Some(span));
                 match concrete {
                     Err(ErrorHandled::TooGeneric(_)) => {
-                        Err(NotConstEvaluatable::Error(infcx.tcx.sess.span_delayed_bug(
+                        Err(NotConstEvaluatable::Error(infcx.dcx().span_delayed_bug(
                             span,
                             "Missing value for constant, but no error reported?",
                         )))
@@ -116,7 +116,7 @@ pub fn is_const_evaluatable<'tcx>(
                         param_env,
                     ) =>
             {
-                tcx.sess
+                tcx.dcx()
                     .struct_span_fatal(
                         // Slightly better span than just using `span` alone
                         if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def) } else { span },
@@ -138,7 +138,7 @@ pub fn is_const_evaluatable<'tcx>(
                 } else if uv.has_non_region_param() {
                     NotConstEvaluatable::MentionsParam
                 } else {
-                    let guar = infcx.tcx.sess.span_delayed_bug(
+                    let guar = infcx.dcx().span_delayed_bug(
                         span,
                         "Missing value for constant, but no error reported?",
                     );
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
index 676b40850b1ee..90e2c1531b469 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
@@ -141,7 +141,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
         let found_str = args_str(&found_args, &expected_args);
 
         let mut err = struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             span,
             E0593,
             "{} is expected to take {}, but it takes {}",
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index 61e97dde5f866..13ac2e26e4080 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -434,9 +434,9 @@ impl<'tcx> OnUnimplementedDirective {
         } else {
             let cond = item_iter
                 .next()
-                .ok_or_else(|| tcx.sess.emit_err(EmptyOnClauseInOnUnimplemented { span }))?
+                .ok_or_else(|| tcx.dcx().emit_err(EmptyOnClauseInOnUnimplemented { span }))?
                 .meta_item()
-                .ok_or_else(|| tcx.sess.emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
+                .ok_or_else(|| tcx.dcx().emit_err(InvalidOnClauseInOnUnimplemented { span }))?;
             attr::eval_condition(cond, &tcx.sess.parse_sess, Some(tcx.features()), &mut |cfg| {
                 if let Some(value) = cfg.value
                     && let Err(guar) = parse_value(value, cfg.span)
@@ -528,7 +528,7 @@ impl<'tcx> OnUnimplementedDirective {
                 );
             } else {
                 // nothing found
-                tcx.sess.emit_err(NoValueInOnUnimplemented { span: item.span() });
+                tcx.dcx().emit_err(NoValueInOnUnimplemented { span: item.span() });
             }
         }
 
@@ -689,7 +689,7 @@ impl<'tcx> OnUnimplementedDirective {
             Ok(None)
         } else {
             let reported = tcx
-                .sess
+                .dcx()
                 .span_delayed_bug(DUMMY_SP, "of_item: neither meta_item_list nor value_str");
             return Err(reported);
         };
@@ -829,7 +829,7 @@ impl<'tcx> OnUnimplementedFormatString {
                                     );
                                 } else {
                                     result = Err(struct_span_err!(
-                                        tcx.sess,
+                                        tcx.dcx(),
                                         self.span,
                                         E0230,
                                         "there is no parameter `{}` on {}",
@@ -848,7 +848,7 @@ impl<'tcx> OnUnimplementedFormatString {
                     // `{:1}` and `{}` are not to be used
                     Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
                         let reported = struct_span_err!(
-                            tcx.sess,
+                            tcx.dcx(),
                             self.span,
                             E0231,
                             "only named substitution parameters are allowed"
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index e84c5b7642119..e1f3c6d4f975a 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2001,7 +2001,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             _ => "function",
         };
         let mut err = struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             span,
             E0631,
             "type mismatch in {argument_kind} arguments",
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index a495f8399b9f1..4b84aae70fd10 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -228,7 +228,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
         }
 
-        self.tcx.sess.span_delayed_bug(DUMMY_SP, "expected fulfillment errors")
+        self.dcx().span_delayed_bug(DUMMY_SP, "expected fulfillment errors")
     }
 
     /// Reports that an overflow has occurred and halts compilation. We
@@ -251,7 +251,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         mutate(&mut err);
         err.emit();
 
-        self.tcx.sess.abort_if_errors();
+        self.dcx().abort_if_errors();
         // FIXME: this should be something like `build_overflow_error_fatal`, which returns
         // `DiagnosticBuilder<', !>`. Then we don't even need anything after that `emit()`.
         unreachable!(
@@ -281,7 +281,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             pred_str = cx.into_buffer();
         }
         let mut err = struct_span_err!(
-            self.tcx.sess,
+            self.dcx(),
             span,
             E0275,
             "overflow evaluating the requirement `{}`",
@@ -386,7 +386,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         let mut span = obligation.cause.span;
         // FIXME: statically guarantee this by tainting after the diagnostic is emitted
         self.set_tainted_by_errors(
-            tcx.sess.span_delayed_bug(span, "`report_selection_error` did not emit an error"),
+            tcx.dcx().span_delayed_bug(span, "`report_selection_error` did not emit an error"),
         );
 
         let mut err = match *error {
@@ -443,7 +443,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         // FIXME(effects)
                         let predicate_is_const = false;
 
-                        if self.tcx.sess.has_errors().is_some()
+                        if self.dcx().has_errors().is_some()
                             && trait_predicate.references_error()
                         {
                             return;
@@ -525,7 +525,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             (err_msg, None)
                         };
 
-                        let mut err = struct_span_err!(self.tcx.sess, span, E0277, "{}", err_msg);
+                        let mut err = struct_span_err!(self.dcx(), span, E0277, "{}", err_msg);
 
                         let mut suggested = false;
                         if is_try_conversion {
@@ -824,7 +824,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         if self.next_trait_solver() {
                             // FIXME: we'll need a better message which takes into account
                             // which bounds actually failed to hold.
-                            self.tcx.sess.struct_span_err(
+                            self.dcx().struct_span_err(
                                 span,
                                 format!("the type `{ty}` is not well-formed"),
                             )
@@ -873,7 +873,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     ),
 
                     ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ty)) => {
-                        let mut diag = self.tcx.sess.struct_span_err(
+                        let mut diag = self.dcx().struct_span_err(
                             span,
                             format!("the constant `{ct}` is not of type `{ty}`"),
                         );
@@ -1237,7 +1237,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
             ty::Float(_) => {
                 struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     span,
                     E0741,
                     "`{ty}` is forbidden as the type of a const generic parameter",
@@ -1245,7 +1245,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
             ty::FnPtr(_) => {
                 struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     span,
                     E0741,
                     "using function pointers as const generic parameters is forbidden",
@@ -1253,7 +1253,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
             ty::RawPtr(_) => {
                 struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     span,
                     E0741,
                     "using raw pointers as const generic parameters is forbidden",
@@ -1262,7 +1262,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             ty::Adt(def, _) => {
                 // We should probably see if we're *allowed* to derive `ConstParamTy` on the type...
                 let mut diag = struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     span,
                     E0741,
                     "`{ty}` must implement `ConstParamTy` to be used as the type of a const generic parameter",
@@ -1294,7 +1294,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
             _ => {
                 struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     span,
                     E0741,
                     "`{ty}` can't be used as a const parameter type",
@@ -1731,7 +1731,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         cx.into_buffer()
                     }))
                 });
-            let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
+            let mut diag = struct_span_err!(self.dcx(), obligation.cause.span, E0271, "{msg}");
 
             let secondary_span = (|| {
                 let ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)) =
@@ -2419,7 +2419,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     )
                 } else {
                     struct_span_err!(
-                        self.tcx.sess,
+                        self.dcx(),
                         span,
                         E0283,
                         "type annotations needed: cannot satisfy `{}`",
@@ -2522,7 +2522,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
                         // Replace the more general E0283 with a more specific error
                         err.cancel();
-                        err = self.tcx.sess.struct_span_err_with_code(
+                        err = self.dcx().struct_span_err_with_code(
                             span,
                             format!(
                                 "cannot {verb} associated {noun} on trait without specifying the \
@@ -2606,7 +2606,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 // Same hacky approach as above to avoid deluging user
                 // with error messages.
                 if arg.references_error()
-                    || self.tcx.sess.has_errors().is_some()
+                    || self.dcx().has_errors().is_some()
                     || self.tainted_by_errors().is_some()
                 {
                     return;
@@ -2623,7 +2623,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
             ty::PredicateKind::Subtype(data) => {
                 if data.references_error()
-                    || self.tcx.sess.has_errors().is_some()
+                    || self.dcx().has_errors().is_some()
                     || self.tainted_by_errors().is_some()
                 {
                     // no need to overload user in such cases
@@ -2663,7 +2663,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 } else {
                     // If we can't find a substitution, just print a generic error
                     let mut err = struct_span_err!(
-                        self.tcx.sess,
+                        self.dcx(),
                         span,
                         E0284,
                         "type annotations needed: cannot satisfy `{}`",
@@ -2691,7 +2691,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 } else {
                     // If we can't find a substitution, just print a generic error
                     let mut err = struct_span_err!(
-                        self.tcx.sess,
+                        self.dcx(),
                         span,
                         E0284,
                         "type annotations needed: cannot satisfy `{}`",
@@ -2702,11 +2702,11 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
             }
             _ => {
-                if self.tcx.sess.has_errors().is_some() || self.tainted_by_errors().is_some() {
+                if self.dcx().has_errors().is_some() || self.tainted_by_errors().is_some() {
                     return;
                 }
                 let mut err = struct_span_err!(
-                    self.tcx.sess,
+                    self.dcx(),
                     span,
                     E0284,
                     "type annotations needed: cannot satisfy `{}`",
@@ -3367,7 +3367,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
         }
 
-        self.tcx.sess.create_err(err)
+        self.dcx().create_err(err)
     }
 
     fn report_type_parameter_mismatch_cyclic_type_error(
@@ -3405,7 +3405,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 format!("`{}`", self.tcx.def_path_debug_str(def_id))
             }
         };
-        let mut err = self.tcx.sess.struct_span_err(
+        let mut err = self.dcx().struct_span_err(
             obligation.cause.span,
             format!("cannot check whether the hidden type of {name} satisfies auto traits"),
         );
@@ -3423,8 +3423,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
         };
 
-        if let Some(diag) =
-            self.tcx.sess.dcx().steal_diagnostic(self.tcx.def_span(def_id), StashKey::Cycle)
+        if let Some(diag) = self.dcx().steal_diagnostic(self.tcx.def_span(def_id), StashKey::Cycle)
         {
             diag.cancel();
         }
@@ -3547,8 +3546,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
     ) -> Option<DiagnosticBuilder<'tcx>> {
         if !self.tcx.features().generic_const_exprs {
             let mut err = self
-                .tcx
-                .sess
+                .dcx()
                 .struct_span_err(span, "constant expression depends on a generic parameter");
             // FIXME(const_generics): we should suggest to the user how they can resolve this
             // issue. However, this is currently not actually possible
@@ -3565,7 +3563,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(ct)) => match ct.kind() {
                 ty::ConstKind::Unevaluated(uv) => {
                     let mut err =
-                        self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
+                        self.dcx().struct_span_err(span, "unconstrained generic constant");
                     let const_span = self.tcx.def_span(uv.def);
                     match self.tcx.sess.source_map().span_to_snippet(const_span) {
                             Ok(snippet) => err.help(format!(
@@ -3577,8 +3575,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
                 ty::ConstKind::Expr(_) => {
                     let err = self
-                        .tcx
-                        .sess
+                        .dcx()
                         .struct_span_err(span, format!("unconstrained generic constant `{ct}`"));
                     Some(err)
                 }
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index cf4fa233768ac..073174127d6a1 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -173,7 +173,7 @@ pub fn all_fields_implement_trait<'tcx>(
             // between expected and found const-generic types. Don't report an
             // additional copy error here, since it's not typically useful.
             if !normalization_errors.is_empty() || ty.references_error() {
-                tcx.sess.span_delayed_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id)));
+                tcx.dcx().span_delayed_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id)));
                 continue;
             }
 
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 8c5f1e9071545..c52b8f37ef3b7 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -215,7 +215,7 @@ fn do_normalize_predicates<'tcx>(
     // the normalized predicates.
     let errors = infcx.resolve_regions(&outlives_env);
     if !errors.is_empty() {
-        tcx.sess.span_delayed_bug(
+        tcx.dcx().span_delayed_bug(
             span,
             format!("failed region resolution while normalizing {elaborated_env:?}: {errors:?}"),
         );
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 7ac37315fe0d7..6e68dee76a24c 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -508,7 +508,7 @@ fn virtual_call_violations_for_method<'tcx>(
                     Ok(layout) => Some(layout.abi),
                     Err(err) => {
                         // #78372
-                        tcx.sess.span_delayed_bug(
+                        tcx.dcx().span_delayed_bug(
                             tcx.def_span(method.def_id),
                             format!("error: {err}\n while computing layout for type {ty:?}"),
                         );
@@ -524,7 +524,7 @@ fn virtual_call_violations_for_method<'tcx>(
             match abi_of_ty(unit_receiver_ty) {
                 Some(Abi::Scalar(..)) => (),
                 abi => {
-                    tcx.sess.span_delayed_bug(
+                    tcx.dcx().span_delayed_bug(
                         tcx.def_span(method.def_id),
                         format!(
                             "receiver when `Self = ()` should have a Scalar ABI; found {abi:?}"
@@ -542,7 +542,7 @@ fn virtual_call_violations_for_method<'tcx>(
             match abi_of_ty(trait_object_receiver) {
                 Some(Abi::ScalarPair(..)) => (),
                 abi => {
-                    tcx.sess.span_delayed_bug(
+                    tcx.dcx().span_delayed_bug(
                         tcx.def_span(method.def_id),
                         format!(
                             "receiver when `Self = {trait_object_ty}` should have a ScalarPair ABI; found {abi:?}"
@@ -594,7 +594,7 @@ fn virtual_call_violations_for_method<'tcx>(
             // would already have reported an error at the definition of the
             // auto trait.
             if pred_trait_ref.args.len() != 1 {
-                tcx.sess.dcx().span_delayed_bug(span, "auto traits cannot have generic parameters");
+                tcx.dcx().span_delayed_bug(span, "auto traits cannot have generic parameters");
             }
             return false;
         }
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 7513f88cfc3cf..9749ff9cbc11a 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -111,7 +111,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
 
             let errors = ocx.select_all_or_error();
             if !errors.is_empty() {
-                self.tcx.sess.span_delayed_bug(
+                self.dcx().span_delayed_bug(
                     span,
                     "implied_outlives_bounds failed to solve obligations from instantiation",
                 );
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index a1b0ada0e8a8c..d32b4adbefcdd 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -1369,7 +1369,7 @@ pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
 
     if !tcx.recursion_limit().value_within_limit(depth) {
         // Halt compilation because it is important that overflows never be masked.
-        tcx.sess.emit_fatal(InherentProjectionNormalizationOverflow {
+        tcx.dcx().emit_fatal(InherentProjectionNormalizationOverflow {
             span: cause.span,
             ty: alias_ty.to_string(),
         });
@@ -1471,7 +1471,7 @@ pub fn compute_inherent_assoc_ty_args<'a, 'b, 'tcx>(
     match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) {
         Ok(mut ok) => obligations.append(&mut ok.obligations),
         Err(_) => {
-            tcx.sess.span_delayed_bug(
+            tcx.dcx().span_delayed_bug(
                 cause.span,
                 format!(
                     "{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not"
@@ -1983,7 +1983,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
             ImplSource::Builtin(BuiltinImplSource::TraitUpcasting { .. }, _)
             | ImplSource::Builtin(BuiltinImplSource::TupleUnsizing, _) => {
                 // These traits have no associated types.
-                selcx.tcx().sess.span_delayed_bug(
+                selcx.tcx().dcx().span_delayed_bug(
                     obligation.cause.span,
                     format!("Cannot project an associated type from `{impl_source:?}`"),
                 );
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index ec80df1d658a8..f9c8f3d14c3c1 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -237,7 +237,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
                 // By the time this code runs, all type variables ought to
                 // be fully resolved.
 
-                tcx.sess.span_delayed_bug(
+                tcx.dcx().span_delayed_bug(
                     span,
                     format!("upvar_tys for closure not found. Expected capture information for closure {ty}",),
                 );
@@ -286,7 +286,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
             if !args.is_valid() {
                 // By the time this code runs, all type variables ought to
                 // be fully resolved.
-                tcx.sess.span_delayed_bug(
+                tcx.dcx().span_delayed_bug(
                     span,
                     format!("upvar_tys for coroutine not found. Expected capture information for coroutine {ty}",),
                 );
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index ed55533bc551a..e8867187a408a 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -292,7 +292,7 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
                     // Rustdoc normalizes possibly not well-formed types, so only
                     // treat this as a bug if we're not in rustdoc.
                     if !tcx.sess.opts.actually_rustdoc {
-                        tcx.sess.span_delayed_bug(
+                        tcx.dcx().span_delayed_bug(
                             DUMMY_SP,
                             format!("unexpected ambiguity: {c_data:?} {result:?}"),
                         );
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 18bb56ba4ebad..f4baae2711fb0 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -82,13 +82,13 @@ where
     let value = infcx.commit_if_ok(|_| {
         let ocx = ObligationCtxt::new(infcx);
         let value = op(&ocx).map_err(|_| {
-            infcx.tcx.sess.span_delayed_bug(span, format!("error performing operation: {name}"))
+            infcx.dcx().span_delayed_bug(span, format!("error performing operation: {name}"))
         })?;
         let errors = ocx.select_all_or_error();
         if errors.is_empty() {
             Ok(value)
         } else {
-            Err(infcx.tcx.sess.span_delayed_bug(
+            Err(infcx.dcx().span_delayed_bug(
                 DUMMY_SP,
                 format!("errors selecting obligation during MIR typeck: {errors:?}"),
             ))
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index 272f1a54f819b..cab2a62ed7e66 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -159,7 +159,7 @@ where
         let mut region_constraints = QueryRegionConstraints::default();
         let (output, error_info, mut obligations, _) =
             Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| {
-                infcx.tcx.sess.span_delayed_bug(span, format!("error performing {self:?}"))
+                infcx.dcx().span_delayed_bug(span, format!("error performing {self:?}"))
             })?;
 
         // Typically, instantiating NLL query results does not
@@ -188,7 +188,7 @@ where
                 }
             }
             if !progress {
-                return Err(infcx.tcx.sess.span_delayed_bug(
+                return Err(infcx.dcx().span_delayed_bug(
                     span,
                     format!("ambiguity processing {obligations:?} from {self:?}"),
                 ));
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 73e06b8408562..3a37bc518ef5f 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -964,7 +964,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                     |impl_def_id| {
                         if let Some(old_impl_def_id) = relevant_impl {
                             self.tcx()
-                                .sess
+                                .dcx()
                                 .struct_span_err(
                                     self.tcx().def_span(impl_def_id),
                                     "multiple drop impls found",
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index ce3fc2185ba24..f1da1c046d45a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -558,7 +558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             let defs: &ty::Generics = tcx.generics_of(assoc_type);
 
             if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended {
-                tcx.sess.span_delayed_bug(
+                tcx.dcx().span_delayed_bug(
                     obligation.cause.span,
                     "GATs in trait object shouldn't have been considered",
                 );
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 23f7bdd15841e..336c0c5299fc9 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -2426,7 +2426,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 // the placeholder trait ref may fail due the Generalizer relation
                 // raising a CyclicalTy error due to a sub_root_var relation
                 // for a variable being generalized...
-                let guar = self.infcx.tcx.sess.span_delayed_bug(
+                let guar = self.infcx.dcx().span_delayed_bug(
                     obligation.cause.span,
                     format!(
                         "Impl {impl_def_id:?} was matchable against {obligation:?} but now is not"
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 71a88f5f07cb6..d43ab0c8e85a7 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -202,7 +202,7 @@ fn fulfill_implication<'tcx>(
         {
             Ok(source_trait_ref) => source_trait_ref,
             Err(_errors) => {
-                infcx.tcx.sess.span_delayed_bug(
+                infcx.dcx().span_delayed_bug(
                     infcx.tcx.def_span(source_impl),
                     format!("failed to fully normalize {source_trait_ref}"),
                 );
@@ -345,7 +345,7 @@ fn report_negative_positive_conflict<'tcx>(
     positive_impl_def_id: DefId,
     sg: &mut specialization_graph::Graph,
 ) {
-    let mut err = tcx.sess.create_err(NegativePositiveConflict {
+    let mut err = tcx.dcx().create_err(NegativePositiveConflict {
         impl_span: tcx.def_span(local_impl_def_id),
         trait_desc: overlap.trait_ref,
         self_ty: overlap.self_ty,
@@ -426,13 +426,13 @@ fn report_conflicting_impls<'tcx>(
             let reported = if overlap.with_impl.is_local()
                 || tcx.orphan_check_impl(impl_def_id).is_ok()
             {
-                let mut err = tcx.sess.struct_span_err(impl_span, msg);
+                let mut err = tcx.dcx().struct_span_err(impl_span, msg);
                 err.code(error_code!(E0119));
                 decorate(tcx, &overlap, impl_span, &mut err);
                 Some(err.emit())
             } else {
                 Some(
-                    tcx.sess
+                    tcx.dcx()
                         .span_delayed_bug(impl_span, "impl should have failed the orphan check"),
                 )
             };
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index f8e47caccb7c3..868a8a3e8b85f 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -135,7 +135,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for Search<'tcx> {
                 bug!("unexpected type during structural-match checking: {:?}", ty);
             }
             ty::Error(_) => {
-                self.tcx.sess.span_delayed_bug(self.span, "ty::Error in structural-match check");
+                self.tcx.dcx().span_delayed_bug(self.span, "ty::Error in structural-match check");
                 // We still want to check other types after encountering an error,
                 // as this may still emit relevant errors.
                 return ControlFlow::Continue(());
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index f23c100a686c6..d39583b5c7d88 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -195,7 +195,7 @@ fn dump_vtable_entries<'tcx>(
     trait_ref: ty::PolyTraitRef<'tcx>,
     entries: &[VtblEntry<'tcx>],
 ) {
-    tcx.sess.emit_err(DumpVTableEntries { span: sp, trait_ref, entries: format!("{entries:#?}") });
+    tcx.dcx().emit_err(DumpVTableEntries { span: sp, trait_ref, entries: format!("{entries:#?}") });
 }
 
 fn has_own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> bool {
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index b521a5c1145f6..c9f99012b290c 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -276,7 +276,7 @@ fn error(
     sub: GenericConstantTooComplexSub,
     root_span: Span,
 ) -> Result<!, ErrorGuaranteed> {
-    let reported = tcx.sess.emit_err(GenericConstantTooComplex {
+    let reported = tcx.dcx().emit_err(GenericConstantTooComplex {
         span: root_span,
         maybe_supported: None,
         sub,
@@ -290,7 +290,7 @@ fn maybe_supported_error(
     sub: GenericConstantTooComplexSub,
     root_span: Span,
 ) -> Result<!, ErrorGuaranteed> {
-    let reported = tcx.sess.emit_err(GenericConstantTooComplex {
+    let reported = tcx.dcx().emit_err(GenericConstantTooComplex {
         span: root_span,
         maybe_supported: Some(()),
         sub,
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index f1c9bb23e5d6e..42db43caf9f6a 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -79,7 +79,7 @@ fn resolve_associated_item<'tcx>(
     let vtbl = match tcx.codegen_select_candidate((param_env, trait_ref)) {
         Ok(vtbl) => vtbl,
         Err(CodegenObligationError::Ambiguity) => {
-            let reported = tcx.sess.span_delayed_bug(
+            let reported = tcx.dcx().span_delayed_bug(
                 tcx.def_span(trait_item_id),
                 format!(
                     "encountered ambiguity selecting `{trait_ref:?}` during codegen, presuming due to \
@@ -171,7 +171,7 @@ 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.sess.span_delayed_bug(
+                let guard = tcx.dcx().span_delayed_bug(
                     tcx.def_span(leaf_def.item.def_id),
                     "missing value for assoc item in impl",
                 );
@@ -241,7 +241,7 @@ fn resolve_associated_item<'tcx>(
                         args: rcvr_args,
                     })
                 } else {
-                    tcx.sess.emit_fatal(UnexpectedFnPtrAssociatedItem {
+                    tcx.dcx().emit_fatal(UnexpectedFnPtrAssociatedItem {
                         span: tcx.def_span(trait_item_id),
                     })
                 }
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 7918965e04baa..d39377a1acb8d 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -91,7 +91,7 @@ fn univariant_uninterned<'tcx>(
     let dl = cx.data_layout();
     let pack = repr.pack;
     if pack.is_some() && repr.align.is_some() {
-        cx.tcx.sess.span_delayed_bug(DUMMY_SP, "struct cannot be packed and aligned");
+        cx.tcx.dcx().span_delayed_bug(DUMMY_SP, "struct cannot be packed and aligned");
         return Err(cx.tcx.arena.alloc(LayoutError::Unknown(ty)));
     }
 
@@ -344,7 +344,7 @@ fn layout_of_uncached<'tcx>(
         ty::Adt(def, args) if def.repr().simd() => {
             if !def.is_struct() {
                 // Should have yielded E0517 by now.
-                tcx.sess.span_delayed_bug(
+                tcx.dcx().span_delayed_bug(
                     DUMMY_SP,
                     "#[repr(simd)] was applied to an ADT that is not a struct",
                 );
@@ -364,7 +364,7 @@ fn layout_of_uncached<'tcx>(
             // SIMD vectors with zero fields are not supported.
             // (should be caught by typeck)
             if fields.is_empty() {
-                tcx.sess.emit_fatal(ZeroLengthSimdType { ty })
+                tcx.dcx().emit_fatal(ZeroLengthSimdType { ty })
             }
 
             // Type of the first ADT field:
@@ -374,7 +374,7 @@ fn layout_of_uncached<'tcx>(
             // (should be caught by typeck)
             for fi in fields {
                 if fi.ty(tcx, args) != f0_ty {
-                    tcx.sess.span_delayed_bug(
+                    tcx.dcx().span_delayed_bug(
                         DUMMY_SP,
                         "#[repr(simd)] was applied to an ADT with heterogeneous field type",
                     );
@@ -395,7 +395,7 @@ fn layout_of_uncached<'tcx>(
                 // SIMD vectors with multiple array fields are not supported:
                 // Can't be caught by typeck with a generic simd type.
                 if def.non_enum_variant().fields.len() != 1 {
-                    tcx.sess.emit_fatal(MultipleArrayFieldsSimdType { ty });
+                    tcx.dcx().emit_fatal(MultipleArrayFieldsSimdType { ty });
                 }
 
                 // Extract the number of elements from the layout of the array field:
@@ -415,9 +415,9 @@ fn layout_of_uncached<'tcx>(
             //
             // Can't be caught in typeck if the array length is generic.
             if e_len == 0 {
-                tcx.sess.emit_fatal(ZeroLengthSimdType { ty });
+                tcx.dcx().emit_fatal(ZeroLengthSimdType { ty });
             } else if e_len > MAX_SIMD_LANES {
-                tcx.sess.emit_fatal(OversizedSimdType { ty, max_lanes: MAX_SIMD_LANES });
+                tcx.dcx().emit_fatal(OversizedSimdType { ty, max_lanes: MAX_SIMD_LANES });
             }
 
             // Compute the ABI of the element type:
@@ -425,7 +425,7 @@ fn layout_of_uncached<'tcx>(
             let Abi::Scalar(e_abi) = e_ly.abi else {
                 // This error isn't caught in typeck, e.g., if
                 // the element type of the vector is generic.
-                tcx.sess.emit_fatal(NonPrimitiveSimdType { ty, e_ty });
+                tcx.dcx().emit_fatal(NonPrimitiveSimdType { ty, e_ty });
             };
 
             // Compute the size and alignment of the vector:
@@ -485,7 +485,7 @@ fn layout_of_uncached<'tcx>(
 
             if def.is_union() {
                 if def.repr().pack.is_some() && def.repr().align.is_some() {
-                    cx.tcx.sess.span_delayed_bug(
+                    cx.tcx.dcx().span_delayed_bug(
                         tcx.def_span(def.did()),
                         "union cannot be packed and aligned",
                     );
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index 67ccfe7e78abb..8d118e6dfeff8 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -116,7 +116,7 @@ where
             if !self.recursion_limit.value_within_limit(level) {
                 // Not having a `Span` isn't great. But there's hopefully some other
                 // recursion limit error as well.
-                tcx.sess.emit_err(NeedsDropOverflow { query_ty: self.query_ty });
+                tcx.dcx().emit_err(NeedsDropOverflow { query_ty: self.query_ty });
                 return Some(Err(AlwaysRequiresDrop));
             }
 
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index db43c31ccab1c..0bb833c66fa76 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -181,14 +181,14 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
                         }
                     }
                     Err(NotUniqueParam::NotParam(arg)) => {
-                        self.tcx.sess.emit_err(NotParam {
+                        self.tcx.dcx().emit_err(NotParam {
                             arg,
                             span: self.span(),
                             opaque_span: self.tcx.def_span(alias_ty.def_id),
                         });
                     }
                     Err(NotUniqueParam::DuplicateParam(arg)) => {
-                        self.tcx.sess.emit_err(DuplicateArg {
+                        self.tcx.dcx().emit_err(DuplicateArg {
                             arg,
                             span: self.span(),
                             opaque_span: self.tcx.def_span(alias_ty.def_id),
@@ -238,7 +238,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
                                     .instantiate(self.tcx, impl_args)
                                     .visit_with(self);
                             } else {
-                                self.tcx.sess.span_delayed_bug(
+                                self.tcx.dcx().span_delayed_bug(
                                     self.tcx.def_span(assoc.def_id),
                                     "item had incorrect args",
                                 );
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 75f9560f52682..1a25d3f799363 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2996,7 +2996,7 @@ fn clean_use_statement_inner<'tcx>(
 
     if pub_underscore && let Some(ref inline) = inline_attr {
         rustc_errors::struct_span_err!(
-            cx.tcx.sess,
+            cx.tcx.dcx(),
             inline.span(),
             E0780,
             "anonymous imports cannot be inlined"
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 150625c6d920f..179f37e6d96a4 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -1012,7 +1012,7 @@ pub(crate) trait AttributesExt {
                             match Cfg::parse(cfg_mi) {
                                 Ok(new_cfg) => cfg &= new_cfg,
                                 Err(e) => {
-                                    sess.span_err(e.span, e.msg);
+                                    sess.dcx().span_err(e.span, e.msg);
                                 }
                             }
                         }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 4e904ffd768a5..102a9f40e9b32 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -326,7 +326,7 @@ pub(crate) fn run_global_ctxt(
         tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
     });
 
-    tcx.sess.abort_if_errors();
+    tcx.dcx().abort_if_errors();
     tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx));
     tcx.sess.time("check_mod_attrs", || {
         tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module))
@@ -447,7 +447,7 @@ pub(crate) fn run_global_ctxt(
 
     tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc)));
 
-    if tcx.sess.dcx().has_errors_or_lint_errors().is_some() {
+    if tcx.dcx().has_errors_or_lint_errors().is_some() {
         rustc_errors::FatalError.raise();
     }
 
@@ -494,7 +494,7 @@ impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
                     .collect::<String>()
             );
             let mut err = rustc_errors::struct_span_err!(
-                self.tcx.sess,
+                self.tcx.dcx(),
                 path.span,
                 E0433,
                 "failed to resolve: {label}",
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index f0199703c4e16..aad63f8578ad5 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -758,7 +758,7 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
         // Flush pending errors.
         Rc::get_mut(&mut self.shared).unwrap().fs.close();
         let nb_errors =
-            self.shared.errors.iter().map(|err| self.tcx().sess.struct_err(err).emit()).count();
+            self.shared.errors.iter().map(|err| self.tcx().dcx().struct_err(err).emit()).count();
         if nb_errors > 0 {
             Err(Error::new(io::Error::new(io::ErrorKind::Other, "I/O error"), ""))
         } else {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 34350c2ed3ab6..118c6eeb289bb 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -2362,7 +2362,7 @@ fn render_call_locations<W: fmt::Write>(mut w: W, cx: &mut Context<'_>, item: &c
             Ok(contents) => contents,
             Err(err) => {
                 let span = item.span(tcx).map_or(rustc_span::DUMMY_SP, |span| span.inner());
-                tcx.sess.span_err(span, format!("failed to read file {}: {err}", path.display()));
+                tcx.dcx().span_err(span, format!("failed to read file {}: {err}", path.display()));
                 return false;
             }
         };
diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs
index e160ec12f52bb..d4b1da71b40a0 100644
--- a/src/librustdoc/html/sources.rs
+++ b/src/librustdoc/html/sources.rs
@@ -146,7 +146,7 @@ impl DocVisitor for SourceCollector<'_, '_> {
             self.cx.include_sources = match self.emit_source(&filename, file_span) {
                 Ok(()) => true,
                 Err(e) => {
-                    self.cx.shared.tcx.sess.span_err(
+                    self.cx.shared.tcx.dcx().span_err(
                         span,
                         format!(
                             "failed to render source code for `{filename}`: {e}",
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 19db429ad8af6..ad1838c53ad19 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -690,10 +690,10 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
     tcx: TyCtxt<'tcx>,
 ) -> MainResult {
     match formats::run_format::<T>(krate, renderopts, cache, tcx) {
-        Ok(_) => tcx.sess.has_errors().map_or(Ok(()), Err),
+        Ok(_) => tcx.dcx().has_errors().map_or(Ok(()), Err),
         Err(e) => {
             let mut msg =
-                tcx.sess.struct_err(format!("couldn't generate documentation: {}", e.error));
+                tcx.dcx().struct_err(format!("couldn't generate documentation: {}", e.error));
             let file = e.file.display().to_string();
             if !file.is_empty() {
                 msg.note(format!("failed to create or modify \"{file}\""));
@@ -800,7 +800,7 @@ fn main_args(
         compiler.enter(|queries| {
             let mut gcx = abort_on_err(queries.global_ctxt(), sess);
             if sess.dcx().has_errors_or_lint_errors().is_some() {
-                sess.fatal("Compilation failed, aborting rustdoc");
+                sess.dcx().fatal("Compilation failed, aborting rustdoc");
             }
 
             gcx.enter(|tcx| {
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index df2e8584b840c..fc7ef4bcdfa97 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -22,7 +22,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
     let tcx = cx.tcx;
     // We need to check if there are errors before running this pass because it would crash when
     // we try to get auto and blanket implementations.
-    if tcx.sess.dcx().has_errors_or_lint_errors().is_some() {
+    if tcx.dcx().has_errors_or_lint_errors().is_some() {
         return krate;
     }
 
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index a343d7afcee21..74bec5a2e11fd 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -311,7 +311,7 @@ pub(crate) fn run(
 
         // The visitor might have found a type error, which we need to
         // promote to a fatal error
-        if tcx.sess.dcx().has_errors_or_lint_errors().is_some() {
+        if tcx.dcx().has_errors_or_lint_errors().is_some() {
             return Err(String::from("Compilation failed, aborting rustdoc"));
         }
 
@@ -331,7 +331,7 @@ pub(crate) fn run(
     };
 
     if let Err(e) = inner() {
-        tcx.sess.fatal(e);
+        tcx.dcx().fatal(e);
     }
 
     Ok(())
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 88611eb70878e..3cf4377002a86 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -636,11 +636,11 @@ impl Conf {
         match path {
             Ok((_, warnings)) => {
                 for warning in warnings {
-                    sess.warn(warning.clone());
+                    sess.dcx().warn(warning.clone());
                 }
             },
             Err(error) => {
-                sess.err(format!("error finding Clippy's configuration file: {error}"));
+                sess.dcx().err(format!("error finding Clippy's configuration file: {error}"));
             },
         }
 
@@ -652,7 +652,7 @@ impl Conf {
             Ok((Some(path), _)) => match sess.source_map().load_file(path) {
                 Ok(file) => deserialize(&file),
                 Err(error) => {
-                    sess.err(format!("failed to read `{}`: {error}", path.display()));
+                    sess.dcx().err(format!("failed to read `{}`: {error}", path.display()));
                     TryConf::default()
                 },
             },
@@ -663,14 +663,14 @@ impl Conf {
 
         // all conf errors are non-fatal, we just use the default conf in case of error
         for error in errors {
-            sess.span_err(
+            sess.dcx().span_err(
                 error.span,
                 format!("error reading Clippy's configuration file: {}", error.message),
             );
         }
 
         for warning in warnings {
-            sess.span_warn(
+            sess.dcx().span_warn(
                 warning.span,
                 format!("error reading Clippy's configuration file: {}", warning.message),
             );
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index b3ef666e3063c..13e61e5a0326c 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -83,7 +83,7 @@ impl Msrv {
             (None, Some(cargo_msrv)) => self.stack = vec![cargo_msrv],
             (Some(clippy_msrv), Some(cargo_msrv)) => {
                 if clippy_msrv != cargo_msrv {
-                    sess.warn(format!(
+                    sess.dcx().warn(format!(
                         "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
                     ));
                 }
@@ -106,7 +106,7 @@ impl Msrv {
 
         if let Some(msrv_attr) = msrv_attrs.next() {
             if let Some(duplicate) = msrv_attrs.last() {
-                sess.struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times")
+                sess.dcx().struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times")
                     .span_note(msrv_attr.span, "first definition found here")
                     .emit();
             }
@@ -116,9 +116,9 @@ impl Msrv {
                     return Some(version);
                 }
 
-                sess.span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version"));
+                sess.dcx().span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version"));
             } else {
-                sess.span_err(msrv_attr.span, "bad clippy attribute");
+                sess.dcx().span_err(msrv_attr.span, "bad clippy attribute");
             }
         }
 
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index acaa6be30092b..9ba19e0a86581 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -153,7 +153,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn {
 
         if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, &self.msrv) {
             if cx.tcx.is_const_fn_raw(def_id.to_def_id()) {
-                cx.tcx.sess.span_err(span, err);
+                cx.tcx.dcx().span_err(span, err);
             }
         } else {
             span_lint(cx, MISSING_CONST_FOR_FN, span, "this could be a `const fn`");
diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs
index 51771f78d4ff3..46c96fad884f5 100644
--- a/src/tools/clippy/clippy_utils/src/attrs.rs
+++ b/src/tools/clippy/clippy_utils/src/attrs.rs
@@ -76,12 +76,12 @@ pub fn get_attr<'a>(
                 })
                 .map_or_else(
                     || {
-                        sess.span_err(attr_segments[1].ident.span, "usage of unknown attribute");
+                        sess.dcx().span_err(attr_segments[1].ident.span, "usage of unknown attribute");
                         false
                     },
                     |deprecation_status| {
                         let mut diag =
-                            sess.struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute");
+                            sess.dcx().struct_span_err(attr_segments[1].ident.span, "usage of deprecated attribute");
                         match *deprecation_status {
                             DeprecationStatus::Deprecated => {
                                 diag.emit();
@@ -116,10 +116,10 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &'
             if let Ok(value) = FromStr::from_str(value.as_str()) {
                 f(value);
             } else {
-                sess.span_err(attr.span, "not a number");
+                sess.dcx().span_err(attr.span, "not a number");
             }
         } else {
-            sess.span_err(attr.span, "bad clippy attribute");
+            sess.dcx().span_err(attr.span, "bad clippy attribute");
         }
     }
 }
@@ -132,7 +132,7 @@ pub fn get_unique_attr<'a>(
     let mut unique_attr: Option<&ast::Attribute> = None;
     for attr in get_attr(sess, attrs, name) {
         if let Some(duplicate) = unique_attr {
-            sess.struct_span_err(attr.span, format!("`{name}` is defined multiple times"))
+            sess.dcx().struct_span_err(attr.span, format!("`{name}` is defined multiple times"))
                 .span_note(duplicate.span, "first definition found here")
                 .emit();
         } else {
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index f83847d13f1b3..ad6a5a669f006 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -66,19 +66,19 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
     ) -> Compilation {
         queries.global_ctxt().unwrap().enter(|tcx| {
             if tcx.sess.compile_status().is_err() {
-                tcx.sess.fatal("miri cannot be run on programs that fail compilation");
+                tcx.dcx().fatal("miri cannot be run on programs that fail compilation");
             }
 
             let early_dcx = EarlyDiagCtxt::new(tcx.sess.opts.error_format);
             init_late_loggers(&early_dcx, tcx);
             if !tcx.crate_types().contains(&CrateType::Executable) {
-                tcx.sess.fatal("miri only makes sense on bin crates");
+                tcx.dcx().fatal("miri only makes sense on bin crates");
             }
 
             let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) {
                 entry_def
             } else {
-                tcx.sess.fatal("miri can only run programs that have a main function");
+                tcx.dcx().fatal("miri can only run programs that have a main function");
             };
             let mut config = self.miri_config.clone();
 
@@ -91,13 +91,13 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
             }
 
             if tcx.sess.opts.optimize != OptLevel::No {
-                tcx.sess.warn("Miri does not support optimizations. If you have enabled optimizations \
+                tcx.dcx().warn("Miri does not support optimizations. If you have enabled optimizations \
                     by selecting a Cargo profile (such as --release) which changes other profile settings \
                     such as whether debug assertions and overflow checks are enabled, those settings are \
                     still applied.");
             }
             if tcx.sess.mir_opt_level() > 0 {
-                tcx.sess.warn("You have explicitly enabled MIR optimizations, overriding Miri's default \
+                tcx.dcx().warn("You have explicitly enabled MIR optimizations, overriding Miri's default \
                     which is to completely disable them. Any optimizations may hide UB that Miri would \
                     otherwise detect, and it is not necessarily possible to predict what kind of UB will \
                     be missed. If you are enabling optimizations to make Miri run faster, we advise using \
@@ -110,7 +110,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
                     i32::try_from(return_code).expect("Return value was too large!"),
                 );
             }
-            tcx.sess.abort_if_errors();
+            tcx.dcx().abort_if_errors();
         });
 
         Compilation::Stop
diff --git a/src/tools/miri/src/borrow_tracker/mod.rs b/src/tools/miri/src/borrow_tracker/mod.rs
index a6961208ffb02..74ff6ed4e0abe 100644
--- a/src/tools/miri/src/borrow_tracker/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/mod.rs
@@ -343,7 +343,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
         let method = this.machine.borrow_tracker.as_ref().unwrap().borrow().borrow_tracker_method;
         match method {
             BorrowTrackerMethod::StackedBorrows => {
-                this.tcx.tcx.sess.warn("Stacked Borrows does not support named pointers; `miri_pointer_name` is a no-op");
+                this.tcx.tcx.dcx().warn("Stacked Borrows does not support named pointers; `miri_pointer_name` is a no-op");
                 Ok(())
             }
             BorrowTrackerMethod::TreeBorrows =>
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 4c284ff81ee81..4375fa67b807b 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -384,7 +384,7 @@ pub fn report_error<'tcx, 'mir>(
 
     // Include a note like `std` does when we omit frames from a backtrace
     if was_pruned {
-        ecx.tcx.sess.dcx().note(
+        ecx.tcx.dcx().note(
             "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
         );
     }
@@ -431,7 +431,7 @@ pub fn report_leaks<'mir, 'tcx>(
         );
     }
     if any_pruned {
-        ecx.tcx.sess.dcx().note(
+        ecx.tcx.dcx().note(
             "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
         );
     }
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 6013c0bd341f3..6095b8842eb60 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -278,7 +278,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
     // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore.
     let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"], Namespace::ValueNS);
     if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) {
-        tcx.sess.fatal(
+        tcx.dcx().fatal(
             "the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \
             Use `cargo miri setup` to prepare a sysroot that is suitable for Miri."
         );
@@ -363,7 +363,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
     match entry_type {
         EntryFnType::Main { .. } => {
             let start_id = tcx.lang_items().start_fn().unwrap_or_else(|| {
-                tcx.sess.fatal(
+                tcx.dcx().fatal(
                     "could not find start function. Make sure the entry point is marked with `#[start]`."
                 );
             });
@@ -462,8 +462,8 @@ pub fn eval_entry<'tcx>(
     if leak_check && !ignore_leaks {
         // Check for thread leaks.
         if !ecx.have_all_terminated() {
-            tcx.sess.err("the main thread terminated without waiting for all remaining threads");
-            tcx.sess.note("pass `-Zmiri-ignore-leaks` to disable this check");
+            tcx.dcx().err("the main thread terminated without waiting for all remaining threads");
+            tcx.dcx().note("pass `-Zmiri-ignore-leaks` to disable this check");
             return None;
         }
         // Check for memory leaks.
@@ -474,10 +474,10 @@ pub fn eval_entry<'tcx>(
             let leak_message = "the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check";
             if ecx.machine.collect_leak_backtraces {
                 // If we are collecting leak backtraces, each leak is a distinct error diagnostic.
-                tcx.sess.note(leak_message);
+                tcx.dcx().note(leak_message);
             } else {
                 // If we do not have backtraces, we just report an error without any span.
-                tcx.sess.err(leak_message);
+                tcx.dcx().err(leak_message);
             };
             // Ignore the provided return code - let the reported error
             // determine the return code.
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 57dc3b4734c46..d2fd51b099ad7 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -539,7 +539,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
             RejectOpWith::Abort => isolation_abort_error(op_name),
             RejectOpWith::WarningWithoutBacktrace => {
                 this.tcx
-                    .sess
+                    .dcx()
                     .warn(format!("{op_name} was made to return an error due to isolation"));
                 Ok(())
             }
diff --git a/tests/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs b/tests/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
index 086ca0bdf37d3..9e0a7ba63d05f 100644
--- a/tests/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
+++ b/tests/run-make-fulldeps/hotplug_codegen_backend/the_backend.rs
@@ -67,7 +67,7 @@ impl CodegenBackend for TheBackend {
         let crate_name = codegen_results.crate_info.local_crate_name;
         for &crate_type in sess.opts.crate_types.iter() {
             if crate_type != CrateType::Rlib {
-                sess.fatal(format!("Crate type is {:?}", crate_type));
+                sess.dcx().fatal(format!("Crate type is {:?}", crate_type));
             }
             let output_name = out_filename(sess, crate_type, &outputs, crate_name);
             match output_name {
diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
index 9cbe9e5900abd..2e3bf70e14414 100644
--- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs
+++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs
@@ -61,7 +61,7 @@ impl rustc_driver::Callbacks for CompilerCalls {
         compiler: &Compiler,
         queries: &'tcx Queries<'tcx>,
     ) -> Compilation {
-        compiler.sess.abort_if_errors();
+        compiler.sess.dcx().abort_if_errors();
         queries.global_ctxt().unwrap().enter(|tcx| {
             // Collect definition ids of MIR bodies.
             let hir = tcx.hir();