about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-12-18 06:03:53 +0000
committerbors <bors@rust-lang.org>2023-12-18 06:03:53 +0000
commitcda4736f1eaad8af6f49388baa9b7e480df8e329 (patch)
tree42a50495ab069a1198ed0b43bb5c417ec42ff02d
parent8681e077b8afa99d60acf8f8470a012a3ce709a5 (diff)
parent1e831e38ce8ba6fc93338247a7963b3a6b33e542 (diff)
downloadrust-cda4736f1eaad8af6f49388baa9b7e480df8e329.tar.gz
rust-cda4736f1eaad8af6f49388baa9b7e480df8e329.zip
Auto merge of #119063 - nnethercote:dcx, r=compiler-errors
Consistent `Handler` naming

This PR implements the renaming described in https://github.com/rust-lang/compiler-team/issues/699.

r? `@compiler-errors`
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs2
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs85
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs4
-rw-r--r--compiler/rustc_ast_passes/src/show_span.rs12
-rw-r--r--compiler/rustc_attr/src/builtin.rs2
-rw-r--r--compiler/rustc_attr/src/session_diagnostics.rs10
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs10
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs4
-rw-r--r--compiler/rustc_borrowck/src/lib.rs2
-rw-r--r--compiler/rustc_borrowck/src/nll.rs4
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/alloc_error_handler.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs43
-rw-r--r--compiler/rustc_builtin_macros/src/cmdline_attrs.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs15
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs24
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs28
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/pretty_clif.rs5
-rw-r--r--compiler/rustc_codegen_gcc/src/back/lto.rs22
-rw-r--r--compiler/rustc_codegen_gcc/src/back/write.rs10
-rw-r--r--compiler/rustc_codegen_gcc/src/errors.rs7
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs87
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs76
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs19
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs24
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs43
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs32
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs89
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/write.rs8
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs2
-rw-r--r--compiler/rustc_const_eval/src/errors.rs62
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs6
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs4
-rw-r--r--compiler/rustc_driver_impl/src/args.rs6
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs123
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs4
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs118
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs18
-rw-r--r--compiler/rustc_errors/src/emitter.rs10
-rw-r--r--compiler/rustc_errors/src/json/tests.rs6
-rw-r--r--compiler/rustc_errors/src/lib.rs34
-rw-r--r--compiler/rustc_expand/src/base.rs32
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs11
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs35
-rw-r--r--compiler/rustc_expand/src/mbe/metavar_expr.rs21
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs15
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs4
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs2
-rw-r--r--compiler/rustc_expand/src/tests.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs12
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs12
-rw-r--r--compiler/rustc_interface/src/interface.rs52
-rw-r--r--compiler/rustc_interface/src/passes.rs6
-rw-r--r--compiler/rustc_interface/src/queries.rs2
-rw-r--r--compiler/rustc_interface/src/tests.rs70
-rw-r--r--compiler/rustc_interface/src/util.rs26
-rw-r--r--compiler/rustc_lint/src/expect.rs2
-rw-r--r--compiler/rustc_lint/src/levels.rs2
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs19
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs12
-rw-r--r--compiler/rustc_metadata/src/creader.rs2
-rw-r--r--compiler/rustc_metadata/src/errors.rs12
-rw-r--r--compiler/rustc_metadata/src/fs.rs2
-rw-r--r--compiler/rustc_middle/src/lint.rs6
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs8
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs2
-rw-r--r--compiler/rustc_middle/src/util/bug.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/errors.rs8
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs14
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs4
-rw-r--r--compiler/rustc_monomorphize/src/errors.rs4
-rw-r--r--compiler/rustc_parse/src/errors.rs8
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs20
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs4
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs49
-rw-r--r--compiler/rustc_parse/src/lexer/unicode_chars.rs2
-rw-r--r--compiler/rustc_parse/src/lib.rs10
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs4
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs5
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs26
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs24
-rw-r--r--compiler/rustc_parse/src/parser/item.rs14
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs2
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs11
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs4
-rw-r--r--compiler/rustc_parse/src/parser/path.rs4
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs6
-rw-r--r--compiler/rustc_passes/src/errors.rs20
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs4
-rw-r--r--compiler/rustc_query_system/src/query/job.rs10
-rw-r--r--compiler/rustc_resolve/src/macros.rs5
-rw-r--r--compiler/rustc_session/src/config.rs259
-rw-r--r--compiler/rustc_session/src/errors.rs4
-rw-r--r--compiler/rustc_session/src/options.rs14
-rw-r--r--compiler/rustc_session/src/parse.rs37
-rw-r--r--compiler/rustc_session/src/search_paths.rs6
-rw-r--r--compiler/rustc_session/src/session.rs153
-rw-r--r--compiler/rustc_symbol_mangling/src/errors.rs4
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs4
-rw-r--r--src/librustdoc/config.rs92
-rw-r--r--src/librustdoc/core.rs25
-rw-r--r--src/librustdoc/doctest.rs18
-rw-r--r--src/librustdoc/externalfiles.rs22
-rw-r--r--src/librustdoc/lib.rs48
-rw-r--r--src/librustdoc/passes/check_custom_code_classes.rs5
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs2
-rw-r--r--src/librustdoc/passes/lint/check_code_block_syntax.rs6
-rw-r--r--src/librustdoc/scrape_examples.rs15
-rw-r--r--src/librustdoc/theme.rs6
-rw-r--r--src/librustdoc/visit_ast.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs8
-rw-r--r--src/tools/clippy/src/driver.rs6
-rw-r--r--src/tools/error_index_generator/main.rs2
-rw-r--r--src/tools/miri/src/bin/miri.rs20
-rw-r--r--src/tools/miri/src/diagnostics.rs6
-rw-r--r--src/tools/rustfmt/src/parse/macros/cfg_if.rs2
-rw-r--r--src/tools/rustfmt/src/parse/macros/lazy_static.rs6
-rw-r--r--src/tools/rustfmt/src/parse/macros/mod.rs6
-rw-r--r--src/tools/rustfmt/src/parse/session.rs20
-rw-r--r--tests/ui-fulldeps/internal-lints/diagnostics.rs20
-rw-r--r--tests/ui-fulldeps/internal-lints/diagnostics.stderr24
145 files changed, 1296 insertions, 1392 deletions
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index efd80af5ef4..d323c16165b 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -139,7 +139,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
 
         // We should've returned in the for loop above.
 
-        self.tcx.sess.diagnostic().span_bug(
+        self.tcx.sess.dcx().span_bug(
             p.span,
             format!(
                 "lower_qpath: no final extension segment in {}..{}",
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 59cf18c2459..9db72c15941 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -220,8 +220,8 @@ impl<'a> AstValidator<'a> {
         }
     }
 
-    fn err_handler(&self) -> &rustc_errors::Handler {
-        self.session.diagnostic()
+    fn dcx(&self) -> &rustc_errors::DiagCtxt {
+        self.session.dcx()
     }
 
     fn check_lifetime(&self, ident: Ident) {
@@ -269,7 +269,7 @@ impl<'a> AstValidator<'a> {
         ) {
             return;
         }
-        self.err_handler().emit_err(errors::InvalidUnnamedFieldTy { span, ty_span: ty.span });
+        self.dcx().emit_err(errors::InvalidUnnamedFieldTy { span, ty_span: ty.span });
     }
 
     fn deny_anon_struct_or_union(&self, ty: &Ty) {
@@ -278,15 +278,14 @@ impl<'a> AstValidator<'a> {
             TyKind::AnonUnion(..) => "union",
             _ => return,
         };
-        self.err_handler()
-            .emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span: ty.span });
+        self.dcx().emit_err(errors::AnonStructOrUnionNotAllowed { struct_or_union, span: ty.span });
     }
 
     fn deny_unnamed_field(&self, field: &FieldDef) {
         if let Some(ident) = field.ident
             && ident.name == kw::Underscore
         {
-            self.err_handler()
+            self.dcx()
                 .emit_err(errors::InvalidUnnamedField { span: field.span, ident_span: ident.span });
         }
     }
@@ -392,7 +391,7 @@ impl<'a> AstValidator<'a> {
             [b0] => b0.span(),
             [b0, .., bl] => b0.span().to(bl.span()),
         };
-        self.err_handler().emit_err(errors::BoundInContext { span, ctx });
+        self.dcx().emit_err(errors::BoundInContext { span, ctx });
     }
 
     fn check_foreign_ty_genericless(
@@ -402,7 +401,7 @@ impl<'a> AstValidator<'a> {
         after_where_clause: &TyAliasWhereClause,
     ) {
         let cannot_have = |span, descr, remove_descr| {
-            self.err_handler().emit_err(errors::ExternTypesCannotHave {
+            self.dcx().emit_err(errors::ExternTypesCannotHave {
                 span,
                 descr,
                 remove_descr,
@@ -428,7 +427,7 @@ impl<'a> AstValidator<'a> {
         let Some(body) = body else {
             return;
         };
-        self.err_handler().emit_err(errors::BodyInExtern {
+        self.dcx().emit_err(errors::BodyInExtern {
             span: ident.span,
             body,
             block: self.current_extern_span(),
@@ -441,7 +440,7 @@ impl<'a> AstValidator<'a> {
         let Some(body) = body else {
             return;
         };
-        self.err_handler().emit_err(errors::FnBodyInExtern {
+        self.dcx().emit_err(errors::FnBodyInExtern {
             span: ident.span,
             body: body.span,
             block: self.current_extern_span(),
@@ -455,7 +454,7 @@ impl<'a> AstValidator<'a> {
     /// An `fn` in `extern { ... }` cannot have qualifiers, e.g. `async fn`.
     fn check_foreign_fn_headerless(&self, ident: Ident, span: Span, header: FnHeader) {
         if header.has_qualifiers() {
-            self.err_handler().emit_err(errors::FnQualifierInExtern {
+            self.dcx().emit_err(errors::FnQualifierInExtern {
                 span: ident.span,
                 block: self.current_extern_span(),
                 sugg_span: span.until(ident.span.shrink_to_lo()),
@@ -466,7 +465,7 @@ impl<'a> AstValidator<'a> {
     /// An item in `extern { ... }` cannot use non-ascii identifier.
     fn check_foreign_item_ascii_only(&self, ident: Ident) {
         if !ident.as_str().is_ascii() {
-            self.err_handler().emit_err(errors::ExternItemAscii {
+            self.dcx().emit_err(errors::ExternItemAscii {
                 span: ident.span,
                 block: self.current_extern_span(),
             });
@@ -495,7 +494,7 @@ impl<'a> AstValidator<'a> {
             if let Const::Yes(const_span) = header.constness {
                 let mut spans = variadic_spans.clone();
                 spans.push(const_span);
-                self.err_handler().emit_err(errors::ConstAndCVariadic {
+                self.dcx().emit_err(errors::ConstAndCVariadic {
                     spans,
                     const_span,
                     variadic_spans: variadic_spans.clone(),
@@ -517,14 +516,14 @@ impl<'a> AstValidator<'a> {
             _ => {}
         };
 
-        self.err_handler().emit_err(errors::BadCVariadic { span: variadic_spans });
+        self.dcx().emit_err(errors::BadCVariadic { span: variadic_spans });
     }
 
     fn check_item_named(&self, ident: Ident, kind: &str) {
         if ident.name != kw::Underscore {
             return;
         }
-        self.err_handler().emit_err(errors::ItemUnderscore { span: ident.span, kind });
+        self.dcx().emit_err(errors::ItemUnderscore { span: ident.span, kind });
     }
 
     fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
@@ -615,7 +614,7 @@ impl<'a> AstValidator<'a> {
         let args_len = arg_spans.len();
         let constraint_len = constraint_spans.len();
         // ...and then error:
-        self.err_handler().emit_err(errors::ArgsBeforeConstraint {
+        self.dcx().emit_err(errors::ArgsBeforeConstraint {
             arg_spans: arg_spans.clone(),
             constraints: constraint_spans[0],
             args: *arg_spans.iter().last().unwrap(),
@@ -667,7 +666,7 @@ impl<'a> AstValidator<'a> {
                 }
 
                 if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) {
-                    self.err_handler().emit_err(errors::AtLeastOneTrait { span: ty.span });
+                    self.dcx().emit_err(errors::AtLeastOneTrait { span: ty.span });
                 }
             }
             _ => {}
@@ -697,7 +696,7 @@ impl<'a> AstValidator<'a> {
 /// Checks that generic parameters are in the correct order,
 /// which is lifetimes, then types and then consts. (`<'a, T, const N: usize>`)
 fn validate_generic_param_order(
-    handler: &rustc_errors::Handler,
+    dcx: &rustc_errors::DiagCtxt,
     generics: &[GenericParam],
     span: Span,
 ) {
@@ -760,7 +759,7 @@ fn validate_generic_param_order(
         ordered_params += ">";
 
         for (param_ord, (max_param, spans)) in &out_of_order {
-            handler.emit_err(errors::OutOfOrderParams {
+            dcx.emit_err(errors::OutOfOrderParams {
                 spans: spans.clone(),
                 sugg_span: span,
                 param_ord,
@@ -823,7 +822,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         errors::VisibilityNotPermittedNote::TraitImpl,
                     );
                     if let TyKind::Err = self_ty.kind {
-                        this.err_handler().emit_err(errors::ObsoleteAuto { span: item.span });
+                        this.dcx().emit_err(errors::ObsoleteAuto { span: item.span });
                     }
                     if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity)
                     {
@@ -871,7 +870,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     errors::VisibilityNotPermittedNote::IndividualImplItems,
                 );
                 if let &Unsafe::Yes(span) = unsafety {
-                    self.err_handler().emit_err(errors::InherentImplCannotUnsafe {
+                    self.dcx().emit_err(errors::InherentImplCannotUnsafe {
                         span: self_ty.span,
                         annotation_span: span,
                         annotation: "unsafe",
@@ -879,13 +878,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     });
                 }
                 if let &ImplPolarity::Negative(span) = polarity {
-                    self.err_handler().emit_err(error(span, "negative", false));
+                    self.dcx().emit_err(error(span, "negative", false));
                 }
                 if let &Defaultness::Default(def_span) = defaultness {
-                    self.err_handler().emit_err(error(def_span, "`default`", true));
+                    self.dcx().emit_err(error(def_span, "`default`", true));
                 }
                 if let &Const::Yes(span) = constness {
-                    self.err_handler().emit_err(error(span, "`const`", true));
+                    self.dcx().emit_err(error(span, "`const`", true));
                 }
 
                 self.visit_vis(&item.vis);
@@ -937,7 +936,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     errors::VisibilityNotPermittedNote::IndividualForeignItems,
                 );
                 if let &Unsafe::Yes(span) = unsafety {
-                    self.err_handler().emit_err(errors::UnsafeItem { span, kind: "extern block" });
+                    self.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" });
                 }
                 if abi.is_none() {
                     self.maybe_lint_missing_abi(item.span, item.id);
@@ -988,7 +987,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             }
             ItemKind::Mod(unsafety, mod_kind) => {
                 if let &Unsafe::Yes(span) = unsafety {
-                    self.err_handler().emit_err(errors::UnsafeItem { span, kind: "module" });
+                    self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
                 }
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
                 if !matches!(mod_kind, ModKind::Loaded(_, Inline::Yes, _))
@@ -1011,7 +1010,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             },
             ItemKind::Union(vdata, generics) => {
                 if vdata.fields().is_empty() {
-                    self.err_handler().emit_err(errors::FieldlessUnion { span: item.span });
+                    self.dcx().emit_err(errors::FieldlessUnion { span: item.span });
                 }
                 match vdata {
                     VariantData::Struct(fields, ..) => {
@@ -1053,10 +1052,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
                 if self.features.lazy_type_alias {
                     if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
-                        self.err_handler().emit_err(err);
+                        self.dcx().emit_err(err);
                     }
                 } else if where_clauses.1.0 {
-                    self.err_handler().emit_err(errors::WhereClauseAfterTypeAlias {
+                    self.dcx().emit_err(errors::WhereClauseAfterTypeAlias {
                         span: where_clauses.1.1,
                         help: self.session.is_nightly_build().then_some(()),
                     });
@@ -1141,14 +1140,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
                 GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
                     if let Some(span) = prev_param_default {
-                        self.err_handler().emit_err(errors::GenericDefaultTrailing { span });
+                        self.dcx().emit_err(errors::GenericDefaultTrailing { span });
                         break;
                     }
                 }
             }
         }
 
-        validate_generic_param_order(self.err_handler(), &generics.params, generics.span);
+        validate_generic_param_order(self.dcx(), &generics.params, generics.span);
 
         for predicate in &generics.where_clause.predicates {
             if let WherePredicate::EqPredicate(predicate) = predicate {
@@ -1169,7 +1168,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                             match bound {
                                 GenericBound::Trait(t, _) => {
                                     if !t.bound_generic_params.is_empty() {
-                                        self.err_handler()
+                                        self.dcx()
                                             .emit_err(errors::NestedLifetimes { span: t.span });
                                     }
                                 }
@@ -1195,13 +1194,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         if let GenericBound::Trait(poly, modify) = bound {
             match (ctxt, modify) {
                 (BoundKind::SuperTraits, TraitBoundModifier::Maybe) => {
-                    self.err_handler().emit_err(errors::OptionalTraitSupertrait {
+                    self.dcx().emit_err(errors::OptionalTraitSupertrait {
                         span: poly.span,
                         path_str: pprust::path_to_string(&poly.trait_ref.path),
                     });
                 }
                 (BoundKind::TraitObject, TraitBoundModifier::Maybe) => {
-                    self.err_handler().emit_err(errors::OptionalTraitObject { span: poly.span });
+                    self.dcx().emit_err(errors::OptionalTraitObject { span: poly.span });
                 }
                 (_, &TraitBoundModifier::MaybeConst(span))
                     if let Some(reason) = &self.disallow_tilde_const =>
@@ -1224,16 +1223,16 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         }
                         DisallowTildeConstContext::Item => errors::TildeConstReason::Item,
                     };
-                    self.err_handler().emit_err(errors::TildeConstDisallowed { span, reason });
+                    self.dcx().emit_err(errors::TildeConstDisallowed { span, reason });
                 }
                 (_, TraitBoundModifier::MaybeConstMaybe) => {
-                    self.err_handler().emit_err(errors::OptionalConstExclusive {
+                    self.dcx().emit_err(errors::OptionalConstExclusive {
                         span: bound.span(),
                         modifier: "?",
                     });
                 }
                 (_, TraitBoundModifier::MaybeConstNegative) => {
-                    self.err_handler().emit_err(errors::OptionalConstExclusive {
+                    self.dcx().emit_err(errors::OptionalConstExclusive {
                         span: bound.span(),
                         modifier: "!",
                     });
@@ -1249,7 +1248,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         {
             for arg in &args.args {
                 if let ast::AngleBracketedArg::Constraint(constraint) = arg {
-                    self.err_handler()
+                    self.dcx()
                         .emit_err(errors::ConstraintOnNegativeBound { span: constraint.span });
                 }
             }
@@ -1281,7 +1280,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 | CoroutineKind::AsyncGen { span: aspan, .. } => aspan,
             };
             // FIXME(gen_blocks): Report a different error for `const gen`
-            self.err_handler().emit_err(errors::ConstAndAsync {
+            self.dcx().emit_err(errors::ConstAndAsync {
                 spans: vec![cspan, aspan],
                 cspan,
                 aspan,
@@ -1321,10 +1320,8 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                     }
                 } else {
                     match ctxt {
-                        FnCtxt::Foreign => {
-                            self.err_handler().emit_err(errors::PatternInForeign { span })
-                        }
-                        _ => self.err_handler().emit_err(errors::PatternInBodiless { span }),
+                        FnCtxt::Foreign => self.dcx().emit_err(errors::PatternInForeign { span }),
+                        _ => self.dcx().emit_err(errors::PatternInBodiless { span }),
                     };
                 }
             });
@@ -1523,7 +1520,7 @@ fn deny_equality_constraints(
             }
         }
     }
-    this.err_handler().emit_err(err);
+    this.dcx().emit_err(err);
 }
 
 pub fn check_crate(
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index ac55c6cabd0..142cdd15e64 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -102,7 +102,7 @@ impl<'a> PostExpansionVisitor<'a> {
             }
             Err(abi::AbiDisabled::Unrecognized) => {
                 if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) {
-                    self.sess.diagnostic().span_delayed_bug(
+                    self.sess.dcx().span_delayed_bug(
                         span,
                         format!(
                             "unrecognized ABI not caught in lowering: {}",
@@ -654,7 +654,7 @@ fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate)
             if all_stable {
                 err.sugg = Some(attr.span);
             }
-            sess.diagnostic().emit_err(err);
+            sess.dcx().emit_err(err);
         }
     }
 }
diff --git a/compiler/rustc_ast_passes/src/show_span.rs b/compiler/rustc_ast_passes/src/show_span.rs
index 280cf3284c3..9882f1d23ce 100644
--- a/compiler/rustc_ast_passes/src/show_span.rs
+++ b/compiler/rustc_ast_passes/src/show_span.rs
@@ -31,37 +31,37 @@ impl FromStr for Mode {
 }
 
 struct ShowSpanVisitor<'a> {
-    span_diagnostic: &'a rustc_errors::Handler,
+    dcx: &'a rustc_errors::DiagCtxt,
     mode: Mode,
 }
 
 impl<'a> Visitor<'a> for ShowSpanVisitor<'a> {
     fn visit_expr(&mut self, e: &'a ast::Expr) {
         if let Mode::Expression = self.mode {
-            self.span_diagnostic.emit_warning(errors::ShowSpan { span: e.span, msg: "expression" });
+            self.dcx.emit_warning(errors::ShowSpan { span: e.span, msg: "expression" });
         }
         visit::walk_expr(self, e);
     }
 
     fn visit_pat(&mut self, p: &'a ast::Pat) {
         if let Mode::Pattern = self.mode {
-            self.span_diagnostic.emit_warning(errors::ShowSpan { span: p.span, msg: "pattern" });
+            self.dcx.emit_warning(errors::ShowSpan { span: p.span, msg: "pattern" });
         }
         visit::walk_pat(self, p);
     }
 
     fn visit_ty(&mut self, t: &'a ast::Ty) {
         if let Mode::Type = self.mode {
-            self.span_diagnostic.emit_warning(errors::ShowSpan { span: t.span, msg: "type" });
+            self.dcx.emit_warning(errors::ShowSpan { span: t.span, msg: "type" });
         }
         visit::walk_ty(self, t);
     }
 }
 
-pub fn run(span_diagnostic: &rustc_errors::Handler, mode: &str, krate: &ast::Crate) {
+pub fn run(dcx: &rustc_errors::DiagCtxt, mode: &str, krate: &ast::Crate) {
     let Ok(mode) = mode.parse() else {
         return;
     };
-    let mut v = ShowSpanVisitor { span_diagnostic, mode };
+    let mut v = ShowSpanVisitor { dcx, mode };
     visit::walk_crate(&mut v, krate);
 }
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index a6930fe0a17..0959e8d3043 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -945,7 +945,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.diagnostic();
+    let diagnostic = sess.dcx();
 
     if let Some(items) = attr.meta_item_list() {
         for item in items {
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
index ca9bbd28b95..ce8e04defb2 100644
--- a/compiler/rustc_attr/src/session_diagnostics.rs
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -2,7 +2,7 @@ use std::num::IntErrorKind;
 
 use rustc_ast as ast;
 use rustc_errors::{
-    error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
+    error_code, Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
 };
 use rustc_macros::Diagnostic;
 use rustc_span::{Span, Symbol};
@@ -51,9 +51,9 @@ pub(crate) struct UnknownMetaItem<'a> {
 
 // Manual implementation to be able to format `expected` items correctly.
 impl<'a> IntoDiagnostic<'a> for UnknownMetaItem<'_> {
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+    fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         let expected = self.expected.iter().map(|name| format!("`{name}`")).collect::<Vec<_>>();
-        let mut diag = handler.struct_span_err_with_code(
+        let mut diag = dcx.struct_span_err_with_code(
             self.span,
             fluent::attr_unknown_meta_item,
             error_code!(E0541),
@@ -201,8 +201,8 @@ pub(crate) struct UnsupportedLiteral {
 }
 
 impl<'a> IntoDiagnostic<'a> for UnsupportedLiteral {
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut diag = handler.struct_span_err_with_code(
+    fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        let mut diag = dcx.struct_span_err_with_code(
             self.span,
             match self.reason {
                 UnsupportedLiteralReason::Generic => fluent::attr_unsupported_literal_generic,
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 2f366001d4b..db0f4559a6b 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1138,7 +1138,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             });
         } else {
             issued_spans.var_subdiag(
-                Some(self.infcx.tcx.sess.diagnostic()),
+                Some(self.infcx.tcx.sess.dcx()),
                 &mut err,
                 Some(issued_borrow.kind),
                 |kind, var_span| {
@@ -1155,7 +1155,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             );
 
             borrow_spans.var_subdiag(
-                Some(self.infcx.tcx.sess.diagnostic()),
+                Some(self.infcx.tcx.sess.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 1616b5e99bf..ee321365470 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.diagnostic(),
+                                self.infcx.tcx.sess.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.diagnostic(),
+                        self.infcx.tcx.sess.dcx(),
                         OnClosureNote::MovedTwice {
                             place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
                             span: *span,
@@ -624,7 +624,7 @@ impl UseSpans<'_> {
     /// Add a subdiagnostic to the use of the captured variable, if it exists.
     pub(super) fn var_subdiag(
         self,
-        handler: Option<&rustc_errors::Handler>,
+        dcx: Option<&rustc_errors::DiagCtxt>,
         err: &mut Diagnostic,
         kind: Option<rustc_middle::mir::BorrowKind>,
         f: impl FnOnce(Option<CoroutineKind>, Span) -> CaptureVarCause,
@@ -646,7 +646,7 @@ impl UseSpans<'_> {
                 });
             };
             let diag = f(coroutine_kind, path_span);
-            match handler {
+            match dcx {
                 Some(hd) => err.eager_subdiagnostic(hd, diag),
                 None => err.subdiagnostic(diag),
             };
@@ -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.diagnostic(),
+                                self.infcx.tcx.sess.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 94981c45582..66275888c50 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.diagnostic().struct_help(match suggested.last().unwrap() {
+            mbcx.infcx.tcx.sess.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(" + "))
@@ -223,7 +223,7 @@ impl OutlivesSuggestionBuilder {
                 .infcx
                 .tcx
                 .sess
-                .diagnostic()
+                .dcx()
                 .struct_help("the following changes may resolve your lifetime errors");
 
             // Add suggestions.
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 7e0e598cd9f..43f48f579a3 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -2503,7 +2503,7 @@ mod error {
                 self.errors.buffered.sort_by_key(|diag| diag.sort_span);
 
                 for diag in self.errors.buffered.drain(..) {
-                    self.infcx.tcx.sess.diagnostic().emit_diagnostic(diag);
+                    self.infcx.tcx.sess.dcx().emit_diagnostic(diag);
                 }
             }
 
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index c88d9d81fe1..6781c6a756f 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -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.diagnostic().struct_span_note(def_span, "external requirements");
+        let mut err = tcx.sess.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.diagnostic().struct_span_note(def_span, "no external requirements");
+        let mut err = tcx.sess.dcx().struct_span_note(def_span, "no external requirements");
         regioncx.annotate(tcx, &mut err);
 
         err
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 98c21693cf0..5247d5f6981 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -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.diagnostic().span_delayed_bug(span, msg);
+    tcx.sess.dcx().span_delayed_bug(span, msg);
 }
 
 enum FieldAccessError {
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index e13d217ef01..dffda8acc8d 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.diagnostic().emit_err(errors::AllocErrorMustBeFn { span: item.span() });
+        ecx.sess.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 9e66eaf73b3..6f1acd8e570 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -47,10 +47,10 @@ pub fn parse_asm_args<'a>(
     sp: Span,
     is_global_asm: bool,
 ) -> PResult<'a, AsmArgs> {
-    let diag = &sess.span_diagnostic;
+    let dcx = &sess.dcx;
 
     if p.token == token::Eof {
-        return Err(diag.create_err(errors::AsmRequiresTemplate { span: sp }));
+        return Err(dcx.create_err(errors::AsmRequiresTemplate { span: sp }));
     }
 
     let first_template = p.parse_expr()?;
@@ -69,7 +69,7 @@ pub fn parse_asm_args<'a>(
         if !p.eat(&token::Comma) {
             if allow_templates {
                 // After a template string, we always expect *only* a comma...
-                return Err(diag.create_err(errors::AsmExpectedComma { span: p.token.span }));
+                return Err(dcx.create_err(errors::AsmExpectedComma { span: p.token.span }));
             } else {
                 // ...after that delegate to `expect` to also include the other expected tokens.
                 return Err(p.expect(&token::Comma).err().unwrap());
@@ -110,7 +110,7 @@ pub fn parse_asm_args<'a>(
         let op = if !is_global_asm && p.eat_keyword(kw::In) {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
-                let err = diag.create_err(errors::AsmUnderscoreInput { span: p.token.span });
+                let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
                 return Err(err);
             }
             let expr = p.parse_expr()?;
@@ -126,7 +126,7 @@ pub fn parse_asm_args<'a>(
         } else if !is_global_asm && p.eat_keyword(sym::inout) {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
-                let err = diag.create_err(errors::AsmUnderscoreInput { span: p.token.span });
+                let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
                 return Err(err);
             }
             let expr = p.parse_expr()?;
@@ -140,7 +140,7 @@ pub fn parse_asm_args<'a>(
         } else if !is_global_asm && p.eat_keyword(sym::inlateout) {
             let reg = parse_reg(p, &mut explicit_reg)?;
             if p.eat_keyword(kw::Underscore) {
-                let err = diag.create_err(errors::AsmUnderscoreInput { span: p.token.span });
+                let err = dcx.create_err(errors::AsmUnderscoreInput { span: p.token.span });
                 return Err(err);
             }
             let expr = p.parse_expr()?;
@@ -157,7 +157,7 @@ pub fn parse_asm_args<'a>(
         } else if p.eat_keyword(sym::sym) {
             let expr = p.parse_expr()?;
             let ast::ExprKind::Path(qself, path) = &expr.kind else {
-                let err = diag.create_err(errors::AsmSymNoPath { span: expr.span });
+                let err = dcx.create_err(errors::AsmSymNoPath { span: expr.span });
                 return Err(err);
             };
             let sym = ast::InlineAsmSym {
@@ -178,7 +178,7 @@ pub fn parse_asm_args<'a>(
                     ) => {}
                 ast::ExprKind::MacCall(..) => {}
                 _ => {
-                    let err = diag.create_err(errors::AsmExpectedOther {
+                    let err = dcx.create_err(errors::AsmExpectedOther {
                         span: template.span,
                         is_global_asm,
                     });
@@ -201,12 +201,12 @@ pub fn parse_asm_args<'a>(
         // of the argument available.
         if explicit_reg {
             if name.is_some() {
-                diag.emit_err(errors::AsmExplicitRegisterName { span });
+                dcx.emit_err(errors::AsmExplicitRegisterName { span });
             }
             args.reg_args.insert(slot);
         } else if let Some(name) = name {
             if let Some(&prev) = args.named_args.get(&name) {
-                diag.emit_err(errors::AsmDuplicateArg { span, name, prev: args.operands[prev].1 });
+                dcx.emit_err(errors::AsmDuplicateArg { span, name, prev: args.operands[prev].1 });
                 continue;
             }
             args.named_args.insert(name, slot);
@@ -215,7 +215,7 @@ pub fn parse_asm_args<'a>(
                 let named = args.named_args.values().map(|p| args.operands[*p].1).collect();
                 let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect();
 
-                diag.emit_err(errors::AsmPositionalAfter { span, named, explicit });
+                dcx.emit_err(errors::AsmPositionalAfter { span, named, explicit });
             }
         }
     }
@@ -224,19 +224,19 @@ pub fn parse_asm_args<'a>(
         && args.options.contains(ast::InlineAsmOptions::READONLY)
     {
         let spans = args.options_spans.clone();
-        diag.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" });
+        dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" });
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && args.options.contains(ast::InlineAsmOptions::NORETURN)
     {
         let spans = args.options_spans.clone();
-        diag.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" });
+        dcx.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" });
     }
     if args.options.contains(ast::InlineAsmOptions::PURE)
         && !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
     {
         let spans = args.options_spans.clone();
-        diag.emit_err(errors::AsmPureCombine { spans });
+        dcx.emit_err(errors::AsmPureCombine { spans });
     }
 
     let mut have_real_output = false;
@@ -263,17 +263,17 @@ pub fn parse_asm_args<'a>(
         }
     }
     if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
-        diag.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
+        dcx.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
     }
     if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
-        let err = diag.create_err(errors::AsmNoReturn { outputs_sp });
+        let err = dcx.create_err(errors::AsmNoReturn { outputs_sp });
         // Bail out now since this is likely to confuse MIR
         return Err(err);
     }
 
     if args.clobber_abis.len() > 0 {
         if is_global_asm {
-            let err = diag.create_err(errors::GlobalAsmClobberAbi {
+            let err = dcx.create_err(errors::GlobalAsmClobberAbi {
                 spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
             });
 
@@ -281,7 +281,7 @@ pub fn parse_asm_args<'a>(
             return Err(err);
         }
         if !regclass_outputs.is_empty() {
-            diag.emit_err(errors::AsmClobberNoReg {
+            dcx.emit_err(errors::AsmClobberNoReg {
                 spans: regclass_outputs,
                 clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
             });
@@ -298,7 +298,7 @@ pub fn parse_asm_args<'a>(
 fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) {
     // Tool-only output
     let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span };
-    p.sess.span_diagnostic.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
+    p.sess.dcx.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
 }
 
 /// Try to set the provided option in the provided `AsmArgs`.
@@ -370,7 +370,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
     p.expect(&token::OpenDelim(Delimiter::Parenthesis))?;
 
     if p.eat(&token::CloseDelim(Delimiter::Parenthesis)) {
-        return Err(p.sess.span_diagnostic.create_err(errors::NonABI { span: p.token.span }));
+        return Err(p.sess.dcx.create_err(errors::NonABI { span: p.token.span }));
     }
 
     let mut new_abis = Vec::new();
@@ -381,8 +381,7 @@ fn parse_clobber_abi<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> PResult<'a,
             }
             Err(opt_lit) => {
                 let span = opt_lit.map_or(p.token.span, |lit| lit.span);
-                let mut err =
-                    p.sess.span_diagnostic.struct_span_err(span, "expected string literal");
+                let mut err = p.sess.dcx.struct_span_err(span, "expected string literal");
                 err.span_label(span, "not a string literal");
                 return Err(err);
             }
diff --git a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
index 3b1fde1f097..2803ddefba2 100644
--- a/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
+++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs
@@ -25,9 +25,7 @@ pub fn inject(krate: &mut ast::Crate, parse_sess: &ParseSess, attrs: &[String])
         };
         let end_span = parser.token.span;
         if parser.token != token::Eof {
-            parse_sess
-                .span_diagnostic
-                .emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
+            parse_sess.dcx.emit_err(errors::InvalidCrateAttr { span: start_span.to(end_span) });
             continue;
         }
 
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 3d02cd72e54..6ffeb401453 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -1,5 +1,5 @@
 use rustc_errors::{
-    AddToDiagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, MultiSpan,
+    AddToDiagnostic, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
     SingleLabelManySpans,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
@@ -448,12 +448,12 @@ pub(crate) struct EnvNotDefinedWithUserMessage {
 // Hand-written implementation to support custom user messages.
 impl<'a> IntoDiagnostic<'a> for EnvNotDefinedWithUserMessage {
     #[track_caller]
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+    fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
         #[expect(
             rustc::untranslatable_diagnostic,
             reason = "cannot translate user-provided messages"
         )]
-        let mut diag = handler.struct_err(self.msg_from_user.to_string());
+        let mut diag = dcx.struct_err(self.msg_from_user.to_string());
         diag.set_span(self.span);
         diag
     }
@@ -802,17 +802,16 @@ pub(crate) struct AsmClobberNoReg {
 }
 
 impl<'a> IntoDiagnostic<'a> for AsmClobberNoReg {
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut diag =
-            handler.struct_err(crate::fluent_generated::builtin_macros_asm_clobber_no_reg);
+    fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        let mut diag = dcx.struct_err(crate::fluent_generated::builtin_macros_asm_clobber_no_reg);
         diag.set_span(self.spans.clone());
         // eager translation as `span_labels` takes `AsRef<str>`
-        let lbl1 = handler.eagerly_translate_to_string(
+        let lbl1 = dcx.eagerly_translate_to_string(
             crate::fluent_generated::builtin_macros_asm_clobber_abi,
             [].into_iter(),
         );
         diag.span_labels(self.clobbers, &lbl1);
-        let lbl2 = handler.eagerly_translate_to_string(
+        let lbl2 = dcx.eagerly_translate_to_string(
             crate::fluent_generated::builtin_macros_asm_clobber_outputs,
             [].into_iter(),
         );
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 6dc75e3ba4c..00c7907cdb4 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.diagnostic().emit_err(errors::AllocMustStatics { span: item.span() });
+        ecx.sess.dcx().emit_err(errors::AllocMustStatics { span: item.span() });
         return vec![orig_item];
     };
 
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index dae1bc5bfe5..4fddaa8ab6c 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -38,7 +38,7 @@ enum ProcMacro {
 struct CollectProcMacros<'a> {
     macros: Vec<ProcMacro>,
     in_root: bool,
-    handler: &'a rustc_errors::Handler,
+    dcx: &'a rustc_errors::DiagCtxt,
     source_map: &'a SourceMap,
     is_proc_macro_crate: bool,
     is_test_crate: bool,
@@ -52,7 +52,7 @@ pub fn inject(
     is_proc_macro_crate: bool,
     has_proc_macro_decls: bool,
     is_test_crate: bool,
-    handler: &rustc_errors::Handler,
+    dcx: &rustc_errors::DiagCtxt,
 ) {
     let ecfg = ExpansionConfig::default("proc_macro".to_string(), features);
     let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
@@ -60,7 +60,7 @@ pub fn inject(
     let mut collect = CollectProcMacros {
         macros: Vec::new(),
         in_root: true,
-        handler,
+        dcx,
         source_map: sess.source_map(),
         is_proc_macro_crate,
         is_test_crate,
@@ -86,13 +86,13 @@ pub fn inject(
 impl<'a> CollectProcMacros<'a> {
     fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) {
         if self.is_proc_macro_crate && self.in_root && vis.kind.is_pub() {
-            self.handler.emit_err(errors::ProcMacro { span: sp });
+            self.dcx.emit_err(errors::ProcMacro { span: sp });
         }
     }
 
     fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribute) {
         let Some((trait_name, proc_attrs)) =
-            parse_macro_name_and_helper_attrs(self.handler, attr, "derive")
+            parse_macro_name_and_helper_attrs(self.dcx, attr, "derive")
         else {
             return;
         };
@@ -112,7 +112,7 @@ impl<'a> CollectProcMacros<'a> {
             } else {
                 "functions tagged with `#[proc_macro_derive]` must be `pub`"
             };
-            self.handler.span_err(self.source_map.guess_head_span(item.span), msg);
+            self.dcx.span_err(self.source_map.guess_head_span(item.span), msg);
         }
     }
 
@@ -130,7 +130,7 @@ impl<'a> CollectProcMacros<'a> {
             } else {
                 "functions tagged with `#[proc_macro_attribute]` must be `pub`"
             };
-            self.handler.span_err(self.source_map.guess_head_span(item.span), msg);
+            self.dcx.span_err(self.source_map.guess_head_span(item.span), msg);
         }
     }
 
@@ -148,7 +148,7 @@ impl<'a> CollectProcMacros<'a> {
             } else {
                 "functions tagged with `#[proc_macro]` must be `pub`"
             };
-            self.handler.span_err(self.source_map.guess_head_span(item.span), msg);
+            self.dcx.span_err(self.source_map.guess_head_span(item.span), msg);
         }
     }
 }
@@ -157,7 +157,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
     fn visit_item(&mut self, item: &'a ast::Item) {
         if let ast::ItemKind::MacroDef(..) = item.kind {
             if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) {
-                self.handler.emit_err(errors::ExportMacroRules {
+                self.dcx.emit_err(errors::ExportMacroRules {
                     span: self.source_map.guess_head_span(item.span),
                 });
             }
@@ -192,7 +192,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
                         )
                     };
 
-                    self.handler
+                    self.dcx
                         .struct_span_err(attr.span, msg)
                         .span_label(prev_attr.span, "previous attribute here")
                         .emit();
@@ -218,7 +218,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
                 pprust::path_to_string(&attr.get_normal_item().path),
             );
 
-            self.handler.span_err(attr.span, msg);
+            self.dcx.span_err(attr.span, msg);
             return;
         }
 
@@ -232,7 +232,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
                 pprust::path_to_string(&attr.get_normal_item().path),
             );
 
-            self.handler.span_err(attr.span, msg);
+            self.dcx.span_err(attr.span, msg);
             return;
         }
 
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index e5b274304e7..ec843a3a0cd 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -389,16 +389,16 @@ pub fn expand_test_or_bench(
 }
 
 fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) {
-    let diag = cx.sess.diagnostic();
+    let dcx = cx.sess.dcx();
     let msg = "the `#[test]` attribute may only be used on a non-associated function";
     let mut err = match item.map(|i| &i.kind) {
         // These were a warning before #92959 and need to continue being that to avoid breaking
         // stable user code (#94508).
-        Some(ast::ItemKind::MacCall(_)) => diag.struct_span_warn(attr_sp, msg),
+        Some(ast::ItemKind::MacCall(_)) => dcx.struct_span_warn(attr_sp, msg),
         // `.forget_guarantee()` needed to get these two arms to match types. Because of how
         // locally close the `.emit()` call is I'm comfortable with it, but if it can be
         // reworked in the future to not need it, it'd be nice.
-        _ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
+        _ => dcx.struct_span_err(attr_sp, msg).forget_guarantee(),
     };
     if let Some(item) = item {
         err.span_label(
@@ -466,7 +466,7 @@ 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 sd = cx.sess.diagnostic();
+            let dcx = cx.sess.dcx();
 
             match attr.meta_item_list() {
                 // Handle #[should_panic(expected = "foo")]
@@ -477,7 +477,7 @@ 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() {
-                        sd.struct_span_warn(
+                        dcx.struct_span_warn(
                             attr.span,
                             "argument must be of the form: \
                              `expected = \"error message\"`",
@@ -535,30 +535,30 @@ fn check_test_signature(
     f: &ast::Fn,
 ) -> Result<(), ErrorGuaranteed> {
     let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
-    let sd = cx.sess.diagnostic();
+    let dcx = cx.sess.dcx();
 
     if let ast::Unsafe::Yes(span) = f.sig.header.unsafety {
-        return Err(sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
+        return Err(dcx.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
     }
 
     if let Some(coroutine_kind) = f.sig.header.coroutine_kind {
         match coroutine_kind {
             ast::CoroutineKind::Async { span, .. } => {
-                return Err(sd.emit_err(errors::TestBadFn {
+                return Err(dcx.emit_err(errors::TestBadFn {
                     span: i.span,
                     cause: span,
                     kind: "async",
                 }));
             }
             ast::CoroutineKind::Gen { span, .. } => {
-                return Err(sd.emit_err(errors::TestBadFn {
+                return Err(dcx.emit_err(errors::TestBadFn {
                     span: i.span,
                     cause: span,
                     kind: "gen",
                 }));
             }
             ast::CoroutineKind::AsyncGen { span, .. } => {
-                return Err(sd.emit_err(errors::TestBadFn {
+                return Err(dcx.emit_err(errors::TestBadFn {
                     span: i.span,
                     cause: span,
                     kind: "async gen",
@@ -576,15 +576,15 @@ fn check_test_signature(
     };
 
     if !f.sig.decl.inputs.is_empty() {
-        return Err(sd.span_err(i.span, "functions used as tests can not have any arguments"));
+        return Err(dcx.span_err(i.span, "functions used as tests can not have any arguments"));
     }
 
     if has_should_panic_attr && has_output {
-        return Err(sd.span_err(i.span, "functions using `#[should_panic]` must return `()`"));
+        return Err(dcx.span_err(i.span, "functions using `#[should_panic]` must return `()`"));
     }
 
     if f.generics.params.iter().any(|param| !matches!(param.kind, GenericParamKind::Lifetime)) {
-        return Err(sd.span_err(
+        return Err(dcx.span_err(
             i.span,
             "functions used as tests can not have any non-lifetime generic parameters",
         ));
@@ -601,7 +601,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.diagnostic().emit_err(errors::BenchSig { span: i.span }));
+        return Err(cx.sess.dcx().emit_err(errors::BenchSig { span: i.span }));
     }
     Ok(())
 }
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index c5daf17abb9..dc28cd2ea31 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -47,7 +47,7 @@ pub fn inject(
     features: &Features,
     resolver: &mut dyn ResolverExpand,
 ) {
-    let span_diagnostic = sess.diagnostic();
+    let dcx = sess.dcx();
     let panic_strategy = sess.panic_strategy();
     let platform_panic_strategy = sess.target.panic_strategy;
 
@@ -60,7 +60,7 @@ pub fn inject(
 
     // Do this here so that the test_runner crate attribute gets marked as used
     // even in non-test builds
-    let test_runner = get_test_runner(span_diagnostic, krate);
+    let test_runner = get_test_runner(dcx, krate);
 
     if sess.is_test_crate() {
         let panic_strategy = match (panic_strategy, sess.opts.unstable_opts.panic_abort_tests) {
@@ -70,7 +70,7 @@ pub fn inject(
                     // Silently allow compiling with panic=abort on these platforms,
                     // but with old behavior (abort if a test fails).
                 } else {
-                    span_diagnostic.emit_err(errors::TestsNotSupport {});
+                    dcx.emit_err(errors::TestsNotSupport {});
                 }
                 PanicStrategy::Unwind
             }
@@ -389,7 +389,7 @@ fn get_test_name(i: &ast::Item) -> Option<Symbol> {
     attr::first_attr_value_str_by_name(&i.attrs, sym::rustc_test_marker)
 }
 
-fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
+fn get_test_runner(dcx: &rustc_errors::DiagCtxt, krate: &ast::Crate) -> Option<ast::Path> {
     let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
     let meta_list = test_attr.meta_item_list()?;
     let span = test_attr.span;
@@ -397,11 +397,11 @@ fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast
         [single] => match single.meta_item() {
             Some(meta_item) if meta_item.is_word() => return Some(meta_item.path.clone()),
             _ => {
-                sd.emit_err(errors::TestRunnerInvalid { span });
+                dcx.emit_err(errors::TestRunnerInvalid { span });
             }
         },
         _ => {
-            sd.emit_err(errors::TestRunnerNargs { span });
+            dcx.emit_err(errors::TestRunnerNargs { span });
         }
     }
     None
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 71557d49ef2..8b0dc611075 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -176,10 +176,10 @@ pub(crate) fn compile_fn(
         match module.define_function(codegened_func.func_id, context) {
             Ok(()) => {}
             Err(ModuleError::Compilation(CodegenError::ImplLimitExceeded)) => {
-                let handler = rustc_session::EarlyErrorHandler::new(
+                let early_dcx = rustc_session::EarlyDiagCtxt::new(
                     rustc_session::config::ErrorOutputType::default(),
                 );
-                handler.early_error(format!(
+                early_dcx.early_error(format!(
                     "backend implementation limit exceeded while compiling {name}",
                     name = codegened_func.symbol_name
                 ));
diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
index 978891f2b0d..9678969134a 100644
--- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
+++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
@@ -46,7 +46,7 @@ impl ConcurrencyLimiter {
         }
     }
 
-    pub(super) fn acquire(&mut self, handler: &rustc_errors::Handler) -> ConcurrencyLimiterToken {
+    pub(super) fn acquire(&mut self, dcx: &rustc_errors::DiagCtxt) -> ConcurrencyLimiterToken {
         let mut state = self.state.lock().unwrap();
         loop {
             state.assert_invariants();
@@ -64,7 +64,7 @@ impl ConcurrencyLimiter {
                     // Make sure to drop the mutex guard first to prevent poisoning the mutex.
                     drop(state);
                     if let Some(err) = err {
-                        handler.fatal(err);
+                        dcx.fatal(err);
                     } else {
                         // The error was already emitted, but compilation continued. Raise a silent
                         // fatal error.
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 11229dd421e..b3ab533df3d 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -422,7 +422,7 @@ pub(crate) fn run_aot(
                                     backend_config.clone(),
                                     global_asm_config.clone(),
                                     cgu.name(),
-                                    concurrency_limiter.acquire(tcx.sess.diagnostic()),
+                                    concurrency_limiter.acquire(tcx.sess.dcx()),
                                 ),
                                 module_codegen,
                                 Some(rustc_middle::dep_graph::hash_result),
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index 02c0dcb8b1b..196418023d9 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -231,9 +231,8 @@ pub(crate) fn write_ir_file(
     let res = std::fs::File::create(clif_file_name).and_then(|mut file| write(&mut file));
     if let Err(err) = res {
         // Using early_warn as no Session is available here
-        let handler = rustc_session::EarlyErrorHandler::new(
-            rustc_session::config::ErrorOutputType::default(),
-        );
+        let handler =
+            rustc_session::EarlyDiagCtxt::new(rustc_session::config::ErrorOutputType::default());
         handler.early_warn(format!("error writing ir file: {}", err));
     }
 }
diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs
index 529454b119e..c21b7686823 100644
--- a/compiler/rustc_codegen_gcc/src/back/lto.rs
+++ b/compiler/rustc_codegen_gcc/src/back/lto.rs
@@ -30,7 +30,7 @@ use rustc_codegen_ssa::back::write::{CodegenContext, FatLtoInput};
 use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
 use rustc_data_structures::memmap::Mmap;
-use rustc_errors::{FatalError, Handler};
+use rustc_errors::{FatalError, DiagCtxt};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::dep_graph::WorkProduct;
 use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel};
@@ -61,7 +61,7 @@ struct LtoData {
     tmp_path: TempDir,
 }
 
-fn prepare_lto(cgcx: &CodegenContext<GccCodegenBackend>, diag_handler: &Handler) -> Result<LtoData, FatalError> {
+fn prepare_lto(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &DiagCtxt) -> Result<LtoData, FatalError> {
     let export_threshold = match cgcx.lto {
         // We're just doing LTO for our one crate
         Lto::ThinLocal => SymbolExportLevel::Rust,
@@ -106,18 +106,18 @@ fn prepare_lto(cgcx: &CodegenContext<GccCodegenBackend>, diag_handler: &Handler)
         // Make sure we actually can run LTO
         for crate_type in cgcx.crate_types.iter() {
             if !crate_type_allows_lto(*crate_type) {
-                diag_handler.emit_err(LtoDisallowed);
+                dcx.emit_err(LtoDisallowed);
                 return Err(FatalError);
             } else if *crate_type == CrateType::Dylib {
                 if !cgcx.opts.unstable_opts.dylib_lto {
-                    diag_handler.emit_err(LtoDylib);
+                    dcx.emit_err(LtoDylib);
                     return Err(FatalError);
                 }
             }
         }
 
         if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
-            diag_handler.emit_err(DynamicLinkingWithLTO);
+            dcx.emit_err(DynamicLinkingWithLTO);
             return Err(FatalError);
         }
 
@@ -154,7 +154,7 @@ fn prepare_lto(cgcx: &CodegenContext<GccCodegenBackend>, diag_handler: &Handler)
                         upstream_modules.push((module, CString::new(name).unwrap()));
                     }
                     Err(e) => {
-                        diag_handler.emit_err(e);
+                        dcx.emit_err(e);
                         return Err(FatalError);
                     }
                 }
@@ -183,16 +183,16 @@ pub(crate) fn run_fat(
     modules: Vec<FatLtoInput<GccCodegenBackend>>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
 ) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> {
-    let diag_handler = cgcx.create_diag_handler();
-    let lto_data = prepare_lto(cgcx, &diag_handler)?;
+    let dcx = cgcx.create_dcx();
+    let lto_data = prepare_lto(cgcx, &dcx)?;
     /*let symbols_below_threshold =
         lto_data.symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();*/
-    fat_lto(cgcx, &diag_handler, modules, cached_modules, lto_data.upstream_modules, lto_data.tmp_path,
+    fat_lto(cgcx, &dcx, modules, cached_modules, lto_data.upstream_modules, lto_data.tmp_path,
         //&symbols_below_threshold,
     )
 }
 
-fn fat_lto(cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, modules: Vec<FatLtoInput<GccCodegenBackend>>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, tmp_path: TempDir,
+fn fat_lto(cgcx: &CodegenContext<GccCodegenBackend>, _dcx: &DiagCtxt, modules: Vec<FatLtoInput<GccCodegenBackend>>, cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>, mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>, tmp_path: TempDir,
     //symbols_below_threshold: &[*const libc::c_char],
 ) -> Result<LtoModuleCodegen<GccCodegenBackend>, FatalError> {
     let _timer = cgcx.prof.generic_activity("GCC_fat_lto_build_monolithic_module");
@@ -257,7 +257,7 @@ fn fat_lto(cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, mo
             let (buffer, name) = serialized_modules.remove(0);
             info!("no in-memory regular modules to choose from, parsing {:?}", name);
             ModuleCodegen {
-                module_llvm: GccContext::parse(cgcx, &name, buffer.data(), diag_handler)?,
+                module_llvm: GccContext::parse(cgcx, &name, buffer.data(), dcx)?,
                 name: name.into_string().unwrap(),
                 kind: ModuleKind::Regular,
             }*/
diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs
index 04772d7707a..2f8a54f529c 100644
--- a/compiler/rustc_codegen_gcc/src/back/write.rs
+++ b/compiler/rustc_codegen_gcc/src/back/write.rs
@@ -4,7 +4,7 @@ use gccjit::OutputKind;
 use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
 use rustc_codegen_ssa::back::link::ensure_removed;
 use rustc_codegen_ssa::back::write::{BitcodeSection, CodegenContext, EmitObj, ModuleConfig};
-use rustc_errors::Handler;
+use rustc_errors::DiagCtxt;
 use rustc_fs_util::link_or_copy;
 use rustc_session::config::OutputType;
 use rustc_span::fatal_error::FatalError;
@@ -13,7 +13,7 @@ use rustc_target::spec::SplitDebuginfo;
 use crate::{GccCodegenBackend, GccContext};
 use crate::errors::CopyBitcode;
 
-pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, diag_handler: &Handler, module: ModuleCodegen<GccContext>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
+pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, dcx: &DiagCtxt, module: ModuleCodegen<GccContext>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
     let _timer = cgcx.prof.generic_activity_with_arg("GCC_module_codegen", &*module.name);
     {
         let context = &module.module_llvm.context;
@@ -127,12 +127,12 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, diag_hand
             EmitObj::Bitcode => {
                 debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
                 if let Err(err) = link_or_copy(&bc_out, &obj_out) {
-                    diag_handler.emit_err(CopyBitcode { err });
+                    dcx.emit_err(CopyBitcode { err });
                 }
 
                 if !config.emit_bc {
                     debug!("removing_bitcode {:?}", bc_out);
-                    ensure_removed(diag_handler, &bc_out);
+                    ensure_removed(dcx, &bc_out);
                 }
             }
 
@@ -148,7 +148,7 @@ pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, diag_hand
     ))
 }
 
-pub(crate) fn link(_cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, mut _modules: Vec<ModuleCodegen<GccContext>>) -> Result<ModuleCodegen<GccContext>, FatalError> {
+pub(crate) fn link(_cgcx: &CodegenContext<GccCodegenBackend>, _dcx: &DiagCtxt, mut _modules: Vec<ModuleCodegen<GccContext>>) -> Result<ModuleCodegen<GccContext>, FatalError> {
     unimplemented!();
 }
 
diff --git a/compiler/rustc_codegen_gcc/src/errors.rs b/compiler/rustc_codegen_gcc/src/errors.rs
index 5fc4b12d7e6..766d90cf724 100644
--- a/compiler/rustc_codegen_gcc/src/errors.rs
+++ b/compiler/rustc_codegen_gcc/src/errors.rs
@@ -1,5 +1,6 @@
 use rustc_errors::{
-    DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, IntoDiagnosticArg,
+    DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
+    IntoDiagnosticArg,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::Span;
@@ -111,8 +112,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> {
 pub(crate) struct MissingFeatures;
 
 impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
-    fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable);
+    fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = dcx.struct_err(fluent::codegen_gcc_target_feature_disable_or_enable);
         if let Some(span) = self.span {
             diag.set_span(span);
         };
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 0ececc5dda0..1f3f909d8b4 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -100,7 +100,7 @@ use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModul
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::sync::IntoDynSyncSend;
 use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods};
-use rustc_errors::{ErrorGuaranteed, Handler};
+use rustc_errors::{ErrorGuaranteed, DiagCtxt};
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::util::Providers;
@@ -330,7 +330,7 @@ impl WriteBackendMethods for GccCodegenBackend {
         unimplemented!()
     }
 
-    unsafe fn optimize(_cgcx: &CodegenContext<Self>, _diag_handler: &Handler, module: &ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<(), FatalError> {
+    unsafe fn optimize(_cgcx: &CodegenContext<Self>, _dcx: &DiagCtxt, module: &ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<(), FatalError> {
         module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level));
         Ok(())
     }
@@ -344,8 +344,8 @@ impl WriteBackendMethods for GccCodegenBackend {
         unimplemented!();
     }
 
-    unsafe fn codegen(cgcx: &CodegenContext<Self>, diag_handler: &Handler, module: ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
-        back::write::codegen(cgcx, diag_handler, module, config)
+    unsafe fn codegen(cgcx: &CodegenContext<Self>, dcx: &DiagCtxt, module: ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
+        back::write::codegen(cgcx, dcx, module, config)
     }
 
     fn prepare_thin(_module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
@@ -356,8 +356,8 @@ impl WriteBackendMethods for GccCodegenBackend {
         unimplemented!();
     }
 
-    fn run_link(cgcx: &CodegenContext<Self>, diag_handler: &Handler, modules: Vec<ModuleCodegen<Self::Module>>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
-        back::write::link(cgcx, diag_handler, modules)
+    fn run_link(cgcx: &CodegenContext<Self>, dcx: &DiagCtxt, modules: Vec<ModuleCodegen<Self::Module>>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+        back::write::link(cgcx, dcx, modules)
     }
 }
 
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index c9e109a5d23..e9e8ade09b7 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -14,7 +14,7 @@ use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{looks_like_rust_object_file, ModuleCodegen, ModuleKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::memmap::Mmap;
-use rustc_errors::{FatalError, Handler};
+use rustc_errors::{DiagCtxt, FatalError};
 use rustc_hir::def_id::LOCAL_CRATE;
 use rustc_middle::bug;
 use rustc_middle::dep_graph::WorkProduct;
@@ -47,7 +47,7 @@ pub fn crate_type_allows_lto(crate_type: CrateType) -> bool {
 
 fn prepare_lto(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
-    diag_handler: &Handler,
+    dcx: &DiagCtxt,
 ) -> Result<(Vec<CString>, Vec<(SerializedModule<ModuleBuffer>, CString)>), FatalError> {
     let export_threshold = match cgcx.lto {
         // We're just doing LTO for our one crate
@@ -84,23 +84,23 @@ fn prepare_lto(
         // Make sure we actually can run LTO
         for crate_type in cgcx.crate_types.iter() {
             if !crate_type_allows_lto(*crate_type) {
-                diag_handler.emit_err(LtoDisallowed);
+                dcx.emit_err(LtoDisallowed);
                 return Err(FatalError);
             } else if *crate_type == CrateType::Dylib {
                 if !cgcx.opts.unstable_opts.dylib_lto {
-                    diag_handler.emit_err(LtoDylib);
+                    dcx.emit_err(LtoDylib);
                     return Err(FatalError);
                 }
             } else if *crate_type == CrateType::ProcMacro {
                 if !cgcx.opts.unstable_opts.dylib_lto {
-                    diag_handler.emit_err(LtoProcMacro);
+                    dcx.emit_err(LtoProcMacro);
                     return Err(FatalError);
                 }
             }
         }
 
         if cgcx.opts.cg.prefer_dynamic && !cgcx.opts.unstable_opts.dylib_lto {
-            diag_handler.emit_err(DynamicLinkingWithLTO);
+            dcx.emit_err(DynamicLinkingWithLTO);
             return Err(FatalError);
         }
 
@@ -138,7 +138,7 @@ fn prepare_lto(
                         upstream_modules.push((module, CString::new(name).unwrap()));
                     }
                     Err(e) => {
-                        diag_handler.emit_err(e);
+                        dcx.emit_err(e);
                         return Err(FatalError);
                     }
                 }
@@ -200,18 +200,11 @@ pub(crate) fn run_fat(
     modules: Vec<FatLtoInput<LlvmCodegenBackend>>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
 ) -> Result<LtoModuleCodegen<LlvmCodegenBackend>, FatalError> {
-    let diag_handler = cgcx.create_diag_handler();
-    let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, &diag_handler)?;
+    let dcx = cgcx.create_dcx();
+    let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, &dcx)?;
     let symbols_below_threshold =
         symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
-    fat_lto(
-        cgcx,
-        &diag_handler,
-        modules,
-        cached_modules,
-        upstream_modules,
-        &symbols_below_threshold,
-    )
+    fat_lto(cgcx, &dcx, modules, cached_modules, upstream_modules, &symbols_below_threshold)
 }
 
 /// Performs thin LTO by performing necessary global analysis and returning two
@@ -222,8 +215,8 @@ pub(crate) fn run_thin(
     modules: Vec<(String, ThinBuffer)>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
 ) -> Result<(Vec<LtoModuleCodegen<LlvmCodegenBackend>>, Vec<WorkProduct>), FatalError> {
-    let diag_handler = cgcx.create_diag_handler();
-    let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, &diag_handler)?;
+    let dcx = cgcx.create_dcx();
+    let (symbols_below_threshold, upstream_modules) = prepare_lto(cgcx, &dcx)?;
     let symbols_below_threshold =
         symbols_below_threshold.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
     if cgcx.opts.cg.linker_plugin_lto.enabled() {
@@ -232,14 +225,7 @@ pub(crate) fn run_thin(
                       is deferred to the linker"
         );
     }
-    thin_lto(
-        cgcx,
-        &diag_handler,
-        modules,
-        upstream_modules,
-        cached_modules,
-        &symbols_below_threshold,
-    )
+    thin_lto(cgcx, &dcx, modules, upstream_modules, cached_modules, &symbols_below_threshold)
 }
 
 pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBuffer) {
@@ -250,7 +236,7 @@ pub(crate) fn prepare_thin(module: ModuleCodegen<ModuleLlvm>) -> (String, ThinBu
 
 fn fat_lto(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
-    diag_handler: &Handler,
+    dcx: &DiagCtxt,
     modules: Vec<FatLtoInput<LlvmCodegenBackend>>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
     mut serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
@@ -316,7 +302,7 @@ fn fat_lto(
             let (buffer, name) = serialized_modules.remove(0);
             info!("no in-memory regular modules to choose from, parsing {:?}", name);
             ModuleCodegen {
-                module_llvm: ModuleLlvm::parse(cgcx, &name, buffer.data(), diag_handler)?,
+                module_llvm: ModuleLlvm::parse(cgcx, &name, buffer.data(), dcx)?,
                 name: name.into_string().unwrap(),
                 kind: ModuleKind::Regular,
             }
@@ -333,13 +319,8 @@ fn fat_lto(
         // The linking steps below may produce errors and diagnostics within LLVM
         // which we'd like to handle and print, so set up our diagnostic handlers
         // (which get unregistered when they go out of scope below).
-        let _handler = DiagnosticHandlers::new(
-            cgcx,
-            diag_handler,
-            llcx,
-            &module,
-            CodegenDiagnosticsStage::LTO,
-        );
+        let _handler =
+            DiagnosticHandlers::new(cgcx, dcx, llcx, &module, CodegenDiagnosticsStage::LTO);
 
         // For all other modules we codegened we'll need to link them into our own
         // bitcode. All modules were codegened in their own LLVM context, however,
@@ -367,9 +348,7 @@ fn fat_lto(
                 });
             info!("linking {:?}", name);
             let data = bc_decoded.data();
-            linker
-                .add(data)
-                .map_err(|()| write::llvm_err(diag_handler, LlvmError::LoadBitcode { name }))?;
+            linker.add(data).map_err(|()| write::llvm_err(dcx, LlvmError::LoadBitcode { name }))?;
             serialized_bitcode.push(bc_decoded);
         }
         drop(linker);
@@ -452,7 +431,7 @@ impl Drop for Linker<'_> {
 /// they all go out of scope.
 fn thin_lto(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
-    diag_handler: &Handler,
+    dcx: &DiagCtxt,
     modules: Vec<(String, ThinBuffer)>,
     serialized_modules: Vec<(SerializedModule<ModuleBuffer>, CString)>,
     cached_modules: Vec<(SerializedModule<ModuleBuffer>, WorkProduct)>,
@@ -527,7 +506,7 @@ fn thin_lto(
             symbols_below_threshold.as_ptr(),
             symbols_below_threshold.len() as u32,
         )
-        .ok_or_else(|| write::llvm_err(diag_handler, LlvmError::PrepareThinLtoContext))?;
+        .ok_or_else(|| write::llvm_err(dcx, LlvmError::PrepareThinLtoContext))?;
 
         let data = ThinData(data);
 
@@ -599,7 +578,7 @@ fn thin_lto(
         // session, overwriting the previous serialized data (if any).
         if let Some(path) = key_map_path {
             if let Err(err) = curr_key_map.save_to_file(&path) {
-                return Err(write::llvm_err(diag_handler, LlvmError::WriteThinLtoKey { err }));
+                return Err(write::llvm_err(dcx, LlvmError::WriteThinLtoKey { err }));
             }
         }
 
@@ -609,7 +588,7 @@ fn thin_lto(
 
 pub(crate) fn run_pass_manager(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
-    diag_handler: &Handler,
+    dcx: &DiagCtxt,
     module: &mut ModuleCodegen<ModuleLlvm>,
     thin: bool,
 ) -> Result<(), FatalError> {
@@ -637,7 +616,7 @@ pub(crate) fn run_pass_manager(
         }
         let opt_stage = if thin { llvm::OptStage::ThinLTO } else { llvm::OptStage::FatLTO };
         let opt_level = config.opt_level.unwrap_or(config::OptLevel::No);
-        write::llvm_optimize(cgcx, diag_handler, module, config, opt_level, opt_stage)?;
+        write::llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage)?;
     }
     debug!("lto done");
     Ok(())
@@ -721,11 +700,11 @@ pub unsafe fn optimize_thin_module(
     thin_module: ThinModule<LlvmCodegenBackend>,
     cgcx: &CodegenContext<LlvmCodegenBackend>,
 ) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
-    let diag_handler = cgcx.create_diag_handler();
+    let dcx = cgcx.create_dcx();
 
     let module_name = &thin_module.shared.module_names[thin_module.idx];
     let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, module_name.to_str().unwrap());
-    let tm = (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&diag_handler, e))?;
+    let tm = (cgcx.tm_factory)(tm_factory_config).map_err(|e| write::llvm_err(&dcx, e))?;
 
     // Right now the implementation we've got only works over serialized
     // modules, so we create a fresh new LLVM context and parse the module
@@ -733,7 +712,7 @@ pub unsafe fn optimize_thin_module(
     // crates but for locally codegened modules we may be able to reuse
     // that LLVM Context and Module.
     let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
-    let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &diag_handler)? as *const _;
+    let llmod_raw = parse_module(llcx, module_name, thin_module.data(), &dcx)? as *const _;
     let mut module = ModuleCodegen {
         module_llvm: ModuleLlvm { llmod_raw, llcx, tm: ManuallyDrop::new(tm) },
         name: thin_module.name().to_string(),
@@ -756,7 +735,7 @@ pub unsafe fn optimize_thin_module(
             let _timer =
                 cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_rename", thin_module.name());
             if !llvm::LLVMRustPrepareThinLTORename(thin_module.shared.data.0, llmod, target) {
-                return Err(write::llvm_err(&diag_handler, LlvmError::PrepareThinLtoModule));
+                return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule));
             }
             save_temp_bitcode(cgcx, &module, "thin-lto-after-rename");
         }
@@ -766,7 +745,7 @@ pub unsafe fn optimize_thin_module(
                 .prof
                 .generic_activity_with_arg("LLVM_thin_lto_resolve_weak", thin_module.name());
             if !llvm::LLVMRustPrepareThinLTOResolveWeak(thin_module.shared.data.0, llmod) {
-                return Err(write::llvm_err(&diag_handler, LlvmError::PrepareThinLtoModule));
+                return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule));
             }
             save_temp_bitcode(cgcx, &module, "thin-lto-after-resolve");
         }
@@ -776,7 +755,7 @@ pub unsafe fn optimize_thin_module(
                 .prof
                 .generic_activity_with_arg("LLVM_thin_lto_internalize", thin_module.name());
             if !llvm::LLVMRustPrepareThinLTOInternalize(thin_module.shared.data.0, llmod) {
-                return Err(write::llvm_err(&diag_handler, LlvmError::PrepareThinLtoModule));
+                return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule));
             }
             save_temp_bitcode(cgcx, &module, "thin-lto-after-internalize");
         }
@@ -785,7 +764,7 @@ pub unsafe fn optimize_thin_module(
             let _timer =
                 cgcx.prof.generic_activity_with_arg("LLVM_thin_lto_import", thin_module.name());
             if !llvm::LLVMRustPrepareThinLTOImport(thin_module.shared.data.0, llmod, target) {
-                return Err(write::llvm_err(&diag_handler, LlvmError::PrepareThinLtoModule));
+                return Err(write::llvm_err(&dcx, LlvmError::PrepareThinLtoModule));
             }
             save_temp_bitcode(cgcx, &module, "thin-lto-after-import");
         }
@@ -797,7 +776,7 @@ pub unsafe fn optimize_thin_module(
         // little differently.
         {
             info!("running thin lto passes over {}", module.name);
-            run_pass_manager(cgcx, &diag_handler, &mut module, true)?;
+            run_pass_manager(cgcx, &dcx, &mut module, true)?;
             save_temp_bitcode(cgcx, &module, "thin-lto-after-pm");
         }
     }
@@ -868,10 +847,10 @@ pub fn parse_module<'a>(
     cx: &'a llvm::Context,
     name: &CStr,
     data: &[u8],
-    diag_handler: &Handler,
+    dcx: &DiagCtxt,
 ) -> Result<&'a llvm::Module, FatalError> {
     unsafe {
         llvm::LLVMRustParseBitcodeForLTO(cx, data.as_ptr(), data.len(), name.as_ptr())
-            .ok_or_else(|| write::llvm_err(diag_handler, LlvmError::ParseBitcode))
+            .ok_or_else(|| write::llvm_err(dcx, LlvmError::ParseBitcode))
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 048f66ad148..75f99f964d0 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -26,7 +26,7 @@ use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::small_c_str::SmallCStr;
-use rustc_errors::{FatalError, Handler, Level};
+use rustc_errors::{DiagCtxt, FatalError, Level};
 use rustc_fs_util::{link_or_copy, path_to_c_string};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{self, Lto, OutputType, Passes, SplitDwarfKind, SwitchWithOptPath};
@@ -45,15 +45,15 @@ use std::slice;
 use std::str;
 use std::sync::Arc;
 
-pub fn llvm_err<'a>(handler: &rustc_errors::Handler, err: LlvmError<'a>) -> FatalError {
+pub fn llvm_err<'a>(dcx: &rustc_errors::DiagCtxt, err: LlvmError<'a>) -> FatalError {
     match llvm::last_error() {
-        Some(llvm_err) => handler.emit_almost_fatal(WithLlvmError(err, llvm_err)),
-        None => handler.emit_almost_fatal(err),
+        Some(llvm_err) => dcx.emit_almost_fatal(WithLlvmError(err, llvm_err)),
+        None => dcx.emit_almost_fatal(err),
     }
 }
 
 pub fn write_output_file<'ll>(
-    handler: &rustc_errors::Handler,
+    dcx: &rustc_errors::DiagCtxt,
     target: &'ll llvm::TargetMachine,
     pm: &llvm::PassManager<'ll>,
     m: &'ll llvm::Module,
@@ -93,9 +93,7 @@ pub fn write_output_file<'ll>(
             }
         }
 
-        result
-            .into_result()
-            .map_err(|()| llvm_err(handler, LlvmError::WriteOutput { path: output }))
+        result.into_result().map_err(|()| llvm_err(dcx, LlvmError::WriteOutput { path: output }))
     }
 }
 
@@ -105,7 +103,7 @@ pub fn create_informational_target_machine(sess: &Session) -> OwnedTargetMachine
     // system/tcx is set up.
     let features = llvm_util::global_llvm_features(sess, false);
     target_machine_factory(sess, config::OptLevel::No, &features)(config)
-        .unwrap_or_else(|err| llvm_err(sess.diagnostic(), err).raise())
+        .unwrap_or_else(|err| llvm_err(sess.dcx(), err).raise())
 }
 
 pub fn create_target_machine(tcx: TyCtxt<'_>, mod_name: &str) -> OwnedTargetMachine {
@@ -128,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.diagnostic(), err).raise())
+    .unwrap_or_else(|err| llvm_err(tcx.sess.dcx(), err).raise())
 }
 
 pub fn to_llvm_opt_settings(
@@ -332,7 +330,7 @@ pub enum CodegenDiagnosticsStage {
 }
 
 pub struct DiagnosticHandlers<'a> {
-    data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a Handler),
+    data: *mut (&'a CodegenContext<LlvmCodegenBackend>, &'a DiagCtxt),
     llcx: &'a llvm::Context,
     old_handler: Option<&'a llvm::DiagnosticHandler>,
 }
@@ -340,7 +338,7 @@ pub struct DiagnosticHandlers<'a> {
 impl<'a> DiagnosticHandlers<'a> {
     pub fn new(
         cgcx: &'a CodegenContext<LlvmCodegenBackend>,
-        handler: &'a Handler,
+        dcx: &'a DiagCtxt,
         llcx: &'a llvm::Context,
         module: &ModuleCodegen<ModuleLlvm>,
         stage: CodegenDiagnosticsStage,
@@ -375,7 +373,7 @@ impl<'a> DiagnosticHandlers<'a> {
             .and_then(|dir| dir.to_str().and_then(|p| CString::new(p).ok()));
 
         let pgo_available = cgcx.opts.cg.profile_use.is_some();
-        let data = Box::into_raw(Box::new((cgcx, handler)));
+        let data = Box::into_raw(Box::new((cgcx, dcx)));
         unsafe {
             let old_handler = llvm::LLVMRustContextGetDiagnosticHandler(llcx);
             llvm::LLVMRustContextConfigureDiagnosticHandler(
@@ -429,7 +427,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
     if user.is_null() {
         return;
     }
-    let (cgcx, diag_handler) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &Handler));
+    let (cgcx, dcx) = *(user as *const (&CodegenContext<LlvmCodegenBackend>, &DiagCtxt));
 
     match llvm::diagnostic::Diagnostic::unpack(info) {
         llvm::diagnostic::InlineAsm(inline) => {
@@ -437,7 +435,7 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
         }
 
         llvm::diagnostic::Optimization(opt) => {
-            diag_handler.emit_note(FromLlvmOptimizationDiag {
+            dcx.emit_note(FromLlvmOptimizationDiag {
                 filename: &opt.filename,
                 line: opt.line,
                 column: opt.column,
@@ -459,14 +457,14 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
                 llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
             })
             .expect("non-UTF8 diagnostic");
-            diag_handler.emit_warning(FromLlvmDiag { message });
+            dcx.emit_warning(FromLlvmDiag { message });
         }
         llvm::diagnostic::Unsupported(diagnostic_ref) => {
             let message = llvm::build_string(|s| {
                 llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s)
             })
             .expect("non-UTF8 diagnostic");
-            diag_handler.emit_err(FromLlvmDiag { message });
+            dcx.emit_err(FromLlvmDiag { message });
         }
         llvm::diagnostic::UnknownDiagnostic(..) => {}
     }
@@ -507,7 +505,7 @@ fn get_instr_profile_output_path(config: &ModuleConfig) -> Option<CString> {
 
 pub(crate) unsafe fn llvm_optimize(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
-    diag_handler: &Handler,
+    dcx: &DiagCtxt,
     module: &ModuleCodegen<ModuleLlvm>,
     config: &ModuleConfig,
     opt_level: config::OptLevel,
@@ -588,13 +586,13 @@ pub(crate) unsafe fn llvm_optimize(
         llvm_plugins.as_ptr().cast(),
         llvm_plugins.len(),
     );
-    result.into_result().map_err(|()| llvm_err(diag_handler, LlvmError::RunLlvmPasses))
+    result.into_result().map_err(|()| llvm_err(dcx, LlvmError::RunLlvmPasses))
 }
 
 // Unsafe due to LLVM calls.
 pub(crate) unsafe fn optimize(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
-    diag_handler: &Handler,
+    dcx: &DiagCtxt,
     module: &ModuleCodegen<ModuleLlvm>,
     config: &ModuleConfig,
 ) -> Result<(), FatalError> {
@@ -602,8 +600,7 @@ pub(crate) unsafe fn optimize(
 
     let llmod = module.module_llvm.llmod();
     let llcx = &*module.module_llvm.llcx;
-    let _handlers =
-        DiagnosticHandlers::new(cgcx, diag_handler, llcx, module, CodegenDiagnosticsStage::Opt);
+    let _handlers = DiagnosticHandlers::new(cgcx, dcx, llcx, module, CodegenDiagnosticsStage::Opt);
 
     let module_name = module.name.clone();
     let module_name = Some(&module_name[..]);
@@ -621,14 +618,14 @@ pub(crate) unsafe fn optimize(
             _ if cgcx.opts.cg.linker_plugin_lto.enabled() => llvm::OptStage::PreLinkThinLTO,
             _ => llvm::OptStage::PreLinkNoLTO,
         };
-        return llvm_optimize(cgcx, diag_handler, module, config, opt_level, opt_stage);
+        return llvm_optimize(cgcx, dcx, module, config, opt_level, opt_stage);
     }
     Ok(())
 }
 
 pub(crate) fn link(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
-    diag_handler: &Handler,
+    dcx: &DiagCtxt,
     mut modules: Vec<ModuleCodegen<ModuleLlvm>>,
 ) -> Result<ModuleCodegen<ModuleLlvm>, FatalError> {
     use super::lto::{Linker, ModuleBuffer};
@@ -641,9 +638,9 @@ pub(crate) fn link(
     for module in elements {
         let _timer = cgcx.prof.generic_activity_with_arg("LLVM_link_module", &*module.name);
         let buffer = ModuleBuffer::new(module.module_llvm.llmod());
-        linker.add(buffer.data()).map_err(|()| {
-            llvm_err(diag_handler, LlvmError::SerializeModule { name: &module.name })
-        })?;
+        linker
+            .add(buffer.data())
+            .map_err(|()| llvm_err(dcx, LlvmError::SerializeModule { name: &module.name }))?;
     }
     drop(linker);
     Ok(modules.remove(0))
@@ -651,7 +648,7 @@ pub(crate) fn link(
 
 pub(crate) unsafe fn codegen(
     cgcx: &CodegenContext<LlvmCodegenBackend>,
-    diag_handler: &Handler,
+    dcx: &DiagCtxt,
     module: ModuleCodegen<ModuleLlvm>,
     config: &ModuleConfig,
 ) -> Result<CompiledModule, FatalError> {
@@ -662,13 +659,8 @@ pub(crate) unsafe fn codegen(
         let tm = &*module.module_llvm.tm;
         let module_name = module.name.clone();
         let module_name = Some(&module_name[..]);
-        let _handlers = DiagnosticHandlers::new(
-            cgcx,
-            diag_handler,
-            llcx,
-            &module,
-            CodegenDiagnosticsStage::Codegen,
-        );
+        let _handlers =
+            DiagnosticHandlers::new(cgcx, dcx, llcx, &module, CodegenDiagnosticsStage::Codegen);
 
         if cgcx.msvc_imps_needed {
             create_msvc_imps(cgcx, llcx, llmod);
@@ -726,7 +718,7 @@ pub(crate) unsafe fn codegen(
                     .prof
                     .generic_activity_with_arg("LLVM_module_codegen_emit_bitcode", &*module.name);
                 if let Err(err) = fs::write(&bc_out, data) {
-                    diag_handler.emit_err(WriteBytecode { path: &bc_out, err });
+                    dcx.emit_err(WriteBytecode { path: &bc_out, err });
                 }
             }
 
@@ -776,9 +768,7 @@ pub(crate) unsafe fn codegen(
                 record_artifact_size(&cgcx.prof, "llvm_ir", &out);
             }
 
-            result
-                .into_result()
-                .map_err(|()| llvm_err(diag_handler, LlvmError::WriteIr { path: &out }))?;
+            result.into_result().map_err(|()| llvm_err(dcx, LlvmError::WriteIr { path: &out }))?;
         }
 
         if config.emit_asm {
@@ -797,7 +787,7 @@ pub(crate) unsafe fn codegen(
             };
             with_codegen(tm, llmod, |cpm| {
                 write_output_file(
-                    diag_handler,
+                    dcx,
                     tm,
                     cpm,
                     llmod,
@@ -832,7 +822,7 @@ pub(crate) unsafe fn codegen(
 
                 with_codegen(tm, llmod, |cpm| {
                     write_output_file(
-                        diag_handler,
+                        dcx,
                         tm,
                         cpm,
                         llmod,
@@ -847,12 +837,12 @@ pub(crate) unsafe fn codegen(
             EmitObj::Bitcode => {
                 debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
                 if let Err(err) = link_or_copy(&bc_out, &obj_out) {
-                    diag_handler.emit_err(CopyBitcode { err });
+                    dcx.emit_err(CopyBitcode { err });
                 }
 
                 if !config.emit_bc {
                     debug!("removing_bitcode {:?}", bc_out);
-                    ensure_removed(diag_handler, &bc_out);
+                    ensure_removed(dcx, &bc_out);
                 }
             }
 
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index e6e37a02335..671a225259a 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -5,7 +5,7 @@ use std::path::Path;
 use crate::fluent_generated as fluent;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_errors::{
-    DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, FatalError, Handler, IntoDiagnostic,
+    DiagCtxt, DiagnosticBuilder, EmissionGuarantee, ErrorGuaranteed, FatalError, IntoDiagnostic,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_span::Span;
@@ -102,13 +102,12 @@ pub(crate) struct DynamicLinkingWithLTO;
 pub(crate) struct ParseTargetMachineConfig<'a>(pub LlvmError<'a>);
 
 impl IntoDiagnostic<'_, FatalError> for ParseTargetMachineConfig<'_> {
-    fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, FatalError> {
-        let diag: DiagnosticBuilder<'_, FatalError> = self.0.into_diagnostic(handler);
+    fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, FatalError> {
+        let diag: DiagnosticBuilder<'_, FatalError> = self.0.into_diagnostic(dcx);
         let (message, _) = diag.styled_message().first().expect("`LlvmError` with no message");
-        let message = handler.eagerly_translate_to_string(message.clone(), diag.args());
+        let message = dcx.eagerly_translate_to_string(message.clone(), diag.args());
 
-        let mut diag =
-            handler.struct_almost_fatal(fluent::codegen_llvm_parse_target_machine_config);
+        let mut diag = dcx.struct_almost_fatal(fluent::codegen_llvm_parse_target_machine_config);
         diag.set_arg("error", message);
         diag
     }
@@ -125,8 +124,8 @@ pub(crate) struct TargetFeatureDisableOrEnable<'a> {
 pub(crate) struct MissingFeatures;
 
 impl IntoDiagnostic<'_, ErrorGuaranteed> for TargetFeatureDisableOrEnable<'_> {
-    fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable);
+    fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = dcx.struct_err(fluent::codegen_llvm_target_feature_disable_or_enable);
         if let Some(span) = self.span {
             diag.set_span(span);
         };
@@ -185,7 +184,7 @@ pub enum LlvmError<'a> {
 pub(crate) struct WithLlvmError<'a>(pub LlvmError<'a>, pub String);
 
 impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for WithLlvmError<'_> {
-    fn into_diagnostic(self, handler: &'_ Handler) -> DiagnosticBuilder<'_, G> {
+    fn into_diagnostic(self, dcx: &'_ DiagCtxt) -> DiagnosticBuilder<'_, G> {
         use LlvmError::*;
         let msg_with_llvm_err = match &self.0 {
             WriteOutput { .. } => fluent::codegen_llvm_write_output_with_llvm_err,
@@ -202,7 +201,7 @@ impl<G: EmissionGuarantee> IntoDiagnostic<'_, G> for WithLlvmError<'_> {
             PrepareThinLtoModule => fluent::codegen_llvm_prepare_thin_lto_module_with_llvm_err,
             ParseBitcode => fluent::codegen_llvm_parse_bitcode_with_llvm_err,
         };
-        let mut diag = self.0.into_diagnostic(handler);
+        let mut diag = self.0.into_diagnostic(dcx);
         diag.set_primary_message(msg_with_llvm_err);
         diag.set_arg("llvm_err", self.1);
         diag
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index dfef2fbab56..3c42eb21d07 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -40,7 +40,7 @@ use rustc_codegen_ssa::traits::*;
 use rustc_codegen_ssa::ModuleCodegen;
 use rustc_codegen_ssa::{CodegenResults, CompiledModule};
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_errors::{ErrorGuaranteed, FatalError, Handler};
+use rustc_errors::{DiagCtxt, ErrorGuaranteed, FatalError};
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
 use rustc_middle::ty::TyCtxt;
@@ -200,10 +200,10 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     }
     fn run_link(
         cgcx: &CodegenContext<Self>,
-        diag_handler: &Handler,
+        dcx: &DiagCtxt,
         modules: Vec<ModuleCodegen<Self::Module>>,
     ) -> Result<ModuleCodegen<Self::Module>, FatalError> {
-        back::write::link(cgcx, diag_handler, modules)
+        back::write::link(cgcx, dcx, modules)
     }
     fn run_fat_lto(
         cgcx: &CodegenContext<Self>,
@@ -221,18 +221,18 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     }
     unsafe fn optimize(
         cgcx: &CodegenContext<Self>,
-        diag_handler: &Handler,
+        dcx: &DiagCtxt,
         module: &ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> Result<(), FatalError> {
-        back::write::optimize(cgcx, diag_handler, module, config)
+        back::write::optimize(cgcx, dcx, module, config)
     }
     fn optimize_fat(
         cgcx: &CodegenContext<Self>,
         module: &mut ModuleCodegen<Self::Module>,
     ) -> Result<(), FatalError> {
-        let diag_handler = cgcx.create_diag_handler();
-        back::lto::run_pass_manager(cgcx, &diag_handler, module, false)
+        let dcx = cgcx.create_dcx();
+        back::lto::run_pass_manager(cgcx, &dcx, module, false)
     }
     unsafe fn optimize_thin(
         cgcx: &CodegenContext<Self>,
@@ -242,11 +242,11 @@ impl WriteBackendMethods for LlvmCodegenBackend {
     }
     unsafe fn codegen(
         cgcx: &CodegenContext<Self>,
-        diag_handler: &Handler,
+        dcx: &DiagCtxt,
         module: ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> Result<CompiledModule, FatalError> {
-        back::write::codegen(cgcx, diag_handler, module, config)
+        back::write::codegen(cgcx, dcx, module, config)
     }
     fn prepare_thin(module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
         back::lto::prepare_thin(module)
@@ -447,16 +447,16 @@ impl ModuleLlvm {
         cgcx: &CodegenContext<LlvmCodegenBackend>,
         name: &CStr,
         buffer: &[u8],
-        handler: &Handler,
+        dcx: &DiagCtxt,
     ) -> Result<Self, FatalError> {
         unsafe {
             let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names);
-            let llmod_raw = back::lto::parse_module(llcx, name, buffer, handler)?;
+            let llmod_raw = back::lto::parse_module(llcx, name, buffer, dcx)?;
             let tm_factory_config = TargetMachineFactoryConfig::new(cgcx, name.to_str().unwrap());
             let tm = match (cgcx.tm_factory)(tm_factory_config) {
                 Ok(m) => m,
                 Err(e) => {
-                    return Err(handler.emit_almost_fatal(ParseTargetMachineConfig(e)));
+                    return Err(dcx.emit_almost_fatal(ParseTargetMachineConfig(e)));
                 }
             };
 
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 000b2748e4f..b32865a0518 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -4,7 +4,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::temp_dir::MaybeTempDir;
-use rustc_errors::{ErrorGuaranteed, Handler};
+use rustc_errors::{DiagCtxt, ErrorGuaranteed};
 use rustc_fs_util::{fix_windows_verbatim_for_gcc, try_canonicalize};
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc_metadata::find_native_static_library;
@@ -52,10 +52,10 @@ use std::path::{Path, PathBuf};
 use std::process::{ExitStatus, Output, Stdio};
 use std::{env, fmt, fs, io, mem, str};
 
-pub fn ensure_removed(diag_handler: &Handler, path: &Path) {
+pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) {
     if let Err(e) = fs::remove_file(path) {
         if e.kind() != io::ErrorKind::NotFound {
-            diag_handler.err(format!("failed to remove {}: {}", path.display(), e));
+            dcx.err(format!("failed to remove {}: {}", path.display(), e));
         }
     }
 }
@@ -143,7 +143,7 @@ pub fn link_binary<'a>(
                 }
             }
             if sess.opts.json_artifact_notifications {
-                sess.diagnostic().emit_artifact_notification(&out_filename, "link");
+                sess.dcx().emit_artifact_notification(&out_filename, "link");
             }
 
             if sess.prof.enabled() {
@@ -183,13 +183,13 @@ pub fn link_binary<'a>(
             |preserve_objects: bool, preserve_dwarf_objects: bool, module: &CompiledModule| {
                 if !preserve_objects {
                     if let Some(ref obj) = module.object {
-                        ensure_removed(sess.diagnostic(), obj);
+                        ensure_removed(sess.dcx(), obj);
                     }
                 }
 
                 if !preserve_dwarf_objects {
                     if let Some(ref dwo_obj) = module.dwarf_object {
-                        ensure_removed(sess.diagnostic(), dwo_obj);
+                        ensure_removed(sess.dcx(), dwo_obj);
                     }
                 }
             };
@@ -208,7 +208,7 @@ pub fn link_binary<'a>(
 
         // Remove the temporary files if output goes to stdout
         for temp in tempfiles_for_stdout_output {
-            ensure_removed(sess.diagnostic(), &temp);
+            ensure_removed(sess.dcx(), &temp);
         }
 
         // If no requested outputs require linking, then the object temporaries should
@@ -933,7 +933,7 @@ fn link_natively<'a>(
                     command: &cmd,
                     escaped_output,
                 };
-                sess.diagnostic().emit_err(err);
+                sess.dcx().emit_err(err);
                 // If MSVC's `link.exe` was expected but the return code
                 // is not a Microsoft LNK error then suggest a way to fix or
                 // install the Visual Studio build tools.
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 40fd8c5c1d6..0442bef8a44 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -14,7 +14,7 @@ use rustc_data_structures::memmap::Mmap;
 use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::Emitter;
-use rustc_errors::{translation::Translate, DiagnosticId, FatalError, Handler, Level};
+use rustc_errors::{translation::Translate, DiagCtxt, DiagnosticId, FatalError, Level};
 use rustc_errors::{DiagnosticMessage, Style};
 use rustc_fs_util::link_or_copy;
 use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
@@ -344,7 +344,7 @@ pub struct CodegenContext<B: WriteBackendMethods> {
     /// how to call the compiler with the same arguments.
     pub expanded_args: Vec<String>,
 
-    /// Handler to use for diagnostics produced during codegen.
+    /// Emitter to use for diagnostics produced during codegen.
     pub diag_emitter: SharedEmitter,
     /// LLVM optimizations for which we want to print remarks.
     pub remark: Passes,
@@ -359,8 +359,8 @@ pub struct CodegenContext<B: WriteBackendMethods> {
 }
 
 impl<B: WriteBackendMethods> CodegenContext<B> {
-    pub fn create_diag_handler(&self) -> Handler {
-        Handler::with_emitter(Box::new(self.diag_emitter.clone()))
+    pub fn create_dcx(&self) -> DiagCtxt {
+        DiagCtxt::with_emitter(Box::new(self.diag_emitter.clone()))
     }
 
     pub fn config(&self, kind: ModuleKind) -> &ModuleConfig {
@@ -558,7 +558,7 @@ fn produce_final_output_artifacts(
             }
             if !sess.opts.cg.save_temps && !keep_numbered {
                 // The user just wants `foo.x`, not `foo.#module-name#.x`.
-                ensure_removed(sess.diagnostic(), &path);
+                ensure_removed(sess.dcx(), &path);
             }
         } else {
             let extension = crate_output
@@ -649,19 +649,19 @@ fn produce_final_output_artifacts(
         for module in compiled_modules.modules.iter() {
             if let Some(ref path) = module.object {
                 if !keep_numbered_objects {
-                    ensure_removed(sess.diagnostic(), path);
+                    ensure_removed(sess.dcx(), path);
                 }
             }
 
             if let Some(ref path) = module.dwarf_object {
                 if !keep_numbered_objects {
-                    ensure_removed(sess.diagnostic(), path);
+                    ensure_removed(sess.dcx(), path);
                 }
             }
 
             if let Some(ref path) = module.bytecode {
                 if !keep_numbered_bitcode {
-                    ensure_removed(sess.diagnostic(), path);
+                    ensure_removed(sess.dcx(), path);
                 }
             }
         }
@@ -669,7 +669,7 @@ fn produce_final_output_artifacts(
         if !user_wants_bitcode {
             if let Some(ref allocator_module) = compiled_modules.allocator_module {
                 if let Some(ref path) = allocator_module.bytecode {
-                    ensure_removed(sess.diagnostic(), path);
+                    ensure_removed(sess.dcx(), path);
                 }
             }
         }
@@ -825,10 +825,10 @@ fn execute_optimize_work_item<B: ExtraBackendMethods>(
     module: ModuleCodegen<B::Module>,
     module_config: &ModuleConfig,
 ) -> Result<WorkItemResult<B>, FatalError> {
-    let diag_handler = cgcx.create_diag_handler();
+    let dcx = cgcx.create_dcx();
 
     unsafe {
-        B::optimize(cgcx, &diag_handler, &module, module_config)?;
+        B::optimize(cgcx, &dcx, &module, module_config)?;
     }
 
     // After we've done the initial round of optimizations we need to
@@ -891,11 +891,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
         match link_or_copy(&source_file, &output_path) {
             Ok(_) => Some(output_path),
             Err(error) => {
-                cgcx.create_diag_handler().emit_err(errors::CopyPathBuf {
-                    source_file,
-                    output_path,
-                    error,
-                });
+                cgcx.create_dcx().emit_err(errors::CopyPathBuf { source_file, output_path, error });
                 None
             }
         }
@@ -939,13 +935,13 @@ fn finish_intra_module_work<B: ExtraBackendMethods>(
     module: ModuleCodegen<B::Module>,
     module_config: &ModuleConfig,
 ) -> Result<WorkItemResult<B>, FatalError> {
-    let diag_handler = cgcx.create_diag_handler();
+    let dcx = cgcx.create_dcx();
 
     if !cgcx.opts.unstable_opts.combine_cgu
         || module.kind == ModuleKind::Metadata
         || module.kind == ModuleKind::Allocator
     {
-        let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? };
+        let module = unsafe { B::codegen(cgcx, &dcx, module, module_config)? };
         Ok(WorkItemResult::Finished(module))
     } else {
         Ok(WorkItemResult::NeedsLink(module))
@@ -1595,11 +1591,10 @@ fn start_executing_work<B: ExtraBackendMethods>(
         let needs_link = mem::take(&mut needs_link);
         if !needs_link.is_empty() {
             assert!(compiled_modules.is_empty());
-            let diag_handler = cgcx.create_diag_handler();
-            let module = B::run_link(&cgcx, &diag_handler, needs_link).map_err(|_| ())?;
+            let dcx = cgcx.create_dcx();
+            let module = B::run_link(&cgcx, &dcx, needs_link).map_err(|_| ())?;
             let module = unsafe {
-                B::codegen(&cgcx, &diag_handler, module, cgcx.config(ModuleKind::Regular))
-                    .map_err(|_| ())?
+                B::codegen(&cgcx, &dcx, module, cgcx.config(ModuleKind::Regular)).map_err(|_| ())?
             };
             compiled_modules.push(module);
         }
@@ -1842,13 +1837,13 @@ impl SharedEmitterMain {
 
             match message {
                 Ok(SharedEmitterMessage::Diagnostic(diag)) => {
-                    let handler = sess.diagnostic();
+                    let dcx = sess.dcx();
                     let mut d = rustc_errors::Diagnostic::new_with_messages(diag.lvl, diag.msg);
                     if let Some(code) = diag.code {
                         d.code(code);
                     }
                     d.replace_args(diag.args);
-                    handler.emit_diagnostic(d);
+                    dcx.emit_diagnostic(d);
                 }
                 Ok(SharedEmitterMessage::InlineAsmError(cookie, msg, level, source)) => {
                     let msg = msg.strip_prefix("error: ").unwrap_or(&msg).to_string();
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 015ea10d721..e529956b1ba 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -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.diagnostic(),
+                                            tcx.sess.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.diagnostic(),
+                                        tcx.sess.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.diagnostic(),
+                                tcx.sess.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.diagnostic(),
+                                tcx.sess.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.diagnostic(),
+                                tcx.sess.dcx(),
                                 attr.span,
                                 E0589,
                                 "invalid `repr(align)` attribute: {}",
@@ -469,27 +469,17 @@ 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.diagnostic(),
-                        attr.span,
-                        E0534,
-                        "expected one argument"
-                    )
-                    .emit();
+                    struct_span_err!(tcx.sess.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.diagnostic(),
-                        items[0].span(),
-                        E0535,
-                        "invalid argument"
-                    )
-                    .help("valid inline arguments are `always` and `never`")
-                    .emit();
+                    struct_span_err!(tcx.sess.dcx(), items[0].span(), E0535, "invalid argument")
+                        .help("valid inline arguments are `always` and `never`")
+                        .emit();
 
                     InlineAttr::None
                 }
@@ -503,7 +493,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.diagnostic(), sp, E0722, "{}", s).emit();
+        let err = |sp, s| struct_span_err!(tcx.sess.dcx(), sp, E0722, "{}", s).emit();
         match attr.meta_kind() {
             Some(MetaItemKind::Word) => {
                 err(attr.span, "expected one argument");
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index ed6ac9f9c5d..668d39afbda 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -4,7 +4,7 @@ use crate::assert_module_sources::CguReuse;
 use crate::back::command::Command;
 use crate::fluent_generated as fluent;
 use rustc_errors::{
-    DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
+    DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
     IntoDiagnosticArg,
 };
 use rustc_macros::Diagnostic;
@@ -210,192 +210,191 @@ pub enum LinkRlibError {
 pub struct ThorinErrorWrapper(pub thorin::Error);
 
 impl IntoDiagnostic<'_> for ThorinErrorWrapper {
-    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+    fn into_diagnostic(self, dcx: &DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
         let mut diag;
         match self.0 {
             thorin::Error::ReadInput(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_read_input_failure);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_read_input_failure);
                 diag
             }
             thorin::Error::ParseFileKind(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_file_kind);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_input_file_kind);
                 diag
             }
             thorin::Error::ParseObjectFile(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_object_file);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_input_object_file);
                 diag
             }
             thorin::Error::ParseArchiveFile(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_input_archive_file);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_input_archive_file);
                 diag
             }
             thorin::Error::ParseArchiveMember(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_archive_member);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_archive_member);
                 diag
             }
             thorin::Error::InvalidInputKind => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_invalid_input_kind);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_invalid_input_kind);
                 diag
             }
             thorin::Error::DecompressData(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_decompress_data);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_decompress_data);
                 diag
             }
             thorin::Error::NamelessSection(_, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_section_without_name);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_section_without_name);
                 diag.set_arg("offset", format!("0x{offset:08x}"));
                 diag
             }
             thorin::Error::RelocationWithInvalidSymbol(section, offset) => {
-                diag =
-                    handler.struct_err(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_relocation_with_invalid_symbol);
                 diag.set_arg("section", section);
                 diag.set_arg("offset", format!("0x{offset:08x}"));
                 diag
             }
             thorin::Error::MultipleRelocations(section, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_relocations);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_multiple_relocations);
                 diag.set_arg("section", section);
                 diag.set_arg("offset", format!("0x{offset:08x}"));
                 diag
             }
             thorin::Error::UnsupportedRelocation(section, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_unsupported_relocation);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_unsupported_relocation);
                 diag.set_arg("section", section);
                 diag.set_arg("offset", format!("0x{offset:08x}"));
                 diag
             }
             thorin::Error::MissingDwoName(id) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_dwo_name);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_missing_dwo_name);
                 diag.set_arg("id", format!("0x{id:08x}"));
                 diag
             }
             thorin::Error::NoCompilationUnits => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_no_compilation_units);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_no_compilation_units);
                 diag
             }
             thorin::Error::NoDie => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_no_die);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_no_die);
                 diag
             }
             thorin::Error::TopLevelDieNotUnit => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_top_level_die_not_unit);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_top_level_die_not_unit);
                 diag
             }
             thorin::Error::MissingRequiredSection(section) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_required_section);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_missing_required_section);
                 diag.set_arg("section", section);
                 diag
             }
             thorin::Error::ParseUnitAbbreviations(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_abbreviations);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit_abbreviations);
                 diag
             }
             thorin::Error::ParseUnitAttribute(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_attribute);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit_attribute);
                 diag
             }
             thorin::Error::ParseUnitHeader(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit_header);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit_header);
                 diag
             }
             thorin::Error::ParseUnit(_) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_unit);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_unit);
                 diag
             }
             thorin::Error::IncompatibleIndexVersion(section, format, actual) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_incompatible_index_version);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_incompatible_index_version);
                 diag.set_arg("section", section);
                 diag.set_arg("actual", actual);
                 diag.set_arg("format", format);
                 diag
             }
             thorin::Error::OffsetAtIndex(_, index) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_offset_at_index);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_offset_at_index);
                 diag.set_arg("index", index);
                 diag
             }
             thorin::Error::StrAtOffset(_, offset) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_str_at_offset);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_str_at_offset);
                 diag.set_arg("offset", format!("0x{offset:08x}"));
                 diag
             }
             thorin::Error::ParseIndex(_, section) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_parse_index);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_parse_index);
                 diag.set_arg("section", section);
                 diag
             }
             thorin::Error::UnitNotInIndex(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_unit_not_in_index);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_unit_not_in_index);
                 diag.set_arg("unit", format!("0x{unit:08x}"));
                 diag
             }
             thorin::Error::RowNotInIndex(_, row) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_row_not_in_index);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_row_not_in_index);
                 diag.set_arg("row", row);
                 diag
             }
             thorin::Error::SectionNotInRow => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_section_not_in_row);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_section_not_in_row);
                 diag
             }
             thorin::Error::EmptyUnit(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_empty_unit);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_empty_unit);
                 diag.set_arg("unit", format!("0x{unit:08x}"));
                 diag
             }
             thorin::Error::MultipleDebugInfoSection => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_debug_info_section);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_multiple_debug_info_section);
                 diag
             }
             thorin::Error::MultipleDebugTypesSection => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_multiple_debug_types_section);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_multiple_debug_types_section);
                 diag
             }
             thorin::Error::NotSplitUnit => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_not_split_unit);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_not_split_unit);
                 diag
             }
             thorin::Error::DuplicateUnit(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_duplicate_unit);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_duplicate_unit);
                 diag.set_arg("unit", format!("0x{unit:08x}"));
                 diag
             }
             thorin::Error::MissingReferencedUnit(unit) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_missing_referenced_unit);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_missing_referenced_unit);
                 diag.set_arg("unit", format!("0x{unit:08x}"));
                 diag
             }
             thorin::Error::NoOutputObjectCreated => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_not_output_object_created);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_not_output_object_created);
                 diag
             }
             thorin::Error::MixedInputEncodings => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_mixed_input_encodings);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_mixed_input_encodings);
                 diag
             }
             thorin::Error::Io(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_io);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_io);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::ObjectRead(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_object_read);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_object_read);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::ObjectWrite(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_object_write);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_object_write);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::GimliRead(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_gimli_read);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_gimli_read);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
             thorin::Error::GimliWrite(e) => {
-                diag = handler.struct_err(fluent::codegen_ssa_thorin_gimli_write);
+                diag = dcx.struct_err(fluent::codegen_ssa_thorin_gimli_write);
                 diag.set_arg("error", format!("{e}"));
                 diag
             }
@@ -412,8 +411,8 @@ pub struct LinkingFailed<'a> {
 }
 
 impl IntoDiagnostic<'_> for LinkingFailed<'_> {
-    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::codegen_ssa_linking_failed);
+    fn into_diagnostic(self, dcx: &DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = dcx.struct_err(fluent::codegen_ssa_linking_failed);
         diag.set_arg("linker_path", format!("{}", self.linker_path.display()));
         diag.set_arg("exit_status", format!("{}", self.exit_status));
 
diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs
index ecf5095d8a3..048540894ac 100644
--- a/compiler/rustc_codegen_ssa/src/traits/write.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/write.rs
@@ -2,7 +2,7 @@ use crate::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
 use crate::back::write::{CodegenContext, FatLtoInput, ModuleConfig};
 use crate::{CompiledModule, ModuleCodegen};
 
-use rustc_errors::{FatalError, Handler};
+use rustc_errors::{DiagCtxt, FatalError};
 use rustc_middle::dep_graph::WorkProduct;
 
 pub trait WriteBackendMethods: 'static + Sized + Clone {
@@ -16,7 +16,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
     /// Merge all modules into main_module and returning it
     fn run_link(
         cgcx: &CodegenContext<Self>,
-        diag_handler: &Handler,
+        dcx: &DiagCtxt,
         modules: Vec<ModuleCodegen<Self::Module>>,
     ) -> Result<ModuleCodegen<Self::Module>, FatalError>;
     /// Performs fat LTO by merging all modules into a single one and returning it
@@ -38,7 +38,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
     fn print_statistics(&self);
     unsafe fn optimize(
         cgcx: &CodegenContext<Self>,
-        diag_handler: &Handler,
+        dcx: &DiagCtxt,
         module: &ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> Result<(), FatalError>;
@@ -52,7 +52,7 @@ pub trait WriteBackendMethods: 'static + Sized + Clone {
     ) -> Result<ModuleCodegen<Self::Module>, FatalError>;
     unsafe fn codegen(
         cgcx: &CodegenContext<Self>,
-        diag_handler: &Handler,
+        dcx: &DiagCtxt,
         module: ModuleCodegen<Self::Module>,
         config: &ModuleConfig,
     ) -> Result<CompiledModule, FatalError>;
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 26cf3b3f2b0..8f18cd78d3f 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -154,7 +154,7 @@ where
             let mut err = tcx.sess.create_err(err);
 
             let msg = error.diagnostic_message();
-            error.add_args(tcx.sess.diagnostic(), &mut err);
+            error.add_args(tcx.sess.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/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index 46fb64fd5b3..adce1f5430f 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -1,5 +1,5 @@
 use rustc_errors::{
-    DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler,
+    DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee,
     IntoDiagnostic,
 };
 use rustc_hir::ConstContext;
@@ -432,11 +432,7 @@ pub struct UndefinedBehavior {
 pub trait ReportErrorExt {
     /// Returns the diagnostic message for this error.
     fn diagnostic_message(&self) -> DiagnosticMessage;
-    fn add_args<G: EmissionGuarantee>(
-        self,
-        handler: &Handler,
-        builder: &mut DiagnosticBuilder<'_, G>,
-    );
+    fn add_args<G: EmissionGuarantee>(self, dcx: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>);
 
     fn debug(self) -> String
     where
@@ -444,17 +440,17 @@ pub trait ReportErrorExt {
     {
         ty::tls::with(move |tcx| {
             let mut builder = tcx.sess.struct_allow(DiagnosticMessage::Str(String::new().into()));
-            let handler = tcx.sess.diagnostic();
+            let dcx = tcx.sess.dcx();
             let message = self.diagnostic_message();
-            self.add_args(handler, &mut builder);
-            let s = handler.eagerly_translate_to_string(message, builder.args());
+            self.add_args(dcx, &mut builder);
+            let s = dcx.eagerly_translate_to_string(message, builder.args());
             builder.cancel();
             s
         })
     }
 }
 
-fn bad_pointer_message(msg: CheckInAllocMsg, handler: &Handler) -> String {
+fn bad_pointer_message(msg: CheckInAllocMsg, dcx: &DiagCtxt) -> String {
     use crate::fluent_generated::*;
 
     let msg = match msg {
@@ -464,7 +460,7 @@ fn bad_pointer_message(msg: CheckInAllocMsg, handler: &Handler) -> String {
         CheckInAllocMsg::InboundsTest => const_eval_in_bounds_test,
     };
 
-    handler.eagerly_translate_to_string(msg, [].into_iter())
+    dcx.eagerly_translate_to_string(msg, [].into_iter())
 }
 
 impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
@@ -514,7 +510,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
 
     fn add_args<G: EmissionGuarantee>(
         self,
-        handler: &Handler,
+        dcx: &DiagCtxt,
         builder: &mut DiagnosticBuilder<'_, G>,
     ) {
         use UndefinedBehaviorInfo::*;
@@ -525,7 +521,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
                     builder.set_arg(name, value);
                 });
             }
-            ValidationError(e) => e.add_args(handler, builder),
+            ValidationError(e) => e.add_args(dcx, builder),
 
             Unreachable
             | DivisionByZero
@@ -549,7 +545,7 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             PointerUseAfterFree(alloc_id, msg) => {
                 builder
                     .set_arg("alloc_id", alloc_id)
-                    .set_arg("bad_pointer_message", bad_pointer_message(msg, handler));
+                    .set_arg("bad_pointer_message", bad_pointer_message(msg, dcx));
             }
             PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
                 builder
@@ -557,14 +553,14 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
                     .set_arg("alloc_size", alloc_size.bytes())
                     .set_arg("ptr_offset", ptr_offset)
                     .set_arg("ptr_size", ptr_size.bytes())
-                    .set_arg("bad_pointer_message", bad_pointer_message(msg, handler));
+                    .set_arg("bad_pointer_message", bad_pointer_message(msg, dcx));
             }
             DanglingIntPointer(ptr, msg) => {
                 if ptr != 0 {
                     builder.set_arg("pointer", format!("{ptr:#x}[noalloc]"));
                 }
 
-                builder.set_arg("bad_pointer_message", bad_pointer_message(msg, handler));
+                builder.set_arg("bad_pointer_message", bad_pointer_message(msg, dcx));
             }
             AlignmentCheckFailed(Misalignment { required, has }, msg) => {
                 builder.set_arg("required", required.bytes());
@@ -678,7 +674,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         }
     }
 
-    fn add_args<G: EmissionGuarantee>(self, handler: &Handler, err: &mut DiagnosticBuilder<'_, G>) {
+    fn add_args<G: EmissionGuarantee>(self, dcx: &DiagCtxt, err: &mut DiagnosticBuilder<'_, G>) {
         use crate::fluent_generated as fluent;
         use rustc_middle::mir::interpret::ValidationErrorKind::*;
 
@@ -688,12 +684,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         }
 
         let message = if let Some(path) = self.path {
-            handler.eagerly_translate_to_string(
+            dcx.eagerly_translate_to_string(
                 fluent::const_eval_validation_front_matter_invalid_value_with_path,
                 [("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
             )
         } else {
-            handler.eagerly_translate_to_string(
+            dcx.eagerly_translate_to_string(
                 fluent::const_eval_validation_front_matter_invalid_value,
                 [].into_iter(),
             )
@@ -704,7 +700,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         fn add_range_arg<G: EmissionGuarantee>(
             r: WrappingRange,
             max_hi: u128,
-            handler: &Handler,
+            dcx: &DiagCtxt,
             err: &mut DiagnosticBuilder<'_, G>,
         ) {
             let WrappingRange { start: lo, end: hi } = r;
@@ -728,7 +724,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
                 ("hi".into(), DiagnosticArgValue::Str(hi.to_string().into())),
             ];
             let args = args.iter().map(|(a, b)| (a, b));
-            let message = handler.eagerly_translate_to_string(msg, args);
+            let message = dcx.eagerly_translate_to_string(msg, args);
             err.set_arg("in_range", message);
         }
 
@@ -750,7 +746,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
                     ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
                     ExpectedKind::Str => fluent::const_eval_validation_expected_str,
                 };
-                let msg = handler.eagerly_translate_to_string(msg, [].into_iter());
+                let msg = dcx.eagerly_translate_to_string(msg, [].into_iter());
                 err.set_arg("expected", msg);
             }
             InvalidEnumTag { value }
@@ -761,11 +757,11 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
                 err.set_arg("value", value);
             }
             NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
-                add_range_arg(range, max_value, handler, err)
+                add_range_arg(range, max_value, dcx, err)
             }
             OutOfRange { range, max_value, value } => {
                 err.set_arg("value", value);
-                add_range_arg(range, max_value, handler, err);
+                add_range_arg(range, max_value, dcx, err);
             }
             UnalignedPtr { required_bytes, found_bytes, .. } => {
                 err.set_arg("required_bytes", required_bytes);
@@ -804,7 +800,7 @@ impl ReportErrorExt for UnsupportedOpInfo {
             UnsupportedOpInfo::ReadExternStatic(_) => const_eval_read_extern_static,
         }
     }
-    fn add_args<G: EmissionGuarantee>(self, _: &Handler, builder: &mut DiagnosticBuilder<'_, G>) {
+    fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>) {
         use crate::fluent_generated::*;
 
         use UnsupportedOpInfo::*;
@@ -839,14 +835,14 @@ impl<'tcx> ReportErrorExt for InterpError<'tcx> {
     }
     fn add_args<G: EmissionGuarantee>(
         self,
-        handler: &Handler,
+        dcx: &DiagCtxt,
         builder: &mut DiagnosticBuilder<'_, G>,
     ) {
         match self {
-            InterpError::UndefinedBehavior(ub) => ub.add_args(handler, builder),
-            InterpError::Unsupported(e) => e.add_args(handler, builder),
-            InterpError::InvalidProgram(e) => e.add_args(handler, builder),
-            InterpError::ResourceExhaustion(e) => e.add_args(handler, builder),
+            InterpError::UndefinedBehavior(ub) => ub.add_args(dcx, builder),
+            InterpError::Unsupported(e) => e.add_args(dcx, builder),
+            InterpError::InvalidProgram(e) => e.add_args(dcx, builder),
+            InterpError::ResourceExhaustion(e) => e.add_args(dcx, builder),
             InterpError::MachineStop(e) => e.add_args(&mut |name, value| {
                 builder.set_arg(name, value);
             }),
@@ -871,7 +867,7 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
     }
     fn add_args<G: EmissionGuarantee>(
         self,
-        handler: &Handler,
+        dcx: &DiagCtxt,
         builder: &mut DiagnosticBuilder<'_, G>,
     ) {
         match self {
@@ -879,7 +875,7 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
             | InvalidProgramInfo::AlreadyReported(_)
             | InvalidProgramInfo::ConstPropNonsense => {}
             InvalidProgramInfo::Layout(e) => {
-                let diag: DiagnosticBuilder<'_, ()> = e.into_diagnostic().into_diagnostic(handler);
+                let diag: DiagnosticBuilder<'_, ()> = e.into_diagnostic().into_diagnostic(dcx);
                 for (name, val) in diag.args() {
                     builder.set_arg(name.clone(), val.clone());
                 }
@@ -904,5 +900,5 @@ impl ReportErrorExt for ResourceExhaustionInfo {
             ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
         }
     }
-    fn add_args<G: EmissionGuarantee>(self, _: &Handler, _: &mut DiagnosticBuilder<'_, G>) {}
+    fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, _: &mut DiagnosticBuilder<'_, G>) {}
 }
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 847d6503f20..af8e5e7d151 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -473,12 +473,12 @@ 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 handler = self.tcx.sess.diagnostic();
+        let dcx = self.tcx.sess.dcx();
         #[allow(rustc::untranslatable_diagnostic)]
         let mut diag = self.tcx.sess.struct_allow("");
         let msg = e.diagnostic_message();
-        e.add_args(handler, &mut diag);
-        let s = handler.eagerly_translate_to_string(msg, diag.args());
+        e.add_args(dcx, &mut diag);
+        let s = dcx.eagerly_translate_to_string(msg, diag.args());
         diag.cancel();
         s
     }
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 bb17602d3ba..949606ed6c9 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -278,7 +278,7 @@ 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.diagnostic().emit_diagnostic(error);
+                self.tcx.sess.dcx().emit_diagnostic(error);
             }
         } else {
             assert!(self.tcx.sess.has_errors().is_some());
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index eaf4abf39b7..cca5b90abb9 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -130,7 +130,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.diagnostic().span_delayed_bug(
+        self.tcx.sess.dcx().span_delayed_bug(
             span,
             format!(
                 "broken MIR in {:?} ({}) at {:?}:\n{}",
@@ -571,7 +571,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.diagnostic().span_delayed_bug(
+            self.tcx.sess.dcx().span_delayed_bug(
                 self.body.span,
                 format!(
                     "broken MIR in {:?} ({}):\ninvalid source scope {:?}",
diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs
index 654d7636da2..dc546da7342 100644
--- a/compiler/rustc_driver_impl/src/args.rs
+++ b/compiler/rustc_driver_impl/src/args.rs
@@ -3,7 +3,7 @@ use std::fmt;
 use std::fs;
 use std::io;
 
-use rustc_session::EarlyErrorHandler;
+use rustc_session::EarlyDiagCtxt;
 
 fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
     if let Some(path) = arg.strip_prefix('@') {
@@ -23,12 +23,12 @@ fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
 /// **Note:** This function doesn't interpret argument 0 in any special way.
 /// If this function is intended to be used with command line arguments,
 /// `argv[0]` must be removed prior to calling it manually.
-pub fn arg_expand_all(handler: &EarlyErrorHandler, at_args: &[String]) -> Vec<String> {
+pub fn arg_expand_all(early_dcx: &EarlyDiagCtxt, at_args: &[String]) -> Vec<String> {
     let mut args = Vec::new();
     for arg in at_args {
         match arg_expand(arg.clone()) {
             Ok(arg) => args.extend(arg),
-            Err(err) => handler.early_error(format!("Failed to load argument file: {err}")),
+            Err(err) => early_dcx.early_error(format!("Failed to load argument file: {err}")),
         }
     }
     args
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index e49db64536f..d67fea7e9a4 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -27,7 +27,7 @@ use rustc_data_structures::profiling::{
 use rustc_data_structures::sync::SeqCst;
 use rustc_errors::registry::{InvalidErrorCode, Registry};
 use rustc_errors::{markdown, ColorConfig};
-use rustc_errors::{ErrorGuaranteed, Handler, PResult};
+use rustc_errors::{DiagCtxt, ErrorGuaranteed, PResult};
 use rustc_feature::find_gated_cfg;
 use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
 use rustc_interface::{interface, Queries};
@@ -38,7 +38,7 @@ use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
 use rustc_session::config::{ErrorOutputType, Input, OutFileName, OutputType, TrimmedDefPaths};
 use rustc_session::getopts::{self, Matches};
 use rustc_session::lint::{Lint, LintId};
-use rustc_session::{config, EarlyErrorHandler, Session};
+use rustc_session::{config, EarlyDiagCtxt, Session};
 use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::source_map::FileLoader;
 use rustc_span::symbol::sym;
@@ -291,7 +291,7 @@ fn run_compiler(
     >,
     using_internal_features: Arc<std::sync::atomic::AtomicBool>,
 ) -> interface::Result<()> {
-    let mut default_handler = EarlyErrorHandler::new(ErrorOutputType::default());
+    let mut default_early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
     // Throw away the first argument, the name of the binary.
     // In case of at_args being empty, as might be the case by
@@ -303,14 +303,14 @@ fn run_compiler(
     // the compiler with @empty_file as argv[0] and no more arguments.
     let at_args = at_args.get(1..).unwrap_or_default();
 
-    let args = args::arg_expand_all(&default_handler, at_args);
+    let args = args::arg_expand_all(&default_early_dcx, at_args);
 
-    let Some(matches) = handle_options(&default_handler, &args) else { return Ok(()) };
+    let Some(matches) = handle_options(&default_early_dcx, &args) else { return Ok(()) };
 
-    let sopts = config::build_session_options(&mut default_handler, &matches);
+    let sopts = config::build_session_options(&mut default_early_dcx, &matches);
 
     if let Some(ref code) = matches.opt_str("explain") {
-        handle_explain(&default_handler, diagnostics_registry(), code, sopts.color);
+        handle_explain(&default_early_dcx, diagnostics_registry(), code, sopts.color);
         return Ok(());
     }
 
@@ -336,7 +336,7 @@ fn run_compiler(
         expanded_args: args,
     };
 
-    let has_input = match make_input(&default_handler, &matches.free) {
+    let has_input = match make_input(&default_early_dcx, &matches.free) {
         Err(reported) => return Err(reported),
         Ok(Some(input)) => {
             config.input = input;
@@ -345,7 +345,7 @@ fn run_compiler(
         Ok(None) => match matches.free.len() {
             0 => false, // no input: we will exit early
             1 => panic!("make_input should have provided valid inputs"),
-            _ => default_handler.early_error(format!(
+            _ => default_early_dcx.early_error(format!(
                 "multiple input filenames provided (first two filenames are `{}` and `{}`)",
                 matches.free[0], matches.free[1],
             )),
@@ -354,8 +354,8 @@ fn run_compiler(
 
     callbacks.config(&mut config);
 
-    default_handler.abort_if_errors();
-    drop(default_handler);
+    default_early_dcx.abort_if_errors();
+    drop(default_early_dcx);
 
     interface::run_compiler(config, |compiler| {
         let sess = &compiler.sess;
@@ -369,18 +369,18 @@ fn run_compiler(
             return sess.compile_status();
         }
 
-        let handler = EarlyErrorHandler::new(sess.opts.error_format);
+        let early_dcx = EarlyDiagCtxt::new(sess.opts.error_format);
 
-        if print_crate_info(&handler, codegen_backend, sess, has_input) == Compilation::Stop {
+        if print_crate_info(&early_dcx, codegen_backend, sess, has_input) == Compilation::Stop {
             return sess.compile_status();
         }
 
         if !has_input {
-            handler.early_error("no input filename given"); // this is fatal
+            early_dcx.early_error("no input filename given"); // this is fatal
         }
 
         if !sess.opts.unstable_opts.ls.is_empty() {
-            list_metadata(&handler, sess, &*codegen_backend.metadata_loader());
+            list_metadata(&early_dcx, sess, &*codegen_backend.metadata_loader());
             return sess.compile_status();
         }
 
@@ -495,7 +495,7 @@ fn make_output(matches: &getopts::Matches) -> (Option<PathBuf>, Option<OutFileNa
 
 // Extract input (string or file and optional path) from matches.
 fn make_input(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     free_matches: &[String],
 ) -> Result<Option<Input>, ErrorGuaranteed> {
     if free_matches.len() == 1 {
@@ -505,7 +505,7 @@ fn make_input(
             if io::stdin().read_to_string(&mut src).is_err() {
                 // Immediately stop compilation if there was an issue reading
                 // the input (for example if the input stream is not UTF-8).
-                let reported = handler.early_error_no_abort(
+                let reported = early_dcx.early_error_no_abort(
                     "couldn't read from stdin, as it did not contain valid UTF-8",
                 );
                 return Err(reported);
@@ -537,7 +537,7 @@ pub enum Compilation {
     Continue,
 }
 
-fn handle_explain(handler: &EarlyErrorHandler, registry: Registry, code: &str, color: ColorConfig) {
+fn handle_explain(early_dcx: &EarlyDiagCtxt, registry: Registry, code: &str, color: ColorConfig) {
     let upper_cased_code = code.to_ascii_uppercase();
     let normalised =
         if upper_cased_code.starts_with('E') { upper_cased_code } else { format!("E{code:0>4}") };
@@ -567,7 +567,7 @@ fn handle_explain(handler: &EarlyErrorHandler, registry: Registry, code: &str, c
             }
         }
         Err(InvalidErrorCode) => {
-            handler.early_error(format!("{code} is not a valid error code"));
+            early_dcx.early_error(format!("{code} is not a valid error code"));
         }
     }
 }
@@ -669,11 +669,7 @@ fn process_rlink(sess: &Session, compiler: &interface::Compiler) {
     }
 }
 
-fn list_metadata(
-    handler: &EarlyErrorHandler,
-    sess: &Session,
-    metadata_loader: &dyn MetadataLoader,
-) {
+fn list_metadata(early_dcx: &EarlyDiagCtxt, sess: &Session, metadata_loader: &dyn MetadataLoader) {
     match sess.io.input {
         Input::File(ref ifile) => {
             let path = &(*ifile);
@@ -689,13 +685,13 @@ fn list_metadata(
             safe_println!("{}", String::from_utf8(v).unwrap());
         }
         Input::Str { .. } => {
-            handler.early_error("cannot list metadata for stdin");
+            early_dcx.early_error("cannot list metadata for stdin");
         }
     }
 }
 
 fn print_crate_info(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     codegen_backend: &dyn CodegenBackend,
     sess: &Session,
     parse_attrs: bool,
@@ -842,7 +838,7 @@ fn print_crate_info(
                         .expect("unknown Apple target OS");
                     println_info!("deployment_target={}", format!("{major}.{minor}"))
                 } else {
-                    handler
+                    early_dcx
                         .early_error("only Apple targets currently support deployment version info")
                 }
             }
@@ -856,12 +852,12 @@ fn print_crate_info(
 /// Prints version information
 ///
 /// NOTE: this is a macro to support drivers built at a different time than the main `rustc_driver` crate.
-pub macro version($handler: expr, $binary: literal, $matches: expr) {
+pub macro version($early_dcx: expr, $binary: literal, $matches: expr) {
     fn unw(x: Option<&str>) -> &str {
         x.unwrap_or("unknown")
     }
     $crate::version_at_macro_invocation(
-        $handler,
+        $early_dcx,
         $binary,
         $matches,
         unw(option_env!("CFG_VERSION")),
@@ -873,7 +869,7 @@ pub macro version($handler: expr, $binary: literal, $matches: expr) {
 
 #[doc(hidden)] // use the macro instead
 pub fn version_at_macro_invocation(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     binary: &str,
     matches: &getopts::Matches,
     version: &str,
@@ -894,7 +890,7 @@ pub fn version_at_macro_invocation(
 
         let debug_flags = matches.opt_strs("Z");
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-        get_codegen_backend(handler, &None, backend_name).print_version();
+        get_codegen_backend(early_dcx, &None, backend_name).print_version();
     }
 }
 
@@ -1072,7 +1068,7 @@ Available lint options:
 /// Show help for flag categories shared between rustdoc and rustc.
 ///
 /// Returns whether a help option was printed.
-pub fn describe_flag_categories(handler: &EarlyErrorHandler, matches: &Matches) -> bool {
+pub fn describe_flag_categories(early_dcx: &EarlyDiagCtxt, matches: &Matches) -> bool {
     // Handle the special case of -Wall.
     let wall = matches.opt_strs("W");
     if wall.iter().any(|x| *x == "all") {
@@ -1094,12 +1090,12 @@ pub fn describe_flag_categories(handler: &EarlyErrorHandler, matches: &Matches)
     }
 
     if cg_flags.iter().any(|x| *x == "no-stack-check") {
-        handler.early_warn("the --no-stack-check flag is deprecated and does nothing");
+        early_dcx.early_warn("the --no-stack-check flag is deprecated and does nothing");
     }
 
     if cg_flags.iter().any(|x| *x == "passes=list") {
         let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-        get_codegen_backend(handler, &None, backend_name).print_passes();
+        get_codegen_backend(early_dcx, &None, backend_name).print_passes();
         return true;
     }
 
@@ -1160,7 +1156,7 @@ fn print_flag_list<T>(
 /// This does not need to be `pub` for rustc itself, but @chaosite needs it to
 /// be public when using rustc as a library, see
 /// <https://github.com/rust-lang/rust/commit/2b4c33817a5aaecabf4c6598d41e190080ec119e>
-pub fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<getopts::Matches> {
+pub fn handle_options(early_dcx: &EarlyDiagCtxt, args: &[String]) -> Option<getopts::Matches> {
     if args.is_empty() {
         // user did not write `-v` nor `-Z unstable-options`, so do not
         // include that extra information.
@@ -1186,7 +1182,7 @@ pub fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<ge
                 .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
             _ => None,
         };
-        handler.early_error(msg.unwrap_or_else(|| e.to_string()));
+        early_dcx.early_error(msg.unwrap_or_else(|| e.to_string()));
     });
 
     // For all options we just parsed, we check a few aspects:
@@ -1200,7 +1196,7 @@ pub fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<ge
     //   we're good to go.
     // * Otherwise, if we're an unstable option then we generate an error
     //   (unstable option being used on stable)
-    nightly_options::check_nightly_options(handler, &matches, &config::rustc_optgroups());
+    nightly_options::check_nightly_options(early_dcx, &matches, &config::rustc_optgroups());
 
     if matches.opt_present("h") || matches.opt_present("help") {
         // Only show unstable options in --help if we accept unstable options.
@@ -1210,12 +1206,12 @@ pub fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option<ge
         return None;
     }
 
-    if describe_flag_categories(handler, &matches) {
+    if describe_flag_categories(early_dcx, &matches) {
         return None;
     }
 
     if matches.opt_present("version") {
-        version!(handler, "rustc", &matches);
+        version!(early_dcx, "rustc", &matches);
         return None;
     }
 
@@ -1310,7 +1306,10 @@ fn ice_path() -> &'static Option<PathBuf> {
 /// internal features.
 ///
 /// A custom rustc driver can skip calling this to set up a custom ICE hook.
-pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) -> Arc<AtomicBool> {
+pub fn install_ice_hook(
+    bug_report_url: &'static str,
+    extra_info: fn(&DiagCtxt),
+) -> Arc<AtomicBool> {
     // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
     // full backtraces. When a compiler ICE happens, we want to gather
     // as much information as possible to present in the issue opened
@@ -1333,8 +1332,8 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
                 if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
                 {
                     // the error code is already going to be reported when the panic unwinds up the stack
-                    let handler = EarlyErrorHandler::new(ErrorOutputType::default());
-                    let _ = handler.early_error_no_abort(msg.clone());
+                    let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
+                    let _ = early_dcx.early_error_no_abort(msg.clone());
                     return;
                 }
             };
@@ -1388,7 +1387,7 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler))
 fn report_ice(
     info: &panic::PanicInfo<'_>,
     bug_report_url: &str,
-    extra_info: fn(&Handler),
+    extra_info: fn(&DiagCtxt),
     using_internal_features: &AtomicBool,
 ) {
     let fallback_bundle =
@@ -1397,20 +1396,20 @@ fn report_ice(
         rustc_errors::ColorConfig::Auto,
         fallback_bundle,
     ));
-    let handler = rustc_errors::Handler::with_emitter(emitter);
+    let dcx = rustc_errors::DiagCtxt::with_emitter(emitter);
 
     // a .span_bug or .bug call has already printed what
     // it wants to print.
     if !info.payload().is::<rustc_errors::ExplicitBug>()
         && !info.payload().is::<rustc_errors::DelayedBugPanic>()
     {
-        handler.emit_err(session_diagnostics::Ice);
+        dcx.emit_err(session_diagnostics::Ice);
     }
 
     if using_internal_features.load(std::sync::atomic::Ordering::Relaxed) {
-        handler.emit_note(session_diagnostics::IceBugReportInternalFeature);
+        dcx.emit_note(session_diagnostics::IceBugReportInternalFeature);
     } else {
-        handler.emit_note(session_diagnostics::IceBugReport { bug_report_url });
+        dcx.emit_note(session_diagnostics::IceBugReport { bug_report_url });
     }
 
     let version = util::version_str!().unwrap_or("unknown_version");
@@ -1422,7 +1421,7 @@ fn report_ice(
         // Create the ICE dump target file.
         match crate::fs::File::options().create(true).append(true).open(&path) {
             Ok(mut file) => {
-                handler.emit_note(session_diagnostics::IcePath { path: path.clone() });
+                dcx.emit_note(session_diagnostics::IcePath { path: path.clone() });
                 if FIRST_PANIC.swap(false, Ordering::SeqCst) {
                     let _ = write!(file, "\n\nrustc version: {version}\nplatform: {triple}");
                 }
@@ -1430,26 +1429,26 @@ fn report_ice(
             }
             Err(err) => {
                 // The path ICE couldn't be written to disk, provide feedback to the user as to why.
-                handler.emit_warning(session_diagnostics::IcePathError {
+                dcx.emit_warning(session_diagnostics::IcePathError {
                     path: path.clone(),
                     error: err.to_string(),
                     env_var: std::env::var_os("RUSTC_ICE")
                         .map(PathBuf::from)
                         .map(|env_var| session_diagnostics::IcePathErrorEnv { env_var }),
                 });
-                handler.emit_note(session_diagnostics::IceVersion { version, triple });
+                dcx.emit_note(session_diagnostics::IceVersion { version, triple });
                 None
             }
         }
     } else {
-        handler.emit_note(session_diagnostics::IceVersion { version, triple });
+        dcx.emit_note(session_diagnostics::IceVersion { version, triple });
         None
     };
 
     if let Some((flags, excluded_cargo_defaults)) = rustc_session::utils::extra_compiler_flags() {
-        handler.emit_note(session_diagnostics::IceFlags { flags: flags.join(" ") });
+        dcx.emit_note(session_diagnostics::IceFlags { flags: flags.join(" ") });
         if excluded_cargo_defaults {
-            handler.emit_note(session_diagnostics::IceExcludeCargoDefaults);
+            dcx.emit_note(session_diagnostics::IceExcludeCargoDefaults);
         }
     }
 
@@ -1458,11 +1457,11 @@ fn report_ice(
 
     let num_frames = if backtrace { None } else { Some(2) };
 
-    interface::try_print_query_stack(&handler, num_frames, file);
+    interface::try_print_query_stack(&dcx, num_frames, file);
 
     // We don't trust this callback not to panic itself, so run it at the end after we're sure we've
     // printed all the relevant info.
-    extra_info(&handler);
+    extra_info(&dcx);
 
     #[cfg(windows)]
     if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
@@ -1473,16 +1472,16 @@ fn report_ice(
 
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version.
-pub fn init_rustc_env_logger(handler: &EarlyErrorHandler) {
-    init_logger(handler, rustc_log::LoggerConfig::from_env("RUSTC_LOG"));
+pub fn init_rustc_env_logger(early_dcx: &EarlyDiagCtxt) {
+    init_logger(early_dcx, rustc_log::LoggerConfig::from_env("RUSTC_LOG"));
 }
 
 /// This allows tools to enable rust logging without having to magically match rustc's
 /// tracing crate version. In contrast to `init_rustc_env_logger` it allows you to choose
 /// the values directly rather than having to set an environment variable.
-pub fn init_logger(handler: &EarlyErrorHandler, cfg: rustc_log::LoggerConfig) {
+pub fn init_logger(early_dcx: &EarlyDiagCtxt, cfg: rustc_log::LoggerConfig) {
     if let Err(error) = rustc_log::init_logger(cfg) {
-        handler.early_error(error.to_string());
+        early_dcx.early_error(error.to_string());
     }
 }
 
@@ -1490,9 +1489,9 @@ pub fn main() -> ! {
     let start_time = Instant::now();
     let start_rss = get_resident_set_size();
 
-    let handler = EarlyErrorHandler::new(ErrorOutputType::default());
+    let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
-    init_rustc_env_logger(&handler);
+    init_rustc_env_logger(&early_dcx);
     signal_handler::install();
     let mut callbacks = TimePassesCallbacks::default();
     let using_internal_features = install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
@@ -1501,7 +1500,7 @@ pub fn main() -> ! {
             .enumerate()
             .map(|(i, arg)| {
                 arg.into_string().unwrap_or_else(|arg| {
-                    handler.early_error(format!("argument {i} is not valid Unicode: {arg:?}"))
+                    early_dcx.early_error(format!("argument {i} is not valid Unicode: {arg:?}"))
                 })
             })
             .collect::<Vec<_>>();
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 403e0ec7950..be506806065 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -886,13 +886,13 @@ impl Diagnostic {
     /// interpolated variables).
     pub fn eager_subdiagnostic(
         &mut self,
-        handler: &crate::Handler,
+        dcx: &crate::DiagCtxt,
         subdiagnostic: impl AddToDiagnostic,
     ) -> &mut Self {
         subdiagnostic.add_to_diagnostic_with(self, |diag, msg| {
             let args = diag.args();
             let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
-            handler.eagerly_translate(msg, args)
+            dcx.eagerly_translate(msg, args)
         });
         self
     }
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 315e47c0971..3f66af1fcff 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -1,9 +1,9 @@
 use crate::diagnostic::IntoDiagnosticArg;
+use crate::{DiagCtxt, Level, MultiSpan, StashKey};
 use crate::{
     Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed,
     ExplicitBug, SubdiagnosticMessage,
 };
-use crate::{Handler, Level, MultiSpan, StashKey};
 use rustc_lint_defs::Applicability;
 use rustc_span::source_map::Spanned;
 
@@ -19,9 +19,9 @@ use std::thread::panicking;
 /// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic].
 #[rustc_diagnostic_item = "IntoDiagnostic"]
 pub trait IntoDiagnostic<'a, G: EmissionGuarantee = ErrorGuaranteed> {
-    /// Write out as a diagnostic out of `Handler`.
+    /// Write out as a diagnostic out of `DiagCtxt`.
     #[must_use]
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G>;
+    fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, G>;
 }
 
 impl<'a, T, G> IntoDiagnostic<'a, G> for Spanned<T>
@@ -29,8 +29,8 @@ where
     T: IntoDiagnostic<'a, G>,
     G: EmissionGuarantee,
 {
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> {
-        let mut diag = self.node.into_diagnostic(handler);
+    fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, G> {
+        let mut diag = self.node.into_diagnostic(dcx);
         diag.set_span(self.span);
         diag
     }
@@ -40,7 +40,7 @@ where
 ///
 /// If there is some state in a downstream crate you would like to
 /// access in the methods of `DiagnosticBuilder` here, consider
-/// extending `HandlerFlags`, accessed via `self.handler.flags`.
+/// extending `DiagCtxtFlags`.
 #[must_use]
 #[derive(Clone)]
 pub struct DiagnosticBuilder<'a, G: EmissionGuarantee> {
@@ -74,8 +74,8 @@ struct DiagnosticBuilderInner<'a> {
 enum DiagnosticBuilderState<'a> {
     /// Initial state of a `DiagnosticBuilder`, before `.emit()` or `.cancel()`.
     ///
-    /// The `Diagnostic` will be emitted through this `Handler`.
-    Emittable(&'a Handler),
+    /// The `Diagnostic` will be emitted through this `DiagCtxt`.
+    Emittable(&'a DiagCtxt),
 
     /// State of a `DiagnosticBuilder`, after `.emit()` or *during* `.cancel()`.
     ///
@@ -95,7 +95,7 @@ enum DiagnosticBuilderState<'a> {
 // `DiagnosticBuilderState` should be pointer-sized.
 rustc_data_structures::static_assert_size!(
     DiagnosticBuilderState<'_>,
-    std::mem::size_of::<&Handler>()
+    std::mem::size_of::<&DiagCtxt>()
 );
 
 /// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee"
@@ -110,7 +110,7 @@ pub trait EmissionGuarantee: Sized {
     /// Creates a new `DiagnosticBuilder` that will return this type of guarantee.
     #[track_caller]
     fn make_diagnostic_builder(
-        handler: &Handler,
+        dcx: &DiagCtxt,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, Self>;
 }
@@ -128,11 +128,11 @@ impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> {
 impl EmissionGuarantee for ErrorGuaranteed {
     fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
         match db.inner.state {
-            // First `.emit()` call, the `&Handler` is still available.
-            DiagnosticBuilderState::Emittable(handler) => {
+            // First `.emit()` call, the `&DiagCtxt` is still available.
+            DiagnosticBuilderState::Emittable(dcx) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
 
-                let guar = handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
+                let guar = dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
 
                 // Only allow a guarantee if the `level` wasn't switched to a
                 // non-error - the field isn't `pub`, but the whole `Diagnostic`
@@ -166,10 +166,10 @@ impl EmissionGuarantee for ErrorGuaranteed {
 
     #[track_caller]
     fn make_diagnostic_builder(
-        handler: &Handler,
+        dcx: &DiagCtxt,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, Self> {
-        DiagnosticBuilder::new(handler, Level::Error { lint: false }, msg)
+        DiagnosticBuilder::new(dcx, Level::Error { lint: false }, msg)
     }
 }
 
@@ -177,11 +177,11 @@ impl EmissionGuarantee for ErrorGuaranteed {
 impl EmissionGuarantee for () {
     fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
         match db.inner.state {
-            // First `.emit()` call, the `&Handler` is still available.
-            DiagnosticBuilderState::Emittable(handler) => {
+            // First `.emit()` call, the `&DiagCtxt` is still available.
+            DiagnosticBuilderState::Emittable(dcx) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
 
-                handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
+                dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
             }
             // `.emit()` was previously called, disallowed from repeating it.
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
@@ -189,10 +189,10 @@ impl EmissionGuarantee for () {
     }
 
     fn make_diagnostic_builder(
-        handler: &Handler,
+        dcx: &DiagCtxt,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, Self> {
-        DiagnosticBuilder::new(handler, Level::Warning(None), msg)
+        DiagnosticBuilder::new(dcx, Level::Warning(None), msg)
     }
 }
 
@@ -204,10 +204,10 @@ pub struct Noted;
 impl EmissionGuarantee for Noted {
     fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
         match db.inner.state {
-            // First `.emit()` call, the `&Handler` is still available.
-            DiagnosticBuilderState::Emittable(handler) => {
+            // First `.emit()` call, the `&DiagCtxt` is still available.
+            DiagnosticBuilderState::Emittable(dcx) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
-                handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
+                dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
             }
             // `.emit()` was previously called, disallowed from repeating it.
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
@@ -217,10 +217,10 @@ impl EmissionGuarantee for Noted {
     }
 
     fn make_diagnostic_builder(
-        handler: &Handler,
+        dcx: &DiagCtxt,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, Self> {
-        DiagnosticBuilder::new(handler, Level::Note, msg)
+        DiagnosticBuilder::new(dcx, Level::Note, msg)
     }
 }
 
@@ -232,11 +232,11 @@ pub struct Bug;
 impl EmissionGuarantee for Bug {
     fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
         match db.inner.state {
-            // First `.emit()` call, the `&Handler` is still available.
-            DiagnosticBuilderState::Emittable(handler) => {
+            // First `.emit()` call, the `&DiagCtxt` is still available.
+            DiagnosticBuilderState::Emittable(dcx) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
 
-                handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
+                dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
             }
             // `.emit()` was previously called, disallowed from repeating it.
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
@@ -246,21 +246,21 @@ impl EmissionGuarantee for Bug {
     }
 
     fn make_diagnostic_builder(
-        handler: &Handler,
+        dcx: &DiagCtxt,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, Self> {
-        DiagnosticBuilder::new(handler, Level::Bug, msg)
+        DiagnosticBuilder::new(dcx, Level::Bug, msg)
     }
 }
 
 impl EmissionGuarantee for ! {
     fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
         match db.inner.state {
-            // First `.emit()` call, the `&Handler` is still available.
-            DiagnosticBuilderState::Emittable(handler) => {
+            // First `.emit()` call, the `&DiagCtxt` is still available.
+            DiagnosticBuilderState::Emittable(dcx) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
 
-                handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
+                dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
             }
             // `.emit()` was previously called, disallowed from repeating it.
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
@@ -270,21 +270,21 @@ impl EmissionGuarantee for ! {
     }
 
     fn make_diagnostic_builder(
-        handler: &Handler,
+        dcx: &DiagCtxt,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, Self> {
-        DiagnosticBuilder::new(handler, Level::Fatal, msg)
+        DiagnosticBuilder::new(dcx, Level::Fatal, msg)
     }
 }
 
 impl EmissionGuarantee for rustc_span::fatal_error::FatalError {
     fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
         match db.inner.state {
-            // First `.emit()` call, the `&Handler` is still available.
-            DiagnosticBuilderState::Emittable(handler) => {
+            // First `.emit()` call, the `&DiagCtxt` is still available.
+            DiagnosticBuilderState::Emittable(dcx) => {
                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
 
-                handler.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
+                dcx.emit_diagnostic_without_consuming(&mut db.inner.diagnostic);
             }
             // `.emit()` was previously called, disallowed from repeating it.
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
@@ -294,10 +294,10 @@ impl EmissionGuarantee for rustc_span::fatal_error::FatalError {
     }
 
     fn make_diagnostic_builder(
-        handler: &Handler,
+        dcx: &DiagCtxt,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, Self> {
-        DiagnosticBuilder::new(handler, Level::Fatal, msg)
+        DiagnosticBuilder::new(dcx, Level::Fatal, msg)
     }
 }
 
@@ -340,25 +340,25 @@ impl<G: EmissionGuarantee> DerefMut for DiagnosticBuilder<'_, G> {
 
 impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
     /// Convenience function for internal use, clients should use one of the
-    /// `struct_*` methods on [`Handler`].
+    /// `struct_*` methods on [`DiagCtxt`].
     #[track_caller]
     pub(crate) fn new<M: Into<DiagnosticMessage>>(
-        handler: &'a Handler,
+        dcx: &'a DiagCtxt,
         level: Level,
         message: M,
     ) -> Self {
         let diagnostic = Diagnostic::new(level, message);
-        Self::new_diagnostic(handler, diagnostic)
+        Self::new_diagnostic(dcx, diagnostic)
     }
 
     /// Creates a new `DiagnosticBuilder` with an already constructed
     /// diagnostic.
     #[track_caller]
-    pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
+    pub(crate) fn new_diagnostic(dcx: &'a DiagCtxt, diagnostic: Diagnostic) -> Self {
         debug!("Created new diagnostic");
         Self {
             inner: DiagnosticBuilderInner {
-                state: DiagnosticBuilderState::Emittable(handler),
+                state: DiagnosticBuilderState::Emittable(dcx),
                 diagnostic: Box::new(diagnostic),
             },
             _marker: PhantomData,
@@ -398,7 +398,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
 
     /// Stashes diagnostic for possible later improvement in a different,
     /// later stage of the compiler. The diagnostic can be accessed with
-    /// the provided `span` and `key` through [`Handler::steal_diagnostic()`].
+    /// the provided `span` and `key` through [`DiagCtxt::steal_diagnostic()`].
     ///
     /// As with `buffer`, this is unless the handler has disabled such buffering.
     pub fn stash(self, span: Span, key: StashKey) {
@@ -409,18 +409,18 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
 
     /// Converts the builder to a `Diagnostic` for later emission,
     /// unless handler has disabled such buffering, or `.emit()` was called.
-    pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> {
-        let handler = match self.inner.state {
-            // No `.emit()` calls, the `&Handler` is still available.
-            DiagnosticBuilderState::Emittable(handler) => handler,
+    pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a DiagCtxt)> {
+        let dcx = match self.inner.state {
+            // No `.emit()` calls, the `&DiagCtxt` is still available.
+            DiagnosticBuilderState::Emittable(dcx) => dcx,
             // `.emit()` was previously called, nothing we can do.
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {
                 return None;
             }
         };
 
-        if handler.inner.lock().flags.dont_buffer_diagnostics
-            || handler.inner.lock().flags.treat_err_as_bug.is_some()
+        if dcx.inner.lock().flags.dont_buffer_diagnostics
+            || dcx.inner.lock().flags.treat_err_as_bug.is_some()
         {
             self.emit();
             return None;
@@ -437,13 +437,13 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
         // actually emitted.
         debug!("buffer: diagnostic={:?}", diagnostic);
 
-        Some((diagnostic, handler))
+        Some((diagnostic, dcx))
     }
 
-    /// Retrieves the [`Handler`] if available
-    pub fn handler(&self) -> Option<&Handler> {
+    /// Retrieves the [`DiagCtxt`] if available
+    pub fn dcx(&self) -> Option<&DiagCtxt> {
         match self.inner.state {
-            DiagnosticBuilderState::Emittable(handler) => Some(handler),
+            DiagnosticBuilderState::Emittable(dcx) => Some(dcx),
             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => None,
         }
     }
@@ -640,15 +640,15 @@ impl Drop for DiagnosticBuilderInner<'_> {
     fn drop(&mut self) {
         match self.state {
             // No `.emit()` or `.cancel()` calls.
-            DiagnosticBuilderState::Emittable(handler) => {
+            DiagnosticBuilderState::Emittable(dcx) => {
                 if !panicking() {
-                    handler.emit_diagnostic(Diagnostic::new(
+                    dcx.emit_diagnostic(Diagnostic::new(
                         Level::Bug,
                         DiagnosticMessage::from(
                             "the following error was constructed but not emitted",
                         ),
                     ));
-                    handler.emit_diagnostic_without_consuming(&mut self.diagnostic);
+                    dcx.emit_diagnostic_without_consuming(&mut self.diagnostic);
                     panic!("error was constructed but not emitted");
                 }
             }
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 558262460c7..3e4b3ee758a 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -1,6 +1,6 @@
 use crate::diagnostic::DiagnosticLocation;
 use crate::{fluent_generated as fluent, AddToDiagnostic};
-use crate::{DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg};
+use crate::{DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, IntoDiagnostic, IntoDiagnosticArg};
 use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_hir as hir;
@@ -246,18 +246,18 @@ impl<Id> IntoDiagnosticArg for hir::def::Res<Id> {
 }
 
 impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
-    fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> {
+    fn into_diagnostic(self, dcx: &DiagCtxt) -> DiagnosticBuilder<'_, !> {
         let mut diag;
         match self {
             TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => {
-                diag = handler.struct_fatal(fluent::errors_target_invalid_address_space);
+                diag = dcx.struct_fatal(fluent::errors_target_invalid_address_space);
                 diag.set_arg("addr_space", addr_space);
                 diag.set_arg("cause", cause);
                 diag.set_arg("err", err);
                 diag
             }
             TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => {
-                diag = handler.struct_fatal(fluent::errors_target_invalid_bits);
+                diag = dcx.struct_fatal(fluent::errors_target_invalid_bits);
                 diag.set_arg("kind", kind);
                 diag.set_arg("bit", bit);
                 diag.set_arg("cause", cause);
@@ -265,31 +265,31 @@ impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
                 diag
             }
             TargetDataLayoutErrors::MissingAlignment { cause } => {
-                diag = handler.struct_fatal(fluent::errors_target_missing_alignment);
+                diag = dcx.struct_fatal(fluent::errors_target_missing_alignment);
                 diag.set_arg("cause", cause);
                 diag
             }
             TargetDataLayoutErrors::InvalidAlignment { cause, err } => {
-                diag = handler.struct_fatal(fluent::errors_target_invalid_alignment);
+                diag = dcx.struct_fatal(fluent::errors_target_invalid_alignment);
                 diag.set_arg("cause", cause);
                 diag.set_arg("err_kind", err.diag_ident());
                 diag.set_arg("align", err.align());
                 diag
             }
             TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => {
-                diag = handler.struct_fatal(fluent::errors_target_inconsistent_architecture);
+                diag = dcx.struct_fatal(fluent::errors_target_inconsistent_architecture);
                 diag.set_arg("dl", dl);
                 diag.set_arg("target", target);
                 diag
             }
             TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => {
-                diag = handler.struct_fatal(fluent::errors_target_inconsistent_pointer_width);
+                diag = dcx.struct_fatal(fluent::errors_target_inconsistent_pointer_width);
                 diag.set_arg("pointer_size", pointer_size);
                 diag.set_arg("target", target);
                 diag
             }
             TargetDataLayoutErrors::InvalidBitsSize { err } => {
-                diag = handler.struct_fatal(fluent::errors_target_invalid_bits_size);
+                diag = dcx.struct_fatal(fluent::errors_target_invalid_bits_size);
                 diag.set_arg("err", err);
                 diag
             }
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index ec37240e394..3fb993c3651 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -16,8 +16,8 @@ use crate::snippet::{
 use crate::styled_buffer::StyledBuffer;
 use crate::translation::{to_fluent_args, Translate};
 use crate::{
-    diagnostic::DiagnosticLocation, CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage,
-    FluentBundle, Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic,
+    diagnostic::DiagnosticLocation, CodeSuggestion, DiagCtxt, Diagnostic, DiagnosticId,
+    DiagnosticMessage, FluentBundle, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic,
     SubstitutionHighlight, SuggestionStyle, TerminalUrl,
 };
 use rustc_lint_defs::pluralize;
@@ -553,10 +553,10 @@ impl Emitter for EmitterWriter {
 }
 
 /// An emitter that does nothing when emitting a non-fatal diagnostic.
-/// Fatal diagnostics are forwarded to `fatal_handler` to avoid silent
+/// Fatal diagnostics are forwarded to `fatal_dcx` to avoid silent
 /// failures of rustc, as witnessed e.g. in issue #89358.
 pub struct SilentEmitter {
-    pub fatal_handler: Handler,
+    pub fatal_dcx: DiagCtxt,
     pub fatal_note: Option<String>,
 }
 
@@ -581,7 +581,7 @@ impl Emitter for SilentEmitter {
             if let Some(ref note) = self.fatal_note {
                 d.note(note.clone());
             }
-            self.fatal_handler.emit_diagnostic(d);
+            self.fatal_dcx.emit_diagnostic(d);
         }
     }
 }
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index 5f9e821a48c..303de0a93f6 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -1,7 +1,7 @@
 use super::*;
 
 use crate::emitter::ColorConfig;
-use crate::Handler;
+use crate::DiagCtxt;
 use rustc_span::BytePos;
 
 use std::str;
@@ -61,8 +61,8 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
         );
 
         let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1));
-        let handler = Handler::with_emitter(Box::new(je));
-        handler.span_err(span, "foo");
+        let dcx = DiagCtxt::with_emitter(Box::new(je));
+        dcx.span_err(span, "foo");
 
         let bytes = output.lock().unwrap();
         let actual_output = str::from_utf8(&bytes).unwrap();
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index cf73c638d85..959e26fec70 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -412,15 +412,15 @@ use std::backtrace::{Backtrace, BacktraceStatus};
 /// A handler deals with errors and other compiler output.
 /// Certain errors (fatal, bug, unimpl) may cause immediate exit,
 /// others log errors for later reporting.
-pub struct Handler {
-    inner: Lock<HandlerInner>,
+pub struct DiagCtxt {
+    inner: Lock<DiagCtxtInner>,
 }
 
 /// This inner struct exists to keep it all behind a single lock;
 /// this is done to prevent possible deadlocks in a multi-threaded compiler,
 /// as well as inconsistent state observation.
-struct HandlerInner {
-    flags: HandlerFlags,
+struct DiagCtxtInner {
+    flags: DiagCtxtFlags,
     /// The number of lint errors that have been emitted.
     lint_err_count: usize,
     /// The number of errors that have been emitted, including duplicates.
@@ -518,7 +518,7 @@ pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&mut Diagnostic, &mut dyn FnMut(&mut
     AtomicRef::new(&(default_track_diagnostic as _));
 
 #[derive(Copy, Clone, Default)]
-pub struct HandlerFlags {
+pub struct DiagCtxtFlags {
     /// If false, warning-level lints are suppressed.
     /// (rustc: see `--allow warnings` and `--cap-lints`)
     pub can_emit_warnings: bool,
@@ -540,7 +540,7 @@ pub struct HandlerFlags {
     pub track_diagnostics: bool,
 }
 
-impl Drop for HandlerInner {
+impl Drop for DiagCtxtInner {
     fn drop(&mut self) {
         self.emit_stashed_diagnostics();
 
@@ -572,7 +572,7 @@ impl Drop for HandlerInner {
     }
 }
 
-impl Handler {
+impl DiagCtxt {
     pub fn with_tty_emitter(
         sm: Option<Lrc<SourceMap>>,
         fallback_bundle: LazyFallbackBundle,
@@ -585,7 +585,7 @@ impl Handler {
         self
     }
 
-    pub fn with_flags(mut self, flags: HandlerFlags) -> Self {
+    pub fn with_flags(mut self, flags: DiagCtxtFlags) -> Self {
         self.inner.get_mut().flags = flags;
         self
     }
@@ -597,8 +597,8 @@ impl Handler {
 
     pub fn with_emitter(emitter: Box<DynEmitter>) -> Self {
         Self {
-            inner: Lock::new(HandlerInner {
-                flags: HandlerFlags { can_emit_warnings: true, ..Default::default() },
+            inner: Lock::new(DiagCtxtInner {
+                flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
                 lint_err_count: 0,
                 err_count: 0,
                 warn_count: 0,
@@ -1057,7 +1057,7 @@ impl Handler {
         inner.emit_diagnostic(diagnostic).unwrap()
     }
 
-    // FIXME(eddyb) note the comment inside `impl Drop for HandlerInner`, that's
+    // FIXME(eddyb) note the comment inside `impl Drop for DiagCtxtInner`, that's
     // where the explanation of what "good path" is (also, it should be renamed).
     pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
         let mut inner = self.inner.borrow_mut();
@@ -1396,12 +1396,12 @@ impl Handler {
     }
 
     /// This methods steals all [`LintExpectationId`]s that are stored inside
-    /// [`HandlerInner`] and indicate that the linked expectation has been fulfilled.
+    /// [`DiagCtxtInner`] and indicate that the linked expectation has been fulfilled.
     #[must_use]
     pub fn steal_fulfilled_expectation_ids(&self) -> FxHashSet<LintExpectationId> {
         assert!(
             self.inner.borrow().unstable_expect_diagnostics.is_empty(),
-            "`HandlerInner::unstable_expect_diagnostics` should be empty at this point",
+            "`DiagCtxtInner::unstable_expect_diagnostics` should be empty at this point",
         );
         std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations)
     }
@@ -1413,11 +1413,11 @@ impl Handler {
     }
 }
 
-// Note: we prefer implementing operations on `Handler`, rather than
-// `HandlerInner`, whenever possible. This minimizes functions where
-// `Handler::foo()` just borrows `inner` and forwards a call to
+// Note: we prefer implementing operations on `DiagCtxt`, rather than
+// `DiagCtxtInner`, whenever possible. This minimizes functions where
+// `DiagCtxt::foo()` just borrows `inner` and forwards a call to
 // `HanderInner::foo`.
-impl HandlerInner {
+impl DiagCtxtInner {
     /// Emit all stashed diagnostics.
     fn emit_stashed_diagnostics(&mut self) -> Option<ErrorGuaranteed> {
         let has_errors = self.has_errors();
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index d75556ac7c4..b63609c48e9 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -790,7 +790,7 @@ impl SyntaxExtension {
             .map(|attr| {
                 // Override `helper_attrs` passed above if it's a built-in macro,
                 // marking `proc_macro_derive` macros as built-in is not a realistic use case.
-                parse_macro_name_and_helper_attrs(sess.diagnostic(), attr, "built-in").map_or_else(
+                parse_macro_name_and_helper_attrs(sess.dcx(), attr, "built-in").map_or_else(
                     || (Some(name), Vec::new()),
                     |(name, helper_attrs)| (Some(name), helper_attrs),
                 )
@@ -1119,7 +1119,7 @@ impl<'a> ExtCtxt<'a> {
         sp: S,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        self.sess.diagnostic().struct_span_err(sp, msg)
+        self.sess.dcx().struct_span_err(sp, msg)
     }
 
     #[track_caller]
@@ -1143,10 +1143,10 @@ impl<'a> ExtCtxt<'a> {
     #[rustc_lint_diagnostics]
     #[track_caller]
     pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
-        self.sess.diagnostic().span_err(sp, msg);
+        self.sess.dcx().span_err(sp, msg);
     }
     pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.sess.diagnostic().span_bug(sp, msg);
+        self.sess.dcx().span_bug(sp, msg);
     }
     pub fn trace_macros_diag(&mut self) {
         for (span, notes) in self.expansions.iter() {
@@ -1160,7 +1160,7 @@ impl<'a> ExtCtxt<'a> {
         self.expansions.clear();
     }
     pub fn bug(&self, msg: &'static str) -> ! {
-        self.sess.diagnostic().bug(msg);
+        self.sess.dcx().bug(msg);
     }
     pub fn trace_macros(&self) -> bool {
         self.ecfg.trace_mac
@@ -1208,7 +1208,7 @@ pub fn resolve_path(
                     span,
                     path: parse_sess.source_map().filename_for_diagnostics(&other).to_string(),
                 }
-                .into_diagnostic(&parse_sess.span_diagnostic));
+                .into_diagnostic(&parse_sess.dcx));
             }
         };
         result.pop();
@@ -1350,7 +1350,7 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, tts: TokenStream) -> Option<Vec<
 }
 
 pub fn parse_macro_name_and_helper_attrs(
-    diag: &rustc_errors::Handler,
+    dcx: &rustc_errors::DiagCtxt,
     attr: &Attribute,
     macro_type: &str,
 ) -> Option<(Symbol, Vec<Symbol>)> {
@@ -1359,23 +1359,23 @@ pub fn parse_macro_name_and_helper_attrs(
     // `#[proc_macro_derive(Foo, attributes(A, ..))]`
     let list = attr.meta_item_list()?;
     if list.len() != 1 && list.len() != 2 {
-        diag.emit_err(errors::AttrNoArguments { span: attr.span });
+        dcx.emit_err(errors::AttrNoArguments { span: attr.span });
         return None;
     }
     let Some(trait_attr) = list[0].meta_item() else {
-        diag.emit_err(errors::NotAMetaItem { span: list[0].span() });
+        dcx.emit_err(errors::NotAMetaItem { span: list[0].span() });
         return None;
     };
     let trait_ident = match trait_attr.ident() {
         Some(trait_ident) if trait_attr.is_word() => trait_ident,
         _ => {
-            diag.emit_err(errors::OnlyOneWord { span: trait_attr.span });
+            dcx.emit_err(errors::OnlyOneWord { span: trait_attr.span });
             return None;
         }
     };
 
     if !trait_ident.name.can_be_raw() {
-        diag.emit_err(errors::CannotBeNameOfMacro {
+        dcx.emit_err(errors::CannotBeNameOfMacro {
             span: trait_attr.span,
             trait_ident,
             macro_type,
@@ -1385,29 +1385,29 @@ pub fn parse_macro_name_and_helper_attrs(
     let attributes_attr = list.get(1);
     let proc_attrs: Vec<_> = if let Some(attr) = attributes_attr {
         if !attr.has_name(sym::attributes) {
-            diag.emit_err(errors::ArgumentNotAttributes { span: attr.span() });
+            dcx.emit_err(errors::ArgumentNotAttributes { span: attr.span() });
         }
         attr.meta_item_list()
             .unwrap_or_else(|| {
-                diag.emit_err(errors::AttributesWrongForm { span: attr.span() });
+                dcx.emit_err(errors::AttributesWrongForm { span: attr.span() });
                 &[]
             })
             .iter()
             .filter_map(|attr| {
                 let Some(attr) = attr.meta_item() else {
-                    diag.emit_err(errors::AttributeMetaItem { span: attr.span() });
+                    dcx.emit_err(errors::AttributeMetaItem { span: attr.span() });
                     return None;
                 };
 
                 let ident = match attr.ident() {
                     Some(ident) if attr.is_word() => ident,
                     _ => {
-                        diag.emit_err(errors::AttributeSingleWord { span: attr.span });
+                        dcx.emit_err(errors::AttributeSingleWord { span: attr.span });
                         return None;
                     }
                 };
                 if !ident.name.can_be_raw() {
-                    diag.emit_err(errors::HelperAttributeNameInvalid {
+                    dcx.emit_err(errors::HelperAttributeNameInvalid {
                         span: attr.span,
                         name: ident,
                     });
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 0b1f25b67c8..e66cfbe6fb6 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -205,7 +205,7 @@ pub(super) fn check_meta_variables(
     rhses: &[TokenTree],
 ) -> bool {
     if lhses.len() != rhses.len() {
-        sess.span_diagnostic.span_bug(span, "length mismatch between LHSes and RHSes")
+        sess.dcx.span_bug(span, "length mismatch between LHSes and RHSes")
     }
     let mut valid = true;
     for (lhs, rhs) in iter::zip(lhses, rhses) {
@@ -244,7 +244,7 @@ fn check_binders(
         // MetaVar(fragment) and not as MetaVarDecl(y, fragment).
         TokenTree::MetaVar(span, name) => {
             if macros.is_empty() {
-                sess.span_diagnostic.span_bug(span, "unexpected MetaVar in lhs");
+                sess.dcx.span_bug(span, "unexpected MetaVar in lhs");
             }
             let name = MacroRulesNormalizedIdent::new(name);
             // There are 3 possibilities:
@@ -275,14 +275,13 @@ fn check_binders(
                 );
             }
             if !macros.is_empty() {
-                sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in nested lhs");
+                sess.dcx.span_bug(span, "unexpected MetaVarDecl in nested lhs");
             }
             let name = MacroRulesNormalizedIdent::new(name);
             if let Some(prev_info) = get_binder_info(macros, binders, name) {
                 // Duplicate binders at the top-level macro definition are errors. The lint is only
                 // for nested macro definitions.
-                sess.span_diagnostic
-                    .emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span });
+                sess.dcx.emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span });
                 *valid = false;
             } else {
                 binders.insert(name, BinderInfo { span, ops: ops.into() });
@@ -341,7 +340,7 @@ fn check_occurrences(
     match *rhs {
         TokenTree::Token(..) => {}
         TokenTree::MetaVarDecl(span, _name, _kind) => {
-            sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in rhs")
+            sess.dcx.span_bug(span, "unexpected MetaVarDecl in rhs")
         }
         TokenTree::MetaVar(span, name) => {
             let name = MacroRulesNormalizedIdent::new(name);
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 14d22cbe2dd..44f10e7d380 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -402,7 +402,7 @@ pub fn compile_declarative_macro(
     };
     let dummy_syn_ext = || (mk_syn_ext(Box::new(macro_rules_dummy_expander)), Vec::new());
 
-    let diag = &sess.parse_sess.span_diagnostic;
+    let dcx = &sess.parse_sess.dcx;
     let lhs_nm = Ident::new(sym::lhs, def.span);
     let rhs_nm = Ident::new(sym::rhs, def.span);
     let tt_spec = Some(NonterminalKind::TT);
@@ -482,14 +482,14 @@ pub fn compile_declarative_macro(
 
                 let s = parse_failure_msg(&token);
                 let sp = token.span.substitute_dummy(def.span);
-                let mut err = sess.diagnostic().struct_span_err(sp, s);
+                let mut err = sess.dcx().struct_span_err(sp, s);
                 err.span_label(sp, msg);
                 annotate_doc_comment(&mut err, sess.source_map(), sp);
                 err.emit();
                 return dummy_syn_ext();
             }
             Error(sp, msg) => {
-                sess.diagnostic().struct_span_err(sp.substitute_dummy(def.span), msg).emit();
+                sess.dcx().struct_span_err(sp.substitute_dummy(def.span), msg).emit();
                 return dummy_syn_ext();
             }
             ErrorReported(_) => {
@@ -518,10 +518,10 @@ pub fn compile_declarative_macro(
                     valid &= check_lhs_nt_follows(&sess.parse_sess, def, &tt);
                     return tt;
                 }
-                sess.diagnostic().span_bug(def.span, "wrong-structured lhs")
+                sess.dcx().span_bug(def.span, "wrong-structured lhs")
             })
             .collect::<Vec<mbe::TokenTree>>(),
-        _ => sess.diagnostic().span_bug(def.span, "wrong-structured lhs"),
+        _ => sess.dcx().span_bug(def.span, "wrong-structured lhs"),
     };
 
     let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
@@ -540,10 +540,10 @@ pub fn compile_declarative_macro(
                     .pop()
                     .unwrap();
                 }
-                sess.diagnostic().span_bug(def.span, "wrong-structured rhs")
+                sess.dcx().span_bug(def.span, "wrong-structured rhs")
             })
             .collect::<Vec<mbe::TokenTree>>(),
-        _ => sess.diagnostic().span_bug(def.span, "wrong-structured rhs"),
+        _ => sess.dcx().span_bug(def.span, "wrong-structured rhs"),
     };
 
     for rhs in &rhses {
@@ -560,10 +560,10 @@ pub fn compile_declarative_macro(
     let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules);
     match transparency_error {
         Some(TransparencyError::UnknownTransparency(value, span)) => {
-            diag.span_err(span, format!("unknown macro transparency: `{value}`"));
+            dcx.span_err(span, format!("unknown macro transparency: `{value}`"));
         }
         Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) => {
-            diag.span_err(vec![old_span, new_span], "multiple macro transparency attributes");
+            dcx.span_err(vec![old_span, new_span], "multiple macro transparency attributes");
         }
         None => {}
     }
@@ -599,7 +599,7 @@ pub fn compile_declarative_macro(
                     mbe::TokenTree::Delimited(.., delimited) => {
                         mbe::macro_parser::compute_locs(&delimited.tts)
                     }
-                    _ => sess.diagnostic().span_bug(def.span, "malformed macro lhs"),
+                    _ => sess.dcx().span_bug(def.span, "malformed macro lhs"),
                 }
             })
             .collect()
@@ -626,7 +626,7 @@ fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree)
         check_matcher(sess, def, &delimited.tts)
     } else {
         let msg = "invalid macro matcher; matchers must be contained in balanced delimiters";
-        sess.span_diagnostic.span_err(lhs.span(), msg);
+        sess.dcx.span_err(lhs.span(), msg);
         false
     }
     // we don't abort on errors on rejection, the driver will do that for us
@@ -652,8 +652,7 @@ fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool
                         iter.next();
                     }
                     let span = t.span.to(now.span);
-                    sess.span_diagnostic
-                        .span_note(span, "doc comments are ignored in matcher position");
+                    sess.dcx.span_note(span, "doc comments are ignored in matcher position");
                 }
                 mbe::TokenTree::Sequence(_, sub_seq)
                     if (sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore
@@ -683,7 +682,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool {
             TokenTree::Sequence(span, seq) => {
                 if is_empty_token_tree(sess, seq) {
                     let sp = span.entire();
-                    sess.span_diagnostic.span_err(sp, "repetition matches empty token tree");
+                    sess.dcx.span_err(sp, "repetition matches empty token tree");
                     return false;
                 }
                 if !check_lhs_no_empty_seq(sess, &seq.tts) {
@@ -700,7 +699,7 @@ fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool {
     match *rhs {
         mbe::TokenTree::Delimited(..) => return true,
         _ => {
-            sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited");
+            sess.dcx.span_err(rhs.span(), "macro rhs must be delimited");
         }
     }
     false
@@ -709,9 +708,9 @@ fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool {
 fn check_matcher(sess: &ParseSess, def: &ast::Item, matcher: &[mbe::TokenTree]) -> bool {
     let first_sets = FirstSets::new(matcher);
     let empty_suffix = TokenSet::empty();
-    let err = sess.span_diagnostic.err_count();
+    let err = sess.dcx.err_count();
     check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix);
-    err == sess.span_diagnostic.err_count()
+    err == sess.dcx.err_count()
 }
 
 fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool {
@@ -1190,7 +1189,7 @@ fn check_matcher_core<'tt>(
                             };
 
                             let sp = next_token.span();
-                            let mut err = sess.span_diagnostic.struct_span_err(
+                            let mut err = sess.dcx.struct_span_err(
                                 sp,
                                 format!(
                                     "`${name}:{frag}` {may_be} followed by `{next}`, which \
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index 4b8c6feb93e..e3dc73d0d85 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -36,7 +36,7 @@ impl MetaVarExpr {
         let ident = parse_ident(&mut tts, sess, outer_span)?;
         let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, args)) = tts.next() else {
             let msg = "meta-variable expression parameter must be wrapped in parentheses";
-            return Err(sess.span_diagnostic.struct_span_err(ident.span, msg));
+            return Err(sess.dcx.struct_span_err(ident.span, msg));
         };
         check_trailing_token(&mut tts, sess)?;
         let mut iter = args.trees();
@@ -50,7 +50,7 @@ impl MetaVarExpr {
             "length" => MetaVarExpr::Length(parse_depth(&mut iter, sess, ident.span)?),
             _ => {
                 let err_msg = "unrecognized meta-variable expression";
-                let mut err = sess.span_diagnostic.struct_span_err(ident.span, err_msg);
+                let mut err = sess.dcx.struct_span_err(ident.span, err_msg);
                 err.span_suggestion(
                     ident.span,
                     "supported expressions are count, ignore, index and length",
@@ -79,7 +79,7 @@ fn check_trailing_token<'sess>(
 ) -> PResult<'sess, ()> {
     if let Some(tt) = iter.next() {
         let mut diag = sess
-            .span_diagnostic
+            .dcx
             .struct_span_err(tt.span(), format!("unexpected token: {}", pprust::tt_to_string(tt)));
         diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens");
         Err(diag)
@@ -98,7 +98,7 @@ fn parse_count<'sess>(
     let ident = parse_ident(iter, sess, span)?;
     let depth = if try_eat_comma(iter) {
         if iter.look_ahead(0).is_none() {
-            return Err(sess.span_diagnostic.struct_span_err(
+            return Err(sess.dcx.struct_span_err(
                 span,
                 "`count` followed by a comma must have an associated index indicating its depth",
             ));
@@ -119,7 +119,7 @@ fn parse_depth<'sess>(
     let Some(tt) = iter.next() else { return Ok(0) };
     let TokenTree::Token(token::Token { kind: token::TokenKind::Literal(lit), .. }, _) = tt else {
         return Err(sess
-            .span_diagnostic
+            .dcx
             .struct_span_err(span, "meta-variable expression depth must be a literal"));
     };
     if let Ok(lit_kind) = LitKind::from_token_lit(*lit)
@@ -129,7 +129,7 @@ fn parse_depth<'sess>(
         Ok(n_usize)
     } else {
         let msg = "only unsuffixes integer literals are supported in meta-variable expressions";
-        Err(sess.span_diagnostic.struct_span_err(span, msg))
+        Err(sess.dcx.struct_span_err(span, msg))
     }
 }
 
@@ -146,9 +146,8 @@ fn parse_ident<'sess>(
             return Ok(elem);
         }
         let token_str = pprust::token_to_string(token);
-        let mut err = sess
-            .span_diagnostic
-            .struct_span_err(span, format!("expected identifier, found `{}`", &token_str));
+        let mut err =
+            sess.dcx.struct_span_err(span, format!("expected identifier, found `{}`", &token_str));
         err.span_suggestion(
             token.span,
             format!("try removing `{}`", &token_str),
@@ -157,7 +156,7 @@ fn parse_ident<'sess>(
         );
         return Err(err);
     }
-    Err(sess.span_diagnostic.struct_span_err(span, "expected identifier"))
+    Err(sess.dcx.struct_span_err(span, "expected identifier"))
 }
 
 /// Tries to move the iterator forward returning `true` if there is a comma. If not, then the
@@ -181,7 +180,7 @@ fn eat_dollar<'sess>(
         let _ = iter.next();
         return Ok(());
     }
-    Err(sess.span_diagnostic.struct_span_err(
+    Err(sess.dcx.struct_span_err(
         span,
         "meta-variables within meta-variable expressions must be referenced using a dollar sign",
     ))
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index ab9fb20b364..445be01bc97 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -84,7 +84,7 @@ pub(super) fn parse(
                                                     "invalid fragment specifier `{}`",
                                                     frag.name
                                                 );
-                                                sess.span_diagnostic
+                                                sess.dcx
                                                     .struct_span_err(span, msg)
                                                     .help(VALID_FRAGMENT_NAMES_MSG)
                                                     .emit();
@@ -195,7 +195,7 @@ fn parse_tree<'a>(
                             _ => {
                                 let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
                                 let msg = format!("expected `(` or `{{`, found `{tok}`");
-                                sess.span_diagnostic.span_err(delim_span.entire(), msg);
+                                sess.dcx.span_err(delim_span.entire(), msg);
                             }
                         }
                     }
@@ -244,7 +244,7 @@ fn parse_tree<'a>(
                 Some(tokenstream::TokenTree::Token(token, _)) => {
                     let msg =
                         format!("expected identifier, found `{}`", pprust::token_to_string(token),);
-                    sess.span_diagnostic.span_err(token.span, msg);
+                    sess.dcx.span_err(token.span, msg);
                     TokenTree::MetaVar(token.span, Ident::empty())
                 }
 
@@ -325,7 +325,7 @@ fn parse_sep_and_kleene_op<'a>(
             // #2 is the `?` Kleene op, which does not take a separator (error)
             Ok(Ok((KleeneOp::ZeroOrOne, span))) => {
                 // Error!
-                sess.span_diagnostic.span_err(
+                sess.dcx.span_err(
                     token.span,
                     "the `?` macro repetition operator does not take a separator",
                 );
@@ -346,7 +346,7 @@ fn parse_sep_and_kleene_op<'a>(
     };
 
     // If we ever get to this point, we have experienced an "unexpected token" error
-    sess.span_diagnostic.span_err(span, "expected one of: `*`, `+`, or `?`");
+    sess.dcx.span_err(span, "expected one of: `*`, `+`, or `?`");
 
     // Return a dummy
     (None, KleeneToken::new(KleeneOp::ZeroOrMore, span))
@@ -356,9 +356,8 @@ fn parse_sep_and_kleene_op<'a>(
 //
 // For example, `macro_rules! foo { ( ${length()} ) => {} }`
 fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &ParseSess, token: &Token) {
-    sess.span_diagnostic
-        .span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token)));
-    sess.span_diagnostic.span_note(
+    sess.dcx.span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token)));
+    sess.dcx.span_note(
         token.span,
         "`$$` and meta-variable expressions are not allowed inside macro parameter definitions",
     );
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index d08026b9c14..429bfa61450 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -156,7 +156,7 @@ impl MultiItemModifier for DeriveProcMacro {
             }
         };
 
-        let error_count_before = ecx.sess.diagnostic().err_count();
+        let error_count_before = ecx.sess.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,7 +179,7 @@ impl MultiItemModifier for DeriveProcMacro {
         }
 
         // fail if there have been errors emitted
-        if ecx.sess.diagnostic().err_count() > error_count_before {
+        if ecx.sess.dcx().err_count() > error_count_before {
             ecx.sess.emit_err(errors::ProcMacroDeriveTokens { span });
         }
 
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 4f439c15fbb..c412b064ce9 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -506,7 +506,7 @@ impl server::FreeFunctions for Rustc<'_, '_> {
                 None,
             );
         }
-        self.sess().span_diagnostic.emit_diagnostic(diag);
+        self.sess().dcx.emit_diagnostic(diag);
     }
 }
 
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index b4724b0e9d0..0b859841828 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -8,7 +8,7 @@ use rustc_span::{BytePos, Span};
 
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::{Handler, MultiSpan, PResult};
+use rustc_errors::{DiagCtxt, MultiSpan, PResult};
 use termcolor::WriteColor;
 
 use std::io;
@@ -23,7 +23,7 @@ fn string_to_parser(ps: &ParseSess, source_str: String) -> Parser<'_> {
     new_parser_from_source_str(ps, PathBuf::from("bogofile").into(), source_str)
 }
 
-fn create_test_handler() -> (Handler, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
+fn create_test_handler() -> (DiagCtxt, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
     let output = Arc::new(Mutex::new(Vec::new()));
     let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
     let fallback_bundle = rustc_errors::fallback_fluent_bundle(
@@ -33,8 +33,8 @@ fn create_test_handler() -> (Handler, Lrc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
     let emitter = EmitterWriter::new(Box::new(Shared { data: output.clone() }), fallback_bundle)
         .sm(Some(source_map.clone()))
         .diagnostic_width(Some(140));
-    let handler = Handler::with_emitter(Box::new(emitter));
-    (handler, source_map, output)
+    let dcx = DiagCtxt::with_emitter(Box::new(emitter));
+    (dcx, source_map, output)
 }
 
 /// Returns the result of parsing the given string via the given callback.
@@ -46,7 +46,7 @@ where
 {
     let mut p = string_to_parser(&ps, s);
     let x = f(&mut p).unwrap();
-    p.sess.span_diagnostic.abort_if_errors();
+    p.sess.dcx.abort_if_errors();
     x
 }
 
@@ -57,7 +57,7 @@ where
     F: for<'a> FnOnce(&mut Parser<'a>) -> PResult<'a, T>,
 {
     let (handler, source_map, output) = create_test_handler();
-    let ps = ParseSess::with_span_handler(handler, source_map);
+    let ps = ParseSess::with_dcx(handler, source_map);
     let mut p = string_to_parser(&ps, source_str.to_string());
     let result = f(&mut p);
     assert!(result.is_ok());
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 64026cdfff4..b2ff7959106 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1607,15 +1607,10 @@ fn check_method_receiver<'tcx>(
 }
 
 fn e0307(tcx: TyCtxt<'_>, span: Span, receiver_ty: Ty<'_>) -> ErrorGuaranteed {
-    struct_span_err!(
-        tcx.sess.diagnostic(),
-        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()
+    struct_span_err!(tcx.sess.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()
 }
 
 /// Returns whether `receiver_ty` would be considered a valid receiver type for `self_ty`. If
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 88128d22a3d..d33cfe4ad4d 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -453,7 +453,7 @@ fn lint_auto_trait_impl<'tcx>(
     impl_def_id: LocalDefId,
 ) {
     if trait_ref.args.len() != 1 {
-        tcx.sess.diagnostic().span_delayed_bug(
+        tcx.sess.dcx().span_delayed_bug(
             tcx.def_span(impl_def_id),
             "auto traits cannot have generic parameters",
         );
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index d176665e4c0..688d32fa32d 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -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.diagnostic().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
+            if !tcx.sess.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType)
                 && !(is_suggestable_infer_ty(ty) && body_id.is_some())
             {
                 // Account for `const C: _;`.
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 174217d3b70..15d546537dd 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -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.diagnostic().steal_diagnostic(span, StashKey::ItemNoType) {
+    match tcx.sess.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/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index a4772293697..f461b6a94ec 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -2,7 +2,7 @@
 
 use crate::fluent_generated as fluent;
 use rustc_errors::{
-    error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic,
+    error_code, Applicability, DiagCtxt, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic,
     MultiSpan,
 };
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -317,8 +317,8 @@ pub struct MissingTypeParams {
 // Manual implementation of `IntoDiagnostic` to be able to call `span_to_snippet`.
 impl<'a> IntoDiagnostic<'a> for MissingTypeParams {
     #[track_caller]
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut err = handler.struct_span_err_with_code(
+    fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        let mut err = dcx.struct_span_err_with_code(
             self.span,
             fluent::hir_analysis_missing_type_params,
             error_code!(E0393),
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index baca2be06e6..51f38240033 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -417,7 +417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     && let Some(mut diag) = self
                         .tcx
                         .sess
-                        .diagnostic()
+                        .dcx()
                         .steal_diagnostic(segment.ident.span, StashKey::CallIntoMethod)
                 {
                     // Try suggesting `foo(a)` -> `a.foo()` if possible.
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 80265cf31e6..7bd2c3f8b6b 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -1436,12 +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
-                .diagnostic()
-                .steal_diagnostic(span, StashKey::UnderscoreForArrayLengths)
-            {
+            match self.tcx.sess.dcx().steal_diagnostic(span, StashKey::UnderscoreForArrayLengths) {
                 Some(mut err) => {
                     err.span_suggestion(
                         span,
@@ -2002,11 +1997,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 != range_def_id
         {
             // Suppress any range expr type mismatches
-            if let Some(mut diag) = self
-                .tcx
-                .sess
-                .diagnostic()
-                .steal_diagnostic(last_expr_field.span, StashKey::MaybeFruTypo)
+            if let Some(mut diag) =
+                self.tcx.sess.dcx().steal_diagnostic(last_expr_field.span, StashKey::MaybeFruTypo)
             {
                 diag.delay_as_bug();
             }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 3bee42eb89c..24b577fd3c5 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -848,7 +848,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     && let Some(mut diag) = self
                         .tcx
                         .sess
-                        .diagnostic()
+                        .dcx()
                         .steal_diagnostic(qself.span, StashKey::TraitMissingMethod)
                 {
                     diag.emit();
@@ -884,7 +884,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     && let Some(mut diag) = self
                         .tcx
                         .sess
-                        .diagnostic()
+                        .dcx()
                         .steal_diagnostic(qself.span, StashKey::TraitMissingMethod)
                 {
                     if trait_missing_method {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 3f97b24aa59..17022f1fd37 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1852,7 +1852,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) {
         for (span, code) in errors_causecode {
             let Some(mut diag) =
-                self.tcx.sess.diagnostic().steal_diagnostic(span, StashKey::MaybeForgetReturn)
+                self.tcx.sess.dcx().steal_diagnostic(span, StashKey::MaybeForgetReturn)
             else {
                 continue;
             };
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index f1f893623f6..13a24948611 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -413,21 +413,21 @@ enum TupleArgumentsFlag {
 }
 
 fn fatally_break_rust(tcx: TyCtxt<'_>) {
-    let handler = tcx.sess.diagnostic();
-    handler.span_bug_no_panic(
+    let dcx = tcx.sess.dcx();
+    dcx.span_bug_no_panic(
         MultiSpan::new(),
         "It looks like you're trying to break rust; would you like some ICE?",
     );
-    handler.note("the compiler expectedly panicked. this is a feature.");
-    handler.note(
+    dcx.note("the compiler expectedly panicked. this is a feature.");
+    dcx.note(
         "we would appreciate a joke overview: \
          https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
     );
-    handler.note(format!("rustc {} running on {}", tcx.sess.cfg_version, config::host_triple(),));
+    dcx.note(format!("rustc {} running on {}", tcx.sess.cfg_version, config::host_triple(),));
     if let Some((flags, excluded_cargo_defaults)) = rustc_session::utils::extra_compiler_flags() {
-        handler.note(format!("compiler flags: {}", flags.join(" ")));
+        dcx.note(format!("compiler flags: {}", flags.join(" ")));
         if excluded_cargo_defaults {
-            handler.note("some of the compiler flags provided by cargo are hidden");
+            dcx.note("some of the compiler flags provided by cargo are hidden");
         }
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 8fb703fa7f5..7595f21d9f1 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -1929,7 +1929,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         };
         let Some(mut diag) =
-            self.tcx.sess.diagnostic().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
+            self.tcx.sess.dcx().steal_diagnostic(seg1.ident.span, StashKey::CallAssocMethod)
         else {
             return;
         };
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 5e562d9453f..d0cf4575c8f 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -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.diagnostic().emit_diagnostic(diag);
+                    self.tcx().sess.dcx().emit_diagnostic(diag);
                 }
             }
         }
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 1caa9aa8cd6..817a4451dd1 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
@@ -376,7 +376,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 multi_suggestions,
                 bad_label,
             }
-            .into_diagnostic(self.tcx.sess.diagnostic()),
+            .into_diagnostic(self.tcx.sess.dcx()),
             TypeAnnotationNeeded::E0283 => AmbiguousImpl {
                 span,
                 source_kind,
@@ -386,7 +386,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 multi_suggestions,
                 bad_label,
             }
-            .into_diagnostic(self.tcx.sess.diagnostic()),
+            .into_diagnostic(self.tcx.sess.dcx()),
             TypeAnnotationNeeded::E0284 => AmbiguousReturn {
                 span,
                 source_kind,
@@ -396,7 +396,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 multi_suggestions,
                 bad_label,
             }
-            .into_diagnostic(self.tcx.sess.diagnostic()),
+            .into_diagnostic(self.tcx.sess.dcx()),
         }
     }
 }
@@ -583,7 +583,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 multi_suggestions,
                 bad_label: None,
             }
-            .into_diagnostic(self.tcx.sess.diagnostic()),
+            .into_diagnostic(self.tcx.sess.dcx()),
             TypeAnnotationNeeded::E0283 => AmbiguousImpl {
                 span,
                 source_kind,
@@ -593,7 +593,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 multi_suggestions,
                 bad_label: None,
             }
-            .into_diagnostic(self.tcx.sess.diagnostic()),
+            .into_diagnostic(self.tcx.sess.dcx()),
             TypeAnnotationNeeded::E0284 => AmbiguousReturn {
                 span,
                 source_kind,
@@ -603,7 +603,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 multi_suggestions,
                 bad_label: None,
             }
-            .into_diagnostic(self.tcx.sess.diagnostic()),
+            .into_diagnostic(self.tcx.sess.dcx()),
         }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 1e365848e07..859c10ef142 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -140,7 +140,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     span,
                     notes: reference_valid.into_iter().chain(content_valid).collect(),
                 }
-                .into_diagnostic(self.tcx.sess.diagnostic())
+                .into_diagnostic(self.tcx.sess.dcx())
             }
             infer::RelateObjectBound(span) => {
                 let object_valid = note_and_explain::RegionExplanation::new(
@@ -161,7 +161,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     span,
                     notes: object_valid.into_iter().chain(pointer_valid).collect(),
                 }
-                .into_diagnostic(self.tcx.sess.diagnostic())
+                .into_diagnostic(self.tcx.sess.dcx())
             }
             infer::RelateParamBound(span, ty, opt_span) => {
                 let prefix = match *sub {
@@ -177,7 +177,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     self.tcx, sub, opt_span, prefix, suffix,
                 );
                 FulfillReqLifetime { span, ty: self.resolve_vars_if_possible(ty), note }
-                    .into_diagnostic(self.tcx.sess.diagnostic())
+                    .into_diagnostic(self.tcx.sess.dcx())
             }
             infer::RelateRegionParamBound(span) => {
                 let param_instantiated = note_and_explain::RegionExplanation::new(
@@ -198,7 +198,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     span,
                     notes: param_instantiated.into_iter().chain(param_must_outlive).collect(),
                 }
-                .into_diagnostic(self.tcx.sess.diagnostic())
+                .into_diagnostic(self.tcx.sess.dcx())
             }
             infer::ReferenceOutlivesReferent(ty, span) => {
                 let pointer_valid = note_and_explain::RegionExplanation::new(
@@ -220,7 +220,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ty: self.resolve_vars_if_possible(ty),
                     notes: pointer_valid.into_iter().chain(data_valid).collect(),
                 }
-                .into_diagnostic(self.tcx.sess.diagnostic())
+                .into_diagnostic(self.tcx.sess.dcx())
             }
             infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
                 let mut err = self.report_extra_impl_obligation(
@@ -281,7 +281,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     span,
                     notes: instantiated.into_iter().chain(must_outlive).collect(),
                 }
-                .into_diagnostic(self.tcx.sess.diagnostic())
+                .into_diagnostic(self.tcx.sess.dcx())
             }
         };
         if sub.is_error() || sup.is_error() {
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 6527e87d396..d58d60fc8be 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -8,7 +8,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stable_hasher::StableHasher;
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::registry::Registry;
-use rustc_errors::{ErrorGuaranteed, Handler};
+use rustc_errors::{DiagCtxt, ErrorGuaranteed};
 use rustc_lint::LintStore;
 use rustc_middle::ty;
 use rustc_middle::util::Providers;
@@ -18,7 +18,7 @@ use rustc_query_system::query::print_query_stack;
 use rustc_session::config::{self, Cfg, CheckCfg, ExpectedValues, Input, OutFileName};
 use rustc_session::filesearch::sysroot_candidates;
 use rustc_session::parse::ParseSess;
-use rustc_session::{lint, CompilerIO, EarlyErrorHandler, Session};
+use rustc_session::{lint, CompilerIO, EarlyDiagCtxt, Session};
 use rustc_span::source_map::FileLoader;
 use rustc_span::symbol::sym;
 use rustc_span::FileName;
@@ -42,7 +42,7 @@ pub struct Compiler {
 }
 
 /// Converts strings provided as `--cfg [cfgspec]` into a `Cfg`.
-pub(crate) fn parse_cfg(handler: &Handler, cfgs: Vec<String>) -> Cfg {
+pub(crate) fn parse_cfg(dcx: &DiagCtxt, cfgs: Vec<String>) -> Cfg {
     cfgs.into_iter()
         .map(|s| {
             let sess = ParseSess::with_silent_emitter(Some(format!(
@@ -54,12 +54,11 @@ pub(crate) fn parse_cfg(handler: &Handler, cfgs: Vec<String>) -> Cfg {
                 ($reason: expr) => {
                     #[allow(rustc::untranslatable_diagnostic)]
                     #[allow(rustc::diagnostic_outside_of_impl)]
-                    handler
-                        .struct_fatal(format!(
-                            concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
-                            s
-                        ))
-                        .emit();
+                    dcx.struct_fatal(format!(
+                        concat!("invalid `--cfg` argument: `{}` (", $reason, ")"),
+                        s
+                    ))
+                    .emit();
                 };
             }
 
@@ -101,7 +100,7 @@ pub(crate) fn parse_cfg(handler: &Handler, cfgs: Vec<String>) -> Cfg {
 }
 
 /// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
-pub(crate) fn parse_check_cfg(handler: &Handler, specs: Vec<String>) -> CheckCfg {
+pub(crate) fn parse_check_cfg(dcx: &DiagCtxt, specs: Vec<String>) -> CheckCfg {
     // If any --check-cfg is passed then exhaustive_values and exhaustive_names
     // are enabled by default.
     let exhaustive_names = !specs.is_empty();
@@ -118,12 +117,11 @@ pub(crate) fn parse_check_cfg(handler: &Handler, specs: Vec<String>) -> CheckCfg
             ($reason:expr) => {
                 #[allow(rustc::untranslatable_diagnostic)]
                 #[allow(rustc::diagnostic_outside_of_impl)]
-                handler
-                    .struct_fatal(format!(
-                        concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
-                        s
-                    ))
-                    .emit()
+                dcx.struct_fatal(format!(
+                    concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
+                    s
+                ))
+                .emit()
             };
         }
 
@@ -317,8 +315,8 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
     rustc_data_structures::sync::set_dyn_thread_safe_mode(config.opts.unstable_opts.threads > 1);
 
     // Check jobserver before run_in_thread_pool_with_globals, which call jobserver::acquire_thread
-    let early_handler = EarlyErrorHandler::new(config.opts.error_format);
-    early_handler.initialize_checked_jobserver();
+    let early_dcx = EarlyDiagCtxt::new(config.opts.error_format);
+    early_dcx.initialize_checked_jobserver();
 
     util::run_in_thread_pool_with_globals(
         config.opts.edition,
@@ -326,13 +324,13 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
         || {
             crate::callbacks::setup_callbacks();
 
-            let early_handler = EarlyErrorHandler::new(config.opts.error_format);
+            let early_dcx = EarlyDiagCtxt::new(config.opts.error_format);
 
             let codegen_backend = if let Some(make_codegen_backend) = config.make_codegen_backend {
                 make_codegen_backend(&config.opts)
             } else {
                 util::get_codegen_backend(
-                    &early_handler,
+                    &early_dcx,
                     &config.opts.maybe_sysroot,
                     config.opts.unstable_opts.codegen_backend.as_deref(),
                 )
@@ -349,7 +347,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
             ) {
                 Ok(bundle) => bundle,
                 Err(e) => {
-                    early_handler.early_error(format!("failed to load fluent bundle: {e}"));
+                    early_dcx.early_error(format!("failed to load fluent bundle: {e}"));
                 }
             };
 
@@ -360,7 +358,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
             let target_override = codegen_backend.target_override(&config.opts);
 
             let mut sess = rustc_session::build_session(
-                early_handler,
+                early_dcx,
                 config.opts,
                 CompilerIO {
                     input: config.input,
@@ -382,12 +380,12 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
 
             codegen_backend.init(&sess);
 
-            let cfg = parse_cfg(&sess.diagnostic(), config.crate_cfg);
+            let cfg = parse_cfg(&sess.dcx(), config.crate_cfg);
             let mut cfg = config::build_configuration(&sess, cfg);
             util::add_configuration(&mut cfg, &mut sess, &*codegen_backend);
             sess.parse_sess.config = cfg;
 
-            let mut check_cfg = parse_check_cfg(&sess.diagnostic(), config.crate_check_cfg);
+            let mut check_cfg = parse_check_cfg(&sess.dcx(), config.crate_check_cfg);
             check_cfg.fill_well_known(&sess.target);
             sess.parse_sess.check_config = check_cfg;
 
@@ -433,21 +431,21 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
 }
 
 pub fn try_print_query_stack(
-    handler: &Handler,
+    dcx: &DiagCtxt,
     num_frames: Option<usize>,
     file: Option<std::fs::File>,
 ) {
     eprintln!("query stack during panic:");
 
     // Be careful relying on global state here: this code is called from
-    // a panic hook, which means that the global `Handler` may be in a weird
+    // a panic hook, which means that the global `DiagCtxt` may be in a weird
     // state if it was responsible for triggering the panic.
     let i = ty::tls::with_context_opt(|icx| {
         if let Some(icx) = icx {
             ty::print::with_no_queries!(print_query_stack(
                 QueryCtxt::new(icx.tcx),
                 icx.query,
-                handler,
+                dcx,
                 num_frames,
                 file,
             ))
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 9b59ead0463..21beb90d73f 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -56,7 +56,7 @@ pub fn parse<'a>(sess: &'a Session) -> PResult<'a, ast::Crate> {
     }
 
     if let Some(ref s) = sess.opts.unstable_opts.show_span {
-        rustc_ast_passes::show_span::run(sess.diagnostic(), s, &krate);
+        rustc_ast_passes::show_span::run(sess.dcx(), s, &krate);
     }
 
     if sess.opts.unstable_opts.hir_stats {
@@ -267,7 +267,7 @@ fn configure_and_expand(
             is_proc_macro_crate,
             has_proc_macro_decls,
             is_test_crate,
-            sess.diagnostic(),
+            sess.dcx(),
         )
     });
 
@@ -526,7 +526,7 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
     match result {
         Ok(_) => {
             if sess.opts.json_artifact_notifications {
-                sess.diagnostic().emit_artifact_notification(deps_filename, "dep-info");
+                sess.dcx().emit_artifact_notification(deps_filename, "dep-info");
             }
         }
         Err(error) => {
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index e9611c74a68..8a553b95e8e 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -228,7 +228,7 @@ impl<'tcx> Queries<'tcx> {
 
             // If we have any delayed bugs, for example because we created TyKind::Error earlier,
             // it's likely that codegen will only cause more ICEs, obscuring the original problem
-            self.compiler.sess.diagnostic().flush_delayed();
+            self.compiler.sess.dcx().flush_delayed();
 
             // Hook for UI tests.
             Self::check_for_rustc_errors_attr(tcx);
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index d96b1ba88f5..04a7714d413 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -13,7 +13,7 @@ use rustc_session::config::{
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_session::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
-use rustc_session::{build_session, getopts, CompilerIO, EarlyErrorHandler, Session};
+use rustc_session::{build_session, getopts, CompilerIO, EarlyDiagCtxt, Session};
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
 use rustc_span::symbol::sym;
 use rustc_span::{FileName, SourceFileHashAlgorithm};
@@ -25,11 +25,11 @@ use std::path::{Path, PathBuf};
 use std::sync::Arc;
 
 fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
-    let mut early_handler = EarlyErrorHandler::new(ErrorOutputType::default());
-    early_handler.initialize_checked_jobserver();
+    let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
+    early_dcx.initialize_checked_jobserver();
 
     let registry = registry::Registry::new(&[]);
-    let sessopts = build_session_options(&mut early_handler, &matches);
+    let sessopts = build_session_options(&mut early_dcx, &matches);
     let temps_dir = sessopts.unstable_opts.temps_dir.as_deref().map(PathBuf::from);
     let io = CompilerIO {
         input: Input::Str { name: FileName::Custom(String::new()), input: String::new() },
@@ -38,7 +38,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
         temps_dir,
     };
     let sess = build_session(
-        early_handler,
+        early_dcx,
         sessopts,
         io,
         None,
@@ -52,7 +52,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, Cfg) {
         Arc::default(),
         Default::default(),
     );
-    let cfg = parse_cfg(&sess.diagnostic(), matches.opt_strs("cfg"));
+    let cfg = parse_cfg(&sess.dcx(), matches.opt_strs("cfg"));
     (sess, cfg)
 }
 
@@ -143,20 +143,20 @@ fn test_can_print_warnings() {
     rustc_span::create_default_session_globals_then(|| {
         let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
         let (sess, _) = mk_session(matches);
-        assert!(!sess.diagnostic().can_emit_warnings());
+        assert!(!sess.dcx().can_emit_warnings());
     });
 
     rustc_span::create_default_session_globals_then(|| {
         let matches =
             optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap();
         let (sess, _) = mk_session(matches);
-        assert!(sess.diagnostic().can_emit_warnings());
+        assert!(sess.dcx().can_emit_warnings());
     });
 
     rustc_span::create_default_session_globals_then(|| {
         let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
         let (sess, _) = mk_session(matches);
-        assert!(sess.diagnostic().can_emit_warnings());
+        assert!(sess.dcx().can_emit_warnings());
     });
 }
 
@@ -301,36 +301,36 @@ fn test_search_paths_tracking_hash_different_order() {
     let mut v3 = Options::default();
     let mut v4 = Options::default();
 
-    let handler = EarlyErrorHandler::new(JSON);
+    let early_dcx = EarlyDiagCtxt::new(JSON);
     const JSON: ErrorOutputType = ErrorOutputType::Json {
         pretty: false,
         json_rendered: HumanReadableErrorType::Default(ColorConfig::Never),
     };
 
     // Reference
-    v1.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
-    v1.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
-    v1.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
-    v1.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
-    v1.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
-
-    v2.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
-    v2.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
-    v2.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
-    v2.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
-    v2.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
-
-    v3.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
-    v3.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
-    v3.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
-    v3.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
-    v3.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
-
-    v4.search_paths.push(SearchPath::from_cli_opt(&handler, "all=mno"));
-    v4.search_paths.push(SearchPath::from_cli_opt(&handler, "native=abc"));
-    v4.search_paths.push(SearchPath::from_cli_opt(&handler, "crate=def"));
-    v4.search_paths.push(SearchPath::from_cli_opt(&handler, "dependency=ghi"));
-    v4.search_paths.push(SearchPath::from_cli_opt(&handler, "framework=jkl"));
+    v1.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "native=abc"));
+    v1.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "crate=def"));
+    v1.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "dependency=ghi"));
+    v1.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "framework=jkl"));
+    v1.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "all=mno"));
+
+    v2.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "native=abc"));
+    v2.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "dependency=ghi"));
+    v2.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "crate=def"));
+    v2.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "framework=jkl"));
+    v2.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "all=mno"));
+
+    v3.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "crate=def"));
+    v3.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "framework=jkl"));
+    v3.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "native=abc"));
+    v3.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "dependency=ghi"));
+    v3.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "all=mno"));
+
+    v4.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "all=mno"));
+    v4.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "native=abc"));
+    v4.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "crate=def"));
+    v4.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "dependency=ghi"));
+    v4.search_paths.push(SearchPath::from_cli_opt(&early_dcx, "framework=jkl"));
 
     assert_same_hash(&v1, &v2);
     assert_same_hash(&v1, &v3);
@@ -854,9 +854,9 @@ fn test_edition_parsing() {
     let options = Options::default();
     assert!(options.edition == DEFAULT_EDITION);
 
-    let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+    let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
     let matches = optgroups().parse(&["--edition=2018".to_string()]).unwrap();
-    let sessopts = build_session_options(&mut handler, &matches);
+    let sessopts = build_session_options(&mut early_dcx, &matches);
     assert!(sessopts.edition == Edition::Edition2018)
 }
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index c9c7ffdd937..bffa743218f 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -14,7 +14,7 @@ use rustc_session::{filesearch, output, Session};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
 use rustc_span::symbol::{sym, Symbol};
-use session::EarlyErrorHandler;
+use session::EarlyDiagCtxt;
 use std::env;
 use std::env::consts::{DLL_PREFIX, DLL_SUFFIX};
 use std::mem;
@@ -161,16 +161,16 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
     })
 }
 
-fn load_backend_from_dylib(handler: &EarlyErrorHandler, path: &Path) -> MakeBackendFn {
+fn load_backend_from_dylib(early_dcx: &EarlyDiagCtxt, path: &Path) -> MakeBackendFn {
     let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
         let err = format!("couldn't load codegen backend {path:?}: {err}");
-        handler.early_error(err);
+        early_dcx.early_error(err);
     });
 
     let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
         .unwrap_or_else(|e| {
             let err = format!("couldn't load codegen backend: {e}");
-            handler.early_error(err);
+            early_dcx.early_error(err);
         });
 
     // Intentionally leak the dynamic library. We can't ever unload it
@@ -185,7 +185,7 @@ fn load_backend_from_dylib(handler: &EarlyErrorHandler, path: &Path) -> MakeBack
 ///
 /// A name of `None` indicates that the default backend should be used.
 pub fn get_codegen_backend(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     maybe_sysroot: &Option<PathBuf>,
     backend_name: Option<&str>,
 ) -> Box<dyn CodegenBackend> {
@@ -196,11 +196,11 @@ pub fn get_codegen_backend(
 
         match backend_name.unwrap_or(default_codegen_backend) {
             filename if filename.contains('.') => {
-                load_backend_from_dylib(handler, filename.as_ref())
+                load_backend_from_dylib(early_dcx, filename.as_ref())
             }
             #[cfg(feature = "llvm")]
             "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new,
-            backend_name => get_codegen_sysroot(handler, maybe_sysroot, backend_name),
+            backend_name => get_codegen_sysroot(early_dcx, maybe_sysroot, backend_name),
         }
     });
 
@@ -233,7 +233,7 @@ fn get_rustc_path_inner(bin_path: &str) -> Option<PathBuf> {
 }
 
 fn get_codegen_sysroot(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     maybe_sysroot: &Option<PathBuf>,
     backend_name: &str,
 ) -> MakeBackendFn {
@@ -271,7 +271,7 @@ fn get_codegen_sysroot(
             "failed to find a `codegen-backends` folder \
                            in the sysroot candidates:\n* {candidates}"
         );
-        handler.early_error(err);
+        early_dcx.early_error(err);
     });
     info!("probing {} for a codegen backend", sysroot.display());
 
@@ -282,7 +282,7 @@ fn get_codegen_sysroot(
             sysroot.display(),
             e
         );
-        handler.early_error(err);
+        early_dcx.early_error(err);
     });
 
     let mut file: Option<PathBuf> = None;
@@ -310,16 +310,16 @@ fn get_codegen_sysroot(
                 prev.display(),
                 path.display()
             );
-            handler.early_error(err);
+            early_dcx.early_error(err);
         }
         file = Some(path.clone());
     }
 
     match file {
-        Some(ref s) => load_backend_from_dylib(handler, s),
+        Some(ref s) => load_backend_from_dylib(early_dcx, s),
         None => {
             let err = format!("unsupported builtin codegen backend `{backend_name}`");
-            handler.early_error(err);
+            early_dcx.early_error(err);
         }
     }
 }
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index 047a214a8b2..5dcc1bce5ff 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.diagnostic().steal_fulfilled_expectation_ids();
+    let fulfilled_expectations = tcx.sess.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 8c8ff3fc650..6eff2bfe13c 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.diagnostic().update_unstable_expectation_id(&builder.provider.unstable_to_stable_ids);
+    tcx.sess.dcx().update_unstable_expectation_id(&builder.provider.unstable_to_stable_ids);
 
     builder.provider.expectations
 }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index cd61544f69d..5de0203fc1d 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -17,11 +17,11 @@ pub(crate) struct DiagnosticDerive<'a> {
 }
 
 impl<'a> DiagnosticDerive<'a> {
-    pub(crate) fn new(diag: syn::Ident, handler: syn::Ident, structure: Structure<'a>) -> Self {
+    pub(crate) fn new(diag: syn::Ident, dcx: syn::Ident, structure: Structure<'a>) -> Self {
         Self {
             builder: DiagnosticDeriveBuilder {
                 diag,
-                kind: DiagnosticDeriveKind::Diagnostic { handler },
+                kind: DiagnosticDeriveKind::Diagnostic { dcx },
             },
             structure,
         }
@@ -36,7 +36,7 @@ impl<'a> DiagnosticDerive<'a> {
             let body = builder.body(variant);
 
             let diag = &builder.parent.diag;
-            let DiagnosticDeriveKind::Diagnostic { handler } = &builder.parent.kind else {
+            let DiagnosticDeriveKind::Diagnostic { dcx } = &builder.parent.kind else {
                 unreachable!()
             };
             let init = match builder.slug.value_ref() {
@@ -62,7 +62,7 @@ impl<'a> DiagnosticDerive<'a> {
                 Some(slug) => {
                     slugs.borrow_mut().push(slug.clone());
                     quote! {
-                        let mut #diag = #handler.struct_diagnostic(crate::fluent_generated::#slug);
+                        let mut #diag = #dcx.struct_diagnostic(crate::fluent_generated::#slug);
                     }
                 }
             };
@@ -77,11 +77,12 @@ impl<'a> DiagnosticDerive<'a> {
             }
         });
 
-        let DiagnosticDeriveKind::Diagnostic { handler } = &builder.kind else { unreachable!() };
+        let DiagnosticDeriveKind::Diagnostic { dcx } = &builder.kind else { unreachable!() };
 
+        // A lifetime of `'a` causes conflicts, but `_sess` is fine.
         let mut imp = structure.gen_impl(quote! {
-            gen impl<'__diagnostic_handler_sess, G>
-                    rustc_errors::IntoDiagnostic<'__diagnostic_handler_sess, G>
+            gen impl<'_sess, G>
+                    rustc_errors::IntoDiagnostic<'_sess, G>
                     for @Self
                 where G: rustc_errors::EmissionGuarantee
             {
@@ -89,8 +90,8 @@ impl<'a> DiagnosticDerive<'a> {
                 #[track_caller]
                 fn into_diagnostic(
                     self,
-                    #handler: &'__diagnostic_handler_sess rustc_errors::Handler
-                ) -> rustc_errors::DiagnosticBuilder<'__diagnostic_handler_sess, G> {
+                    #dcx: &'_sess rustc_errors::DiagCtxt
+                ) -> rustc_errors::DiagnosticBuilder<'_sess, G> {
                     use rustc_errors::IntoDiagnosticArg;
                     #implementation
                 }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 2755a161d91..511654d9949 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -19,7 +19,7 @@ use super::utils::SubdiagnosticVariant;
 /// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
 #[derive(Clone, PartialEq, Eq)]
 pub(crate) enum DiagnosticDeriveKind {
-    Diagnostic { handler: syn::Ident },
+    Diagnostic { dcx: syn::Ident },
     LintDiagnostic,
 }
 
@@ -348,11 +348,11 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
             }
             (Meta::Path(_), "subdiagnostic") => {
                 if FieldInnerTy::from_type(&info.binding.ast().ty).will_iterate() {
-                    let DiagnosticDeriveKind::Diagnostic { handler } = &self.parent.kind else {
+                    let DiagnosticDeriveKind::Diagnostic { dcx } = &self.parent.kind else {
                         // No eager translation for lints.
                         return Ok(quote! { #diag.subdiagnostic(#binding); });
                     };
-                    return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
+                    return Ok(quote! { #diag.eager_subdiagnostic(#dcx, #binding); });
                 } else {
                     return Ok(quote! { #diag.subdiagnostic(#binding); });
                 }
@@ -376,15 +376,15 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
                     return Ok(quote! {});
                 }
 
-                let handler = match &self.parent.kind {
-                    DiagnosticDeriveKind::Diagnostic { handler } => handler,
+                let dcx = match &self.parent.kind {
+                    DiagnosticDeriveKind::Diagnostic { dcx } => dcx,
                     DiagnosticDeriveKind::LintDiagnostic => {
                         throw_invalid_attr!(attr, |diag| {
                             diag.help("eager subdiagnostics are not supported on lints")
                         })
                     }
                 };
-                return Ok(quote! { #diag.eager_subdiagnostic(#handler, #binding); });
+                return Ok(quote! { #diag.eager_subdiagnostic(#dcx, #binding); });
             }
             _ => (),
         }
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 301e3f2620d..972c84b10f4 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -267,7 +267,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.diagnostic().emit_unused_externs(
+            tcx.sess.dcx().emit_unused_externs(
                 level,
                 json_unused_externs.is_loud(),
                 &unused_externs,
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index edc8d8532d3..206c15edd78 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -498,9 +498,9 @@ pub(crate) struct MultipleCandidates {
 impl IntoDiagnostic<'_> for MultipleCandidates {
     fn into_diagnostic(
         self,
-        handler: &'_ rustc_errors::Handler,
+        dcx: &'_ rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::metadata_multiple_candidates);
+        let mut diag = dcx.struct_err(fluent::metadata_multiple_candidates);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("flavor", self.flavor);
         diag.code(error_code!(E0464));
@@ -597,9 +597,9 @@ impl IntoDiagnostic<'_> for InvalidMetadataFiles {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &'_ rustc_errors::Handler,
+        dcx: &'_ rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::metadata_invalid_meta_files);
+        let mut diag = dcx.struct_err(fluent::metadata_invalid_meta_files);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("add_info", self.add_info);
         diag.code(error_code!(E0786));
@@ -627,9 +627,9 @@ impl IntoDiagnostic<'_> for CannotFindCrate {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &'_ rustc_errors::Handler,
+        dcx: &'_ rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::metadata_cannot_find_crate);
+        let mut diag = dcx.struct_err(fluent::metadata_cannot_find_crate);
         diag.set_arg("crate_name", self.crate_name);
         diag.set_arg("current_crate", self.current_crate);
         diag.set_arg("add_info", self.add_info);
diff --git a/compiler/rustc_metadata/src/fs.rs b/compiler/rustc_metadata/src/fs.rs
index c95ef01faa7..e80afcc482e 100644
--- a/compiler/rustc_metadata/src/fs.rs
+++ b/compiler/rustc_metadata/src/fs.rs
@@ -91,7 +91,7 @@ pub fn encode_and_write_metadata(tcx: TyCtxt<'_>) -> (EncodedMetadata, bool) {
             }
         };
         if tcx.sess.opts.json_artifact_notifications {
-            tcx.sess.diagnostic().emit_artifact_notification(out_filename.as_path(), "metadata");
+            tcx.sess.dcx().emit_artifact_notification(out_filename.as_path(), "metadata");
         }
         (filename, None)
     } else {
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index 4c4f38d1ad8..c49c4ee819c 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -308,7 +308,7 @@ pub fn struct_lint_level(
             (Level::Expect(expect_id), _) => {
                 // This case is special as we actually allow the lint itself in this context, but
                 // we can't return early like in the case for `Level::Allow` because we still
-                // need the lint diagnostic to be emitted to `rustc_error::HandlerInner`.
+                // need the lint diagnostic to be emitted to `rustc_error::DiagCtxtInner`.
                 //
                 // We can also not mark the lint expectation as fulfilled here right away, as it
                 // can still be cancelled in the decorate function. All of this means that we simply
@@ -324,11 +324,11 @@ pub fn struct_lint_level(
             (Level::Warn | Level::ForceWarn(None), Some(span)) => sess.struct_span_warn(span, ""),
             (Level::Warn | Level::ForceWarn(None), None) => sess.struct_warn(""),
             (Level::Deny | Level::Forbid, Some(span)) => {
-                let mut builder = sess.diagnostic().struct_err_lint("");
+                let mut builder = sess.dcx().struct_err_lint("");
                 builder.set_span(span);
                 builder
             }
-            (Level::Deny | Level::Forbid, None) => sess.diagnostic().struct_err_lint(""),
+            (Level::Deny | Level::Forbid, None) => sess.dcx().struct_err_lint(""),
         };
 
         err.set_is_lint();
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 5fcdd5d4d2e..225dd217807 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -5,7 +5,7 @@ use crate::ty::normalize_erasing_regions::NormalizationError;
 use crate::ty::{self, ConstKind, Ty, TyCtxt, TypeVisitableExt};
 use rustc_error_messages::DiagnosticMessage;
 use rustc_errors::{
-    DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg,
+    DiagCtxt, DiagnosticArgValue, DiagnosticBuilder, IntoDiagnostic, IntoDiagnosticArg,
 };
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
@@ -1273,13 +1273,13 @@ pub enum FnAbiError<'tcx> {
 }
 
 impl<'a, 'b> IntoDiagnostic<'a, !> for FnAbiError<'b> {
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> {
+    fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, !> {
         match self {
-            Self::Layout(e) => e.into_diagnostic().into_diagnostic(handler),
+            Self::Layout(e) => e.into_diagnostic().into_diagnostic(dcx),
             Self::AdjustForForeignAbi(call::AdjustForForeignAbiError::Unsupported {
                 arch,
                 abi,
-            }) => UnsupportedFnAbi { arch, abi: abi.name() }.into_diagnostic(handler),
+            }) => UnsupportedFnAbi { arch, abi: abi.name() }.into_diagnostic(dcx),
         }
     }
 }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 6513bf501e1..96de9c447b6 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1484,7 +1484,7 @@ impl<'tcx> OpaqueHiddenType<'tcx> {
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         if let Some(diag) = tcx
             .sess
-            .diagnostic()
+            .dcx()
             .steal_diagnostic(tcx.def_span(opaque_def_id), StashKey::OpaqueHiddenTypeMismatch)
         {
             diag.cancel();
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
index 21c1a93fde8..5c9dd18aeac 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.diagnostic().span_bug(span, msg),
-            (Some(tcx), None) => tcx.sess.diagnostic().bug(msg),
+            (Some(tcx), Some(span)) => tcx.sess.dcx().span_bug(span, msg),
+            (Some(tcx), None) => tcx.sess.dcx().bug(msg),
             (None, _) => panic_any(msg),
         }
     })
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index 8c68a58d406..ead20539e25 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.diagnostic().span_fatal(
+        tcx.sess.dcx().span_fatal(
             err.span,
             format!("Could not parse {}, found: {:?}", err.expected, err.item_description),
         )
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 9baae706dff..db2624cac02 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1,8 +1,8 @@
 use crate::fluent_generated as fluent;
 use rustc_errors::DiagnosticArgValue;
 use rustc_errors::{
-    error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-    Handler, IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
+    error_code, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder,
+    ErrorGuaranteed, IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
 };
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{self, Ty};
@@ -461,8 +461,8 @@ pub(crate) struct NonExhaustivePatternsTypeNotEmpty<'p, 'tcx, 'm> {
 }
 
 impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_span_err_with_code(
+    fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+        let mut diag = dcx.struct_span_err_with_code(
             self.span,
             fluent::mir_build_non_exhaustive_patterns_type_not_empty,
             error_code!(E0004),
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
index 928db471298..fd4af31501c 100644
--- a/compiler/rustc_mir_transform/src/errors.rs
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -1,8 +1,8 @@
 use std::borrow::Cow;
 
 use rustc_errors::{
-    Applicability, DecorateLint, DiagnosticArgValue, DiagnosticBuilder, DiagnosticMessage,
-    EmissionGuarantee, ErrorGuaranteed, Handler, IntoDiagnostic,
+    Applicability, DecorateLint, DiagCtxt, DiagnosticArgValue, DiagnosticBuilder,
+    DiagnosticMessage, EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic,
 };
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
 use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
@@ -64,12 +64,12 @@ pub(crate) struct RequiresUnsafe {
 // but this would result in a lot of duplication.
 impl<'sess> IntoDiagnostic<'sess> for RequiresUnsafe {
     #[track_caller]
-    fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::mir_transform_requires_unsafe);
+    fn into_diagnostic(self, dcx: &'sess DiagCtxt) -> DiagnosticBuilder<'sess, ErrorGuaranteed> {
+        let mut diag = dcx.struct_err(fluent::mir_transform_requires_unsafe);
         diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string()));
         diag.set_span(self.span);
         diag.span_label(self.span, self.details.label());
-        let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter());
+        let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter());
         diag.set_arg("details", desc);
         diag.set_arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed);
         self.details.add_subdiagnostics(&mut diag);
@@ -181,8 +181,8 @@ pub(crate) struct UnsafeOpInUnsafeFn {
 impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
     #[track_caller]
     fn decorate_lint<'b>(self, diag: &'b mut DiagnosticBuilder<'a, ()>) {
-        let handler = diag.handler().expect("lint should not yet be emitted");
-        let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter());
+        let dcx = diag.dcx().expect("lint should not yet be emitted");
+        let desc = dcx.eagerly_translate_to_string(self.details.label(), [].into_iter());
         diag.set_arg("details", desc);
         diag.span_label(self.details.span, self.details.label());
         self.details.add_subdiagnostics(diag);
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index feceff10f95..a68bfcd06d5 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.diagnostic().err_count();
+    let error_count = tcx.sess.dcx().err_count();
 
     match starting_item.node {
         MonoItem::Static(def_id) => {
@@ -459,7 +459,7 @@ 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.diagnostic().err_count() > error_count
+    if tcx.sess.dcx().err_count() > error_count
         && starting_item.node.is_generic_fn(tcx)
         && starting_item.node.is_user_defined()
     {
diff --git a/compiler/rustc_monomorphize/src/errors.rs b/compiler/rustc_monomorphize/src/errors.rs
index d242a7baec1..247b2245583 100644
--- a/compiler/rustc_monomorphize/src/errors.rs
+++ b/compiler/rustc_monomorphize/src/errors.rs
@@ -51,9 +51,9 @@ impl IntoDiagnostic<'_> for UnusedGenericParamsHint {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &'_ rustc_errors::Handler,
+        dcx: &'_ rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::monomorphize_unused_generic_params);
+        let mut diag = dcx.struct_err(fluent::monomorphize_unused_generic_params);
         diag.set_span(self.span);
         for (span, name) in self.param_spans.into_iter().zip(self.param_names) {
             // FIXME: I can figure out how to do a label with a fluent string with a fixed message,
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index c51a5c095ee..008adcc83d0 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -1042,11 +1042,11 @@ impl<'a> IntoDiagnostic<'a> for ExpectedIdentifier {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &'a rustc_errors::Handler,
+        dcx: &'a rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
         let token_descr = TokenDescription::from_token(&self.token);
 
-        let mut diag = handler.struct_err(match token_descr {
+        let mut diag = dcx.struct_err(match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
                 fluent::parse_expected_identifier_found_reserved_identifier_str
             }
@@ -1099,11 +1099,11 @@ impl<'a> IntoDiagnostic<'a> for ExpectedSemi {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &'a rustc_errors::Handler,
+        dcx: &'a rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
         let token_descr = TokenDescription::from_token(&self.token);
 
-        let mut diag = handler.struct_err(match token_descr {
+        let mut diag = dcx.struct_err(match token_descr {
             Some(TokenDescription::ReservedIdentifier) => {
                 fluent::parse_expected_semi_found_reserved_identifier_str
             }
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index b1dc1f98777..c158edaac25 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -227,7 +227,7 @@ impl<'a> StringReader<'a> {
                         let string = self.str_from(suffix_start);
                         if string == "_" {
                             self.sess
-                                .span_diagnostic
+                                .dcx
                                 .emit_err(errors::UnderscoreLiteralSuffix { span: self.mk_sp(suffix_start, self.pos) });
                             None
                         } else {
@@ -346,7 +346,7 @@ impl<'a> StringReader<'a> {
         c: char,
     ) -> DiagnosticBuilder<'a, !> {
         self.sess
-            .span_diagnostic
+            .dcx
             .struct_span_fatal(self.mk_sp(from_pos, to_pos), format!("{}: {}", m, escaped_char(c)))
     }
 
@@ -403,7 +403,7 @@ impl<'a> StringReader<'a> {
         match kind {
             rustc_lexer::LiteralKind::Char { terminated } => {
                 if !terminated {
-                    self.sess.span_diagnostic.span_fatal_with_code(
+                    self.sess.dcx.span_fatal_with_code(
                         self.mk_sp(start, end),
                         "unterminated character literal",
                         error_code!(E0762),
@@ -413,7 +413,7 @@ impl<'a> StringReader<'a> {
             }
             rustc_lexer::LiteralKind::Byte { terminated } => {
                 if !terminated {
-                    self.sess.span_diagnostic.span_fatal_with_code(
+                    self.sess.dcx.span_fatal_with_code(
                         self.mk_sp(start + BytePos(1), end),
                         "unterminated byte constant",
                         error_code!(E0763),
@@ -423,7 +423,7 @@ impl<'a> StringReader<'a> {
             }
             rustc_lexer::LiteralKind::Str { terminated } => {
                 if !terminated {
-                    self.sess.span_diagnostic.span_fatal_with_code(
+                    self.sess.dcx.span_fatal_with_code(
                         self.mk_sp(start, end),
                         "unterminated double quote string",
                         error_code!(E0765),
@@ -433,7 +433,7 @@ impl<'a> StringReader<'a> {
             }
             rustc_lexer::LiteralKind::ByteStr { terminated } => {
                 if !terminated {
-                    self.sess.span_diagnostic.span_fatal_with_code(
+                    self.sess.dcx.span_fatal_with_code(
                         self.mk_sp(start + BytePos(1), end),
                         "unterminated double quote byte string",
                         error_code!(E0766),
@@ -443,7 +443,7 @@ impl<'a> StringReader<'a> {
             }
             rustc_lexer::LiteralKind::CStr { terminated } => {
                 if !terminated {
-                    self.sess.span_diagnostic.span_fatal_with_code(
+                    self.sess.dcx.span_fatal_with_code(
                         self.mk_sp(start + BytePos(1), end),
                         "unterminated C string",
                         error_code!(E0767),
@@ -578,7 +578,7 @@ impl<'a> StringReader<'a> {
         possible_offset: Option<u32>,
         found_terminators: u32,
     ) -> ! {
-        let mut err = self.sess.span_diagnostic.struct_span_fatal_with_code(
+        let mut err = self.sess.dcx.struct_span_fatal_with_code(
             self.mk_sp(start, start),
             "unterminated raw string",
             error_code!(E0748),
@@ -614,7 +614,7 @@ impl<'a> StringReader<'a> {
             None => "unterminated block comment",
         };
         let last_bpos = self.pos;
-        let mut err = self.sess.span_diagnostic.struct_span_fatal_with_code(
+        let mut err = self.sess.dcx.struct_span_fatal_with_code(
             self.mk_sp(start, last_bpos),
             msg,
             error_code!(E0758),
@@ -719,7 +719,7 @@ impl<'a> StringReader<'a> {
                     has_fatal_err = true;
                 }
                 emit_unescape_error(
-                    &self.sess.span_diagnostic,
+                    &self.sess.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 8cbadc26635..2bc2789a4f7 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -73,7 +73,7 @@ impl<'a> TokenTreesReader<'a> {
 
     fn eof_err(&mut self) -> PErr<'a> {
         let msg = "this file contains an unclosed delimiter";
-        let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
+        let mut err = self.string_reader.sess.dcx.struct_span_err(self.token.span, msg);
         for &(_, sp) in &self.diag_info.open_braces {
             err.span_label(sp, "unclosed delimiter");
             self.diag_info.unmatched_delims.push(UnmatchedDelim {
@@ -290,7 +290,7 @@ impl<'a> TokenTreesReader<'a> {
         // matching opening delimiter).
         let token_str = token_to_string(&self.token);
         let msg = format!("unexpected closing delimiter: `{token_str}`");
-        let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
+        let mut err = self.string_reader.sess.dcx.struct_span_err(self.token.span, msg);
 
         report_suspicious_mismatch_block(
             &mut err,
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 2b4c2e3c250..775082adbe8 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -3,14 +3,14 @@
 use std::iter::once;
 use std::ops::Range;
 
-use rustc_errors::{Applicability, Handler};
+use rustc_errors::{Applicability, DiagCtxt};
 use rustc_lexer::unescape::{EscapeError, Mode};
 use rustc_span::{BytePos, Span};
 
 use crate::errors::{MoreThanOneCharNote, MoreThanOneCharSugg, NoBraceUnicodeSub, UnescapeError};
 
 pub(crate) fn emit_unescape_error(
-    handler: &Handler,
+    dcx: &DiagCtxt,
     // interior part of the literal, between quotes
     lit: &str,
     // full span of the literal, including quotes and any prefix
@@ -33,12 +33,10 @@ pub(crate) fn emit_unescape_error(
     };
     match error {
         EscapeError::LoneSurrogateUnicodeEscape => {
-            handler
-                .emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: true });
+            dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: true });
         }
         EscapeError::OutOfRangeUnicodeEscape => {
-            handler
-                .emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: false });
+            dcx.emit_err(UnescapeError::InvalidUnicodeEscape { span: err_span, surrogate: false });
         }
         EscapeError::MoreThanOneChar => {
             use unicode_normalization::{char::is_combining_mark, UnicodeNormalization};
@@ -104,7 +102,7 @@ pub(crate) fn emit_unescape_error(
                     sugg,
                 }
             });
-            handler.emit_err(UnescapeError::MoreThanOneChar {
+            dcx.emit_err(UnescapeError::MoreThanOneChar {
                 span: full_lit_span,
                 note,
                 suggestion: sugg,
@@ -112,7 +110,7 @@ pub(crate) fn emit_unescape_error(
         }
         EscapeError::EscapeOnlyChar => {
             let (c, char_span) = last_char();
-            handler.emit_err(UnescapeError::EscapeOnlyChar {
+            dcx.emit_err(UnescapeError::EscapeOnlyChar {
                 span: err_span,
                 char_span,
                 escaped_sugg: c.escape_default().to_string(),
@@ -122,11 +120,11 @@ pub(crate) fn emit_unescape_error(
         }
         EscapeError::BareCarriageReturn => {
             let double_quotes = mode.in_double_quotes();
-            handler.emit_err(UnescapeError::BareCr { span: err_span, double_quotes });
+            dcx.emit_err(UnescapeError::BareCr { span: err_span, double_quotes });
         }
         EscapeError::BareCarriageReturnInRawString => {
             assert!(mode.in_double_quotes());
-            handler.emit_err(UnescapeError::BareCrRawString(err_span));
+            dcx.emit_err(UnescapeError::BareCrRawString(err_span));
         }
         EscapeError::InvalidEscape => {
             let (c, span) = last_char();
@@ -137,7 +135,7 @@ pub(crate) fn emit_unescape_error(
                 "unknown character escape"
             };
             let ec = escaped_char(c);
-            let mut diag = handler.struct_span_err(span, format!("{label}: `{ec}`"));
+            let mut diag = dcx.struct_span_err(span, format!("{label}: `{ec}`"));
             diag.span_label(span, label);
             if c == '{' || c == '}' && matches!(mode, Mode::Str | Mode::RawStr) {
                 diag.help(
@@ -166,13 +164,13 @@ pub(crate) fn emit_unescape_error(
             diag.emit();
         }
         EscapeError::TooShortHexEscape => {
-            handler.emit_err(UnescapeError::TooShortHexEscape(err_span));
+            dcx.emit_err(UnescapeError::TooShortHexEscape(err_span));
         }
         EscapeError::InvalidCharInHexEscape | EscapeError::InvalidCharInUnicodeEscape => {
             let (c, span) = last_char();
             let is_hex = error == EscapeError::InvalidCharInHexEscape;
             let ch = escaped_char(c);
-            handler.emit_err(UnescapeError::InvalidCharInEscape { span, is_hex, ch });
+            dcx.emit_err(UnescapeError::InvalidCharInEscape { span, is_hex, ch });
         }
         EscapeError::NonAsciiCharInByte => {
             let (c, span) = last_char();
@@ -182,7 +180,7 @@ pub(crate) fn emit_unescape_error(
                 Mode::RawByteStr => "raw byte string literal",
                 _ => panic!("non-is_byte literal paired with NonAsciiCharInByte"),
             };
-            let mut err = handler.struct_span_err(span, format!("non-ASCII character in {desc}"));
+            let mut err = dcx.struct_span_err(span, format!("non-ASCII character in {desc}"));
             let postfix = if unicode_width::UnicodeWidthChar::width(c).unwrap_or(1) == 0 {
                 format!(" but is {c:?}")
             } else {
@@ -218,21 +216,20 @@ pub(crate) fn emit_unescape_error(
             err.emit();
         }
         EscapeError::OutOfRangeHexEscape => {
-            handler.emit_err(UnescapeError::OutOfRangeHexEscape(err_span));
+            dcx.emit_err(UnescapeError::OutOfRangeHexEscape(err_span));
         }
         EscapeError::LeadingUnderscoreUnicodeEscape => {
             let (c, span) = last_char();
-            handler.emit_err(UnescapeError::LeadingUnderscoreUnicodeEscape {
+            dcx.emit_err(UnescapeError::LeadingUnderscoreUnicodeEscape {
                 span,
                 ch: escaped_char(c),
             });
         }
         EscapeError::OverlongUnicodeEscape => {
-            handler.emit_err(UnescapeError::OverlongUnicodeEscape(err_span));
+            dcx.emit_err(UnescapeError::OverlongUnicodeEscape(err_span));
         }
         EscapeError::UnclosedUnicodeEscape => {
-            handler
-                .emit_err(UnescapeError::UnclosedUnicodeEscape(err_span, err_span.shrink_to_hi()));
+            dcx.emit_err(UnescapeError::UnclosedUnicodeEscape(err_span, err_span.shrink_to_hi()));
         }
         EscapeError::NoBraceInUnicodeEscape => {
             let mut suggestion = "\\u{".to_owned();
@@ -251,30 +248,30 @@ pub(crate) fn emit_unescape_error(
             } else {
                 (Some(err_span), NoBraceUnicodeSub::Help)
             };
-            handler.emit_err(UnescapeError::NoBraceInUnicodeEscape { span: err_span, label, sub });
+            dcx.emit_err(UnescapeError::NoBraceInUnicodeEscape { span: err_span, label, sub });
         }
         EscapeError::UnicodeEscapeInByte => {
-            handler.emit_err(UnescapeError::UnicodeEscapeInByte(err_span));
+            dcx.emit_err(UnescapeError::UnicodeEscapeInByte(err_span));
         }
         EscapeError::EmptyUnicodeEscape => {
-            handler.emit_err(UnescapeError::EmptyUnicodeEscape(err_span));
+            dcx.emit_err(UnescapeError::EmptyUnicodeEscape(err_span));
         }
         EscapeError::ZeroChars => {
-            handler.emit_err(UnescapeError::ZeroChars(err_span));
+            dcx.emit_err(UnescapeError::ZeroChars(err_span));
         }
         EscapeError::LoneSlash => {
-            handler.emit_err(UnescapeError::LoneSlash(err_span));
+            dcx.emit_err(UnescapeError::LoneSlash(err_span));
         }
         EscapeError::UnskippedWhitespaceWarning => {
             let (c, char_span) = last_char();
-            handler.emit_warning(UnescapeError::UnskippedWhitespace {
+            dcx.emit_warning(UnescapeError::UnskippedWhitespace {
                 span: err_span,
                 ch: escaped_char(c),
                 char_span,
             });
         }
         EscapeError::MultipleSkippedLinesWarning => {
-            handler.emit_warning(UnescapeError::MultipleSkippedLinesWarning(err_span));
+            dcx.emit_warning(UnescapeError::MultipleSkippedLinesWarning(err_span));
         }
     }
 }
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index 0dc60688955..dac7569e385 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -350,7 +350,7 @@ pub(super) fn check_for_substitution(
 
     let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else {
         let msg = format!("substitution character not found for '{ch}'");
-        reader.sess.span_diagnostic.span_bug(span, msg);
+        reader.sess.dcx.span_bug(span, msg);
     };
 
     // special help suggestion for "directed" double quotes
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 9887a85e6a4..82b0ff70c16 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -100,7 +100,7 @@ pub fn parse_stream_from_source_str(
 
 /// Creates a new parser from a source string.
 pub fn new_parser_from_source_str(sess: &ParseSess, name: FileName, source: String) -> Parser<'_> {
-    panictry_buffer!(&sess.span_diagnostic, maybe_new_parser_from_source_str(sess, name, source))
+    panictry_buffer!(&sess.dcx, maybe_new_parser_from_source_str(sess, name, source))
 }
 
 /// Creates a new parser from a source string. Returns any buffered errors from lexing the initial
@@ -121,7 +121,7 @@ pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, sp: Option<Spa
 
 /// Given a session and a `source_file`, returns a parser.
 fn source_file_to_parser(sess: &ParseSess, source_file: Lrc<SourceFile>) -> Parser<'_> {
-    panictry_buffer!(&sess.span_diagnostic, maybe_source_file_to_parser(sess, source_file))
+    panictry_buffer!(&sess.dcx, maybe_source_file_to_parser(sess, source_file))
 }
 
 /// Given a session and a `source_file`, return a parser. Returns any buffered errors from lexing the
@@ -166,7 +166,7 @@ fn file_to_source_file(sess: &ParseSess, path: &Path, spanopt: Option<Span>) ->
     match try_file_to_source_file(sess, path, spanopt) {
         Ok(source_file) => source_file,
         Err(d) => {
-            sess.span_diagnostic.emit_diagnostic(d);
+            sess.dcx.emit_diagnostic(d);
             FatalError.raise();
         }
     }
@@ -178,7 +178,7 @@ pub fn source_file_to_stream(
     source_file: Lrc<SourceFile>,
     override_span: Option<Span>,
 ) -> TokenStream {
-    panictry_buffer!(&sess.span_diagnostic, maybe_file_to_stream(sess, source_file, override_span))
+    panictry_buffer!(&sess.dcx, maybe_file_to_stream(sess, source_file, override_span))
 }
 
 /// Given a source file, produces a sequence of token trees. Returns any buffered errors from
@@ -189,7 +189,7 @@ pub fn maybe_file_to_stream(
     override_span: Option<Span>,
 ) -> Result<TokenStream, Vec<Diagnostic>> {
     let src = source_file.src.as_ref().unwrap_or_else(|| {
-        sess.span_diagnostic.bug(format!(
+        sess.dcx.bug(format!(
             "cannot lex `source_file` without source: {}",
             sess.source_map().filename_for_diagnostics(&source_file.name)
         ));
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index c9ce896b868..56e52baf98b 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -55,7 +55,7 @@ impl<'a> Parser<'a> {
             } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
                 if attr_style != ast::AttrStyle::Outer {
                     let span = self.token.span;
-                    let mut err = self.diagnostic().struct_span_err_with_code(
+                    let mut err = self.dcx().struct_span_err_with_code(
                         span,
                         fluent::parse_inner_doc_comment_not_permitted,
                         error_code!(E0753),
@@ -417,7 +417,7 @@ impl<'a> Parser<'a> {
         }
 
         Err(InvalidMetaItem { span: self.token.span, token: self.token.clone() }
-            .into_diagnostic(self.diagnostic()))
+            .into_diagnostic(self.dcx()))
     }
 }
 
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index 5e8447030f1..2307f4cfffa 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -41,7 +41,7 @@ impl AttrWrapper {
     }
 
     pub(crate) fn take_for_recovery(self, sess: &ParseSess) -> AttrVec {
-        sess.span_diagnostic.span_delayed_bug(
+        sess.dcx.span_delayed_bug(
             self.attrs.get(0).map(|attr| attr.span).unwrap_or(DUMMY_SP),
             "AttrVec is taken for recovery but no error is produced",
         );
@@ -266,8 +266,7 @@ impl<'a> Parser<'a> {
             if let Some(attr_range) = self.capture_state.inner_attr_ranges.remove(&inner_attr.id) {
                 inner_attr_replace_ranges.push(attr_range);
             } else {
-                self.diagnostic()
-                    .span_delayed_bug(inner_attr.span, "Missing token range for attribute");
+                self.dcx().span_delayed_bug(inner_attr.span, "Missing token range for attribute");
             }
         }
 
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index 221fc70d9ff..9e3637ea9f3 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, Diagnostic, DiagnosticBuilder, DiagnosticMessage,
-    ErrorGuaranteed, FatalError, Handler, IntoDiagnostic, MultiSpan, PResult,
+    pluralize, AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, DiagnosticBuilder,
+    DiagnosticMessage, ErrorGuaranteed, FatalError, IntoDiagnostic, MultiSpan, PResult,
 };
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
@@ -246,15 +246,15 @@ impl<'a> Parser<'a> {
         sp: S,
         m: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        self.diagnostic().struct_span_err(sp, m)
+        self.dcx().struct_span_err(sp, m)
     }
 
     pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.diagnostic().span_bug(sp, msg)
+        self.dcx().span_bug(sp, msg)
     }
 
-    pub(super) fn diagnostic(&self) -> &'a Handler {
-        &self.sess.span_diagnostic
+    pub(super) fn dcx(&self) -> &'a DiagCtxt {
+        &self.sess.dcx
     }
 
     /// Replace `self` with `snapshot.parser`.
@@ -284,7 +284,7 @@ impl<'a> Parser<'a> {
                 span: self.prev_token.span,
                 missing_comma: None,
             }
-            .into_diagnostic(self.diagnostic()));
+            .into_diagnostic(self.dcx()));
         }
 
         let valid_follow = &[
@@ -347,7 +347,7 @@ impl<'a> Parser<'a> {
             suggest_remove_comma,
             help_cannot_start_number,
         };
-        let mut err = err.into_diagnostic(self.diagnostic());
+        let mut err = err.into_diagnostic(self.dcx());
 
         // if the token we have is a `<`
         // it *might* be a misplaced generic
@@ -1410,7 +1410,7 @@ impl<'a> Parser<'a> {
                                 // Not entirely sure now, but we bubble the error up with the
                                 // suggestion.
                                 self.restore_snapshot(snapshot);
-                                Err(err.into_diagnostic(self.diagnostic()))
+                                Err(err.into_diagnostic(self.dcx()))
                             }
                         }
                     } else if token::OpenDelim(Delimiter::Parenthesis) == self.token.kind {
@@ -1425,7 +1425,7 @@ impl<'a> Parser<'a> {
                         }
                         // Consume the fn call arguments.
                         match self.consume_fn_args() {
-                            Err(()) => Err(err.into_diagnostic(self.diagnostic())),
+                            Err(()) => Err(err.into_diagnostic(self.dcx())),
                             Ok(()) => {
                                 self.sess.emit_err(err);
                                 // FIXME: actually check that the two expressions in the binop are
@@ -1451,7 +1451,7 @@ impl<'a> Parser<'a> {
                             mk_err_expr(self, inner_op.span.to(self.prev_token.span))
                         } else {
                             // These cases cause too many knock-down errors, bail out (#61329).
-                            Err(err.into_diagnostic(self.diagnostic()))
+                            Err(err.into_diagnostic(self.dcx()))
                         }
                     };
                 }
@@ -2539,7 +2539,7 @@ impl<'a> Parser<'a> {
             Ok(Some(GenericArg::Const(self.parse_const_arg()?)))
         } else {
             let after_kw_const = self.token.span;
-            self.recover_const_arg(after_kw_const, err.into_diagnostic(self.diagnostic())).map(Some)
+            self.recover_const_arg(after_kw_const, err.into_diagnostic(self.dcx())).map(Some)
         }
     }
 
@@ -2897,7 +2897,7 @@ impl<'a> Parser<'a> {
                         span: path.span.shrink_to_hi(),
                         between: between_span,
                     }
-                    .into_diagnostic(self.diagnostic()));
+                    .into_diagnostic(self.dcx()));
                 }
             }
         }
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 509cef9826b..cd3e8b92f2f 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -1269,7 +1269,7 @@ impl<'a> Parser<'a> {
                                         .collect(),
                                 },
                             }
-                            .into_diagnostic(self.diagnostic());
+                            .into_diagnostic(self.dcx());
                             replacement_err.emit();
 
                             let old_err = mem::replace(err, replacement_err);
@@ -1693,8 +1693,7 @@ impl<'a> Parser<'a> {
         mk_lit_char: impl FnOnce(Symbol, Span) -> L,
         err: impl FnOnce(&Self) -> DiagnosticBuilder<'a, ErrorGuaranteed>,
     ) -> L {
-        if let Some(mut diag) =
-            self.diagnostic().steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar)
+        if let Some(mut diag) = self.dcx().steal_diagnostic(lifetime.span, StashKey::LifetimeIsChar)
         {
             diag.span_suggestion_verbose(
                 lifetime.span.shrink_to_hi(),
@@ -1884,8 +1883,8 @@ impl<'a> Parser<'a> {
         self.bump(); // `#`
 
         let Some((ident, false)) = self.token.ident() else {
-            let err = errors::ExpectedBuiltinIdent { span: self.token.span }
-                .into_diagnostic(self.diagnostic());
+            let err =
+                errors::ExpectedBuiltinIdent { span: self.token.span }.into_diagnostic(self.dcx());
             return Err(err);
         };
         self.sess.gated_spans.gate(sym::builtin_syntax, ident.span);
@@ -1896,7 +1895,7 @@ impl<'a> Parser<'a> {
             Ok(res)
         } else {
             let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name }
-                .into_diagnostic(self.diagnostic());
+                .into_diagnostic(self.dcx());
             return Err(err);
         };
         self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?;
@@ -1960,7 +1959,7 @@ impl<'a> Parser<'a> {
             && matches!(e.kind, ExprKind::Err)
         {
             let mut err = errors::InvalidInterpolatedExpression { span: self.token.span }
-                .into_diagnostic(self.diagnostic());
+                .into_diagnostic(self.dcx());
             err.downgrade_to_delayed_bug();
             return Err(err);
         }
@@ -2172,7 +2171,7 @@ impl<'a> Parser<'a> {
                     return Err(errors::MissingSemicolonBeforeArray {
                         open_delim: open_delim_span,
                         semicolon: prev_span.shrink_to_hi(),
-                    }.into_diagnostic(self.diagnostic()));
+                    }.into_diagnostic(self.dcx()));
                 }
                 Ok(_) => (),
                 Err(err) => err.cancel(),
@@ -2320,7 +2319,7 @@ impl<'a> Parser<'a> {
             if self.check_keyword(kw::Async) {
                 let move_async_span = self.token.span.with_lo(self.prev_token.span.data().lo);
                 Err(errors::AsyncMoveOrderIncorrect { span: move_async_span }
-                    .into_diagnostic(self.diagnostic()))
+                    .into_diagnostic(self.dcx()))
             } else {
                 Ok(CaptureBy::Value { move_kw: move_kw_span })
             }
@@ -2510,7 +2509,7 @@ impl<'a> Parser<'a> {
             };
             if self.prev_token.kind == token::BinOp(token::Or) {
                 // This was part of a closure, the that part of the parser recover.
-                return Err(err.into_diagnostic(self.diagnostic()));
+                return Err(err.into_diagnostic(self.dcx()));
             } else {
                 Some(self.sess.emit_err(err))
             }
@@ -3194,8 +3193,7 @@ impl<'a> Parser<'a> {
     fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
         let (attrs, body) = self.parse_inner_attrs_and_block()?;
         if self.eat_keyword(kw::Catch) {
-            Err(errors::CatchAfterTry { span: self.prev_token.span }
-                .into_diagnostic(self.diagnostic()))
+            Err(errors::CatchAfterTry { span: self.prev_token.span }.into_diagnostic(self.dcx()))
         } else {
             let span = span_lo.to(body.span);
             self.sess.gated_spans.gate(sym::try_blocks, span);
@@ -3537,7 +3535,7 @@ impl<'a> Parser<'a> {
                     ident_span: this.token.span,
                     token: this.look_ahead(1, |t| t.clone()),
                 }
-                .into_diagnostic(&self.sess.span_diagnostic));
+                .into_diagnostic(&self.sess.dcx));
             }
             let (ident, expr) = if is_shorthand {
                 // Mimic `x: x` for the `x` field shorthand.
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index fd7dad36c9d..bf619daba50 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -438,7 +438,7 @@ impl<'a> Parser<'a> {
             None
         };
 
-        if let Some(err) = err { Err(err.into_diagnostic(self.diagnostic())) } else { Ok(()) }
+        if let Some(err) = err { Err(err.into_diagnostic(self.dcx())) } else { Ok(()) }
     }
 
     fn parse_item_builtin(&mut self) -> PResult<'a, Option<ItemInfo>> {
@@ -759,7 +759,7 @@ impl<'a> Parser<'a> {
             if self.look_ahead(1, |tok| tok == &token::CloseDelim(Delimiter::Brace)) {
                 // FIXME: merge with `DocCommentDoesNotDocumentAnything` (E0585)
                 struct_span_err!(
-                    self.diagnostic(),
+                    self.dcx(),
                     self.token.span,
                     E0584,
                     "found a documentation comment that doesn't document anything",
@@ -1374,7 +1374,7 @@ impl<'a> Parser<'a> {
 
         let span = self.prev_token.span.shrink_to_hi();
         let err: DiagnosticBuilder<'_, ErrorGuaranteed> =
-            errors::MissingConstType { span, colon, kind }.into_diagnostic(self.diagnostic());
+            errors::MissingConstType { span, colon, kind }.into_diagnostic(self.dcx());
         err.stash(span, StashKey::ItemNoType);
 
         // The user intended that the type be inferred,
@@ -1391,7 +1391,7 @@ impl<'a> Parser<'a> {
                 self.bump();
                 self.sess.emit_err(err);
             } else {
-                return Err(err.into_diagnostic(self.diagnostic()));
+                return Err(err.into_diagnostic(self.dcx()));
             }
         }
 
@@ -1591,7 +1591,7 @@ impl<'a> Parser<'a> {
         } else {
             let err =
                 errors::UnexpectedTokenAfterStructName::new(self.token.span, self.token.clone());
-            return Err(err.into_diagnostic(self.diagnostic()));
+            return Err(err.into_diagnostic(self.dcx()));
         };
 
         Ok((class_name, ItemKind::Struct(vdata, generics)))
@@ -1787,7 +1787,7 @@ impl<'a> Parser<'a> {
                         let sp = previous_span.shrink_to_hi();
                         err.missing_comma = Some(sp);
                     }
-                    return Err(err.into_diagnostic(self.diagnostic()));
+                    return Err(err.into_diagnostic(self.dcx()));
                 }
             }
             _ => {
@@ -1837,7 +1837,7 @@ impl<'a> Parser<'a> {
                     // Make sure an error was emitted (either by recovering an angle bracket,
                     // or by finding an identifier as the next token), since we're
                     // going to continue parsing
-                    assert!(self.diagnostic().has_errors().is_some());
+                    assert!(self.dcx().has_errors().is_some());
                 } else {
                     return Err(err);
                 }
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 2baedb2766f..b91432f10c8 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1507,7 +1507,7 @@ pub(crate) fn make_unclosed_delims_error(
         opening_candidate: unmatched.candidate_span,
         unclosed: unmatched.unclosed_span,
     }
-    .into_diagnostic(&sess.span_diagnostic);
+    .into_diagnostic(&sess.dcx);
     Some(err)
 }
 
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 4360a69e501..301a88cd077 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -114,8 +114,9 @@ impl<'a> Parser<'a> {
             NonterminalKind::Item => match self.parse_item(ForceCollect::Yes)? {
                 Some(item) => NtItem(item),
                 None => {
-                    return Err(UnexpectedNonterminal::Item(self.token.span)
-                        .into_diagnostic(self.diagnostic()));
+                    return Err(
+                        UnexpectedNonterminal::Item(self.token.span).into_diagnostic(self.dcx())
+                    );
                 }
             },
             NonterminalKind::Block => {
@@ -127,7 +128,7 @@ impl<'a> Parser<'a> {
                 Some(s) => NtStmt(P(s)),
                 None => {
                     return Err(UnexpectedNonterminal::Statement(self.token.span)
-                        .into_diagnostic(self.diagnostic()));
+                        .into_diagnostic(self.dcx()));
                 }
             },
             NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => {
@@ -163,7 +164,7 @@ impl<'a> Parser<'a> {
                     span: self.token.span,
                     token: self.token.clone(),
                 }
-                .into_diagnostic(self.diagnostic()));
+                .into_diagnostic(self.dcx()));
             }
             NonterminalKind::Path => {
                 NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?))
@@ -181,7 +182,7 @@ impl<'a> Parser<'a> {
                         span: self.token.span,
                         token: self.token.clone(),
                     }
-                    .into_diagnostic(self.diagnostic()));
+                    .into_diagnostic(self.dcx()));
                 }
             }
         };
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 020b66a985a..80233eddb9b 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -873,7 +873,7 @@ impl<'a> Parser<'a> {
         // will direct us over to `parse_enum_variant()`.
         if self.token == token::OpenDelim(Delimiter::Parenthesis) {
             return Err(EnumPatternInsteadOfIdentifier { span: self.prev_token.span }
-                .into_diagnostic(self.diagnostic()));
+                .into_diagnostic(self.dcx()));
         }
 
         Ok(PatKind::Ident(binding_annotation, ident, sub))
@@ -987,7 +987,7 @@ impl<'a> Parser<'a> {
             // check that a comma comes after every field
             if !ate_comma {
                 let mut err = ExpectedCommaAfterPatternField { span: self.token.span }
-                    .into_diagnostic(self.diagnostic());
+                    .into_diagnostic(self.dcx());
                 if let Some(mut delayed) = delayed_err {
                     delayed.emit();
                 }
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index 0f4ba9617c6..3b92a911983 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -123,7 +123,7 @@ impl<'a> Parser<'a> {
 
         self.bump(); // colon
 
-        self.diagnostic()
+        self.dcx()
             .struct_span_err(
                 self.prev_token.span,
                 "found single colon before projection in qualified path",
@@ -326,7 +326,7 @@ impl<'a> Parser<'a> {
                                     .is_nightly_build()
                                     .then_some(()),
                             }
-                            .into_diagnostic(self.diagnostic());
+                            .into_diagnostic(self.dcx());
                         }
                         // Attempt to find places where a missing `>` might belong.
                         else if let Some(arg) = args
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index d10c8c92257..9fea3826652 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -56,7 +56,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
                     let res = match res {
                         Ok(lit) => {
                             if token_lit.suffix.is_some() {
-                                let mut err = sess.span_diagnostic.struct_span_err(
+                                let mut err = sess.dcx.struct_span_err(
                                     expr.span,
                                     "suffixed literals are not allowed in attributes",
                                 );
@@ -89,7 +89,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
                     //   the error because an earlier error will have already
                     //   been reported.
                     let msg = format!("attribute value must be a literal");
-                    let mut err = sess.span_diagnostic.struct_span_err(expr.span, msg);
+                    let mut err = sess.dcx.struct_span_err(expr.span, msg);
                     if let ast::ExprKind::Err = expr.kind {
                         err.downgrade_to_delayed_bug();
                     }
@@ -206,7 +206,7 @@ fn emit_malformed_attribute(
     if should_warn(name) {
         sess.buffer_lint(ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, msg);
     } else {
-        sess.span_diagnostic
+        sess.dcx
             .struct_span_err(span, error_msg)
             .span_suggestions(
                 span,
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 58127445322..8f8da211d31 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -867,9 +867,9 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &'_ rustc_errors::Handler,
+        dcx: &'_ rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::passes_invalid_attr_at_crate_level);
+        let mut diag = dcx.struct_err(fluent::passes_invalid_attr_at_crate_level);
         diag.set_span(self.span);
         diag.set_arg("name", self.name);
         // Only emit an error with a suggestion if we can create a string out
@@ -1020,9 +1020,9 @@ impl<'a> IntoDiagnostic<'_> for BreakNonLoop<'a> {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &rustc_errors::Handler,
+        dcx: &rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_span_err_with_code(
+        let mut diag = dcx.struct_span_err_with_code(
             self.span,
             fluent::passes_break_non_loop,
             error_code!(E0571),
@@ -1169,9 +1169,9 @@ impl IntoDiagnostic<'_> for NakedFunctionsAsmBlock {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &rustc_errors::Handler,
+        dcx: &rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_span_err_with_code(
+        let mut diag = dcx.struct_span_err_with_code(
             self.span,
             fluent::passes_naked_functions_asm_block,
             error_code!(E0787),
@@ -1285,9 +1285,9 @@ impl<'a> IntoDiagnostic<'a> for NoMainErr {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &'a rustc_errors::Handler,
+        dcx: &'a rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut diag = handler.struct_span_err_with_code(
+        let mut diag = dcx.struct_span_err_with_code(
             DUMMY_SP,
             fluent::passes_no_main_function,
             error_code!(E0601),
@@ -1348,9 +1348,9 @@ impl IntoDiagnostic<'_> for DuplicateLangItem {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &rustc_errors::Handler,
+        dcx: &rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err_with_code(
+        let mut diag = dcx.struct_err_with_code(
             match self.duplicate {
                 Duplicate::Plain => fluent::passes_duplicate_lang_item,
                 Duplicate::Crate => fluent::passes_duplicate_lang_item_crate,
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index 3b8ccb67bbe..3556a5ec1d1 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -924,10 +924,10 @@ impl<D: Deps> DepGraphData<D> {
             // Promote the previous diagnostics to the current session.
             qcx.store_side_effects(dep_node_index, side_effects.clone());
 
-            let handle = qcx.dep_context().sess().diagnostic();
+            let dcx = qcx.dep_context().sess().dcx();
 
             for diagnostic in side_effects.diagnostics {
-                handle.emit_diagnostic(diagnostic);
+                dcx.emit_diagnostic(diagnostic);
             }
         }
     }
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index c431e966e44..2a34ffb75f2 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -5,7 +5,7 @@ use crate::query::DepKind;
 use crate::query::{QueryContext, QueryStackFrame};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{
-    Diagnostic, DiagnosticBuilder, ErrorGuaranteed, Handler, IntoDiagnostic, Level,
+    DiagCtxt, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, Level,
 };
 use rustc_hir::def::DefKind;
 use rustc_session::Session;
@@ -604,18 +604,18 @@ pub(crate) fn report_cycle<'a>(
         note_span: (),
     };
 
-    cycle_diag.into_diagnostic(sess.diagnostic())
+    cycle_diag.into_diagnostic(sess.dcx())
 }
 
 pub fn print_query_stack<Qcx: QueryContext>(
     qcx: Qcx,
     mut current_query: Option<QueryJobId>,
-    handler: &Handler,
+    dcx: &DiagCtxt,
     num_frames: Option<usize>,
     mut file: Option<std::fs::File>,
 ) -> usize {
     // Be careful relying on global state here: this code is called from
-    // a panic hook, which means that the global `Handler` may be in a weird
+    // a panic hook, which means that the global `DiagCtxt` may be in a weird
     // state if it was responsible for triggering the panic.
     let mut count_printed = 0;
     let mut count_total = 0;
@@ -638,7 +638,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
                 ),
             );
             diag.span = query_info.job.span.into();
-            handler.force_print_diagnostic(diag);
+            dcx.force_print_diagnostic(diag);
             count_printed += 1;
         }
 
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index ca225416e36..1001286b6c2 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -205,10 +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
-                .diagnostic()
-                .bug(format!("built-in macro `{name}` was already registered"));
+            self.tcx.sess.dcx().bug(format!("built-in macro `{name}` was already registered"));
         }
     }
 
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 20d18fa4b83..0c21e4eb43e 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -7,11 +7,11 @@ use crate::errors::FileWriteFail;
 use crate::search_paths::SearchPath;
 use crate::utils::{CanonicalizedPath, NativeLib, NativeLibKind};
 use crate::{lint, HashStableContext};
-use crate::{EarlyErrorHandler, Session};
+use crate::{EarlyDiagCtxt, Session};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
 use rustc_data_structures::stable_hasher::{StableOrd, ToStableHashKey};
 use rustc_errors::emitter::HumanReadableErrorType;
-use rustc_errors::{ColorConfig, DiagnosticArgValue, HandlerFlags, IntoDiagnosticArg};
+use rustc_errors::{ColorConfig, DiagCtxtFlags, DiagnosticArgValue, IntoDiagnosticArg};
 use rustc_feature::UnstableFeatures;
 use rustc_span::edition::{Edition, DEFAULT_EDITION, EDITION_NAME_LIST, LATEST_STABLE_EDITION};
 use rustc_span::source_map::FilePathMapping;
@@ -1155,8 +1155,8 @@ impl Options {
 }
 
 impl UnstableOptions {
-    pub fn diagnostic_handler_flags(&self, can_emit_warnings: bool) -> HandlerFlags {
-        HandlerFlags {
+    pub fn dcx_flags(&self, can_emit_warnings: bool) -> DiagCtxtFlags {
+        DiagCtxtFlags {
             can_emit_warnings,
             treat_err_as_bug: self.treat_err_as_bug,
             dont_buffer_diagnostics: self.dont_buffer_diagnostics,
@@ -1584,7 +1584,7 @@ pub fn build_configuration(sess: &Session, mut user_cfg: Cfg) -> Cfg {
 }
 
 pub(super) fn build_target_config(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     opts: &Options,
     target_override: Option<Target>,
     sysroot: &Path,
@@ -1594,17 +1594,17 @@ pub(super) fn build_target_config(
         |t| Ok((t, TargetWarnings::empty())),
     );
     let (target, target_warnings) = target_result.unwrap_or_else(|e| {
-        handler.early_error(format!(
+        early_dcx.early_error(format!(
             "Error loading target specification: {e}. \
                  Run `rustc --print target-list` for a list of built-in targets"
         ))
     });
     for warning in target_warnings.warning_messages() {
-        handler.early_warn(warning)
+        early_dcx.early_warn(warning)
     }
 
     if !matches!(target.pointer_width, 16 | 32 | 64) {
-        handler.early_error(format!(
+        early_dcx.early_error(format!(
             "target specification was invalid: unrecognized target-pointer-width {}",
             target.pointer_width
         ))
@@ -1844,7 +1844,7 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> {
 }
 
 pub fn get_cmd_lint_options(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     matches: &getopts::Matches,
 ) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) {
     let mut lint_opts_with_position = vec![];
@@ -1869,14 +1869,14 @@ pub fn get_cmd_lint_options(
 
     let lint_cap = matches.opt_str("cap-lints").map(|cap| {
         lint::Level::from_str(&cap)
-            .unwrap_or_else(|| handler.early_error(format!("unknown lint level: `{cap}`")))
+            .unwrap_or_else(|| early_dcx.early_error(format!("unknown lint level: `{cap}`")))
     });
 
     (lint_opts, describe_lints, lint_cap)
 }
 
 /// Parses the `--color` flag.
-pub fn parse_color(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> ColorConfig {
+pub fn parse_color(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> ColorConfig {
     match matches.opt_str("color").as_deref() {
         Some("auto") => ColorConfig::Auto,
         Some("always") => ColorConfig::Always,
@@ -1884,7 +1884,7 @@ pub fn parse_color(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> C
 
         None => ColorConfig::Auto,
 
-        Some(arg) => handler.early_error(format!(
+        Some(arg) => early_dcx.early_error(format!(
             "argument for `--color` must be auto, \
                  always or never (instead was `{arg}`)"
         )),
@@ -1930,7 +1930,7 @@ impl JsonUnusedExterns {
 ///
 /// The first value returned is how to render JSON diagnostics, and the second
 /// is whether or not artifact notifications are enabled.
-pub fn parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> JsonConfig {
+pub fn parse_json(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> JsonConfig {
     let mut json_rendered: fn(ColorConfig) -> HumanReadableErrorType =
         HumanReadableErrorType::Default;
     let mut json_color = ColorConfig::Never;
@@ -1942,7 +1942,7 @@ pub fn parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Js
         // won't actually be emitting any colors and anything colorized is
         // embedded in a diagnostic message anyway.
         if matches.opt_str("color").is_some() {
-            handler.early_error("cannot specify the `--color` option with `--json`");
+            early_dcx.early_error("cannot specify the `--color` option with `--json`");
         }
 
         for sub_option in option.split(',') {
@@ -1953,7 +1953,7 @@ pub fn parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Js
                 "unused-externs" => json_unused_externs = JsonUnusedExterns::Loud,
                 "unused-externs-silent" => json_unused_externs = JsonUnusedExterns::Silent,
                 "future-incompat" => json_future_incompat = true,
-                s => handler.early_error(format!("unknown `--json` option `{s}`")),
+                s => early_dcx.early_error(format!("unknown `--json` option `{s}`")),
             }
         }
     }
@@ -1968,7 +1968,7 @@ pub fn parse_json(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Js
 
 /// Parses the `--error-format` flag.
 pub fn parse_error_format(
-    handler: &mut EarlyErrorHandler,
+    early_dcx: &mut EarlyDiagCtxt,
     matches: &getopts::Matches,
     color: ColorConfig,
     json_rendered: HumanReadableErrorType,
@@ -1990,10 +1990,10 @@ pub fn parse_error_format(
             Some("short") => ErrorOutputType::HumanReadable(HumanReadableErrorType::Short(color)),
 
             Some(arg) => {
-                handler.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable(
+                early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::HumanReadable(
                     HumanReadableErrorType::Default(color),
                 ));
-                handler.early_error(format!(
+                early_dcx.early_error(format!(
                     "argument for `--error-format` must be `human`, `json` or \
                      `short` (instead was `{arg}`)"
                 ))
@@ -2010,7 +2010,7 @@ pub fn parse_error_format(
         // `--error-format=json`. This means that `--json` is specified we
         // should actually be emitting JSON blobs.
         _ if !matches.opt_strs("json").is_empty() => {
-            handler.early_error("using `--json` requires also using `--error-format=json`");
+            early_dcx.early_error("using `--json` requires also using `--error-format=json`");
         }
 
         _ => {}
@@ -2019,10 +2019,10 @@ pub fn parse_error_format(
     error_format
 }
 
-pub fn parse_crate_edition(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Edition {
+pub fn parse_crate_edition(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Edition {
     let edition = match matches.opt_str("edition") {
         Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
-            handler.early_error(format!(
+            early_dcx.early_error(format!(
                 "argument for `--edition` must be one of: \
                      {EDITION_NAME_LIST}. (instead was `{arg}`)"
             ))
@@ -2039,40 +2039,40 @@ pub fn parse_crate_edition(handler: &EarlyErrorHandler, matches: &getopts::Match
         } else {
             format!("edition {edition} is unstable and only available with -Z unstable-options")
         };
-        handler.early_error(msg)
+        early_dcx.early_error(msg)
     }
 
     edition
 }
 
 fn check_error_format_stability(
-    handler: &mut EarlyErrorHandler,
+    early_dcx: &mut EarlyDiagCtxt,
     unstable_opts: &UnstableOptions,
     error_format: ErrorOutputType,
     json_rendered: HumanReadableErrorType,
 ) {
     if !unstable_opts.unstable_options {
         if let ErrorOutputType::Json { pretty: true, json_rendered } = error_format {
-            handler.abort_if_error_and_set_error_format(ErrorOutputType::Json {
+            early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::Json {
                 pretty: false,
                 json_rendered,
             });
-            handler.early_error("`--error-format=pretty-json` is unstable");
+            early_dcx.early_error("`--error-format=pretty-json` is unstable");
         }
         if let ErrorOutputType::HumanReadable(HumanReadableErrorType::AnnotateSnippet(_)) =
             error_format
         {
-            handler.abort_if_error_and_set_error_format(ErrorOutputType::Json {
+            early_dcx.abort_if_error_and_set_error_format(ErrorOutputType::Json {
                 pretty: false,
                 json_rendered,
             });
-            handler.early_error("`--error-format=human-annotate-rs` is unstable");
+            early_dcx.early_error("`--error-format=human-annotate-rs` is unstable");
         }
     }
 }
 
 fn parse_output_types(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     unstable_opts: &UnstableOptions,
     matches: &getopts::Matches,
 ) -> OutputTypes {
@@ -2082,7 +2082,7 @@ fn parse_output_types(
             for output_type in list.split(',') {
                 let (shorthand, path) = split_out_file_name(output_type);
                 let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
-                    handler.early_error(format!(
+                    early_dcx.early_error(format!(
                         "unknown emission type: `{shorthand}` - expected one of: {display}",
                         display = OutputType::shorthands_display(),
                     ))
@@ -2106,7 +2106,7 @@ fn split_out_file_name(arg: &str) -> (&str, Option<OutFileName>) {
 }
 
 fn should_override_cgus_and_disable_thinlto(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     output_types: &OutputTypes,
     matches: &getopts::Matches,
     mut codegen_units: Option<usize>,
@@ -2126,12 +2126,12 @@ fn should_override_cgus_and_disable_thinlto(
             Some(n) if n > 1 => {
                 if matches.opt_present("o") {
                     for ot in &incompatible {
-                        handler.early_warn(format!(
+                        early_dcx.early_warn(format!(
                             "`--emit={ot}` with `-o` incompatible with \
                                  `-C codegen-units=N` for N > 1",
                         ));
                     }
-                    handler.early_warn("resetting to default -C codegen-units=1");
+                    early_dcx.early_warn("resetting to default -C codegen-units=1");
                     codegen_units = Some(1);
                     disable_local_thinlto = true;
                 }
@@ -2144,14 +2144,14 @@ fn should_override_cgus_and_disable_thinlto(
     }
 
     if codegen_units == Some(0) {
-        handler.early_error("value for codegen units must be a positive non-zero integer");
+        early_dcx.early_error("value for codegen units must be a positive non-zero integer");
     }
 
     (disable_local_thinlto, codegen_units)
 }
 
 fn collect_print_requests(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     cg: &mut CodegenOptions,
     unstable_opts: &mut UnstableOptions,
     matches: &getopts::Matches,
@@ -2204,7 +2204,7 @@ fn collect_print_requests(
                 if unstable_opts.unstable_options {
                     PrintKind::TargetSpec
                 } else {
-                    handler.early_error(
+                    early_dcx.early_error(
                         "the `-Z unstable-options` flag must also be passed to \
                          enable the target-spec-json print option",
                     );
@@ -2214,7 +2214,7 @@ fn collect_print_requests(
                 if unstable_opts.unstable_options {
                     PrintKind::AllTargetSpecs
                 } else {
-                    handler.early_error(
+                    early_dcx.early_error(
                         "the `-Z unstable-options` flag must also be passed to \
                          enable the all-target-specs-json print option",
                     );
@@ -2225,7 +2225,7 @@ fn collect_print_requests(
                 let prints =
                     PRINT_KINDS.iter().map(|(name, _)| format!("`{name}`")).collect::<Vec<_>>();
                 let prints = prints.join(", ");
-                handler.early_error(format!(
+                early_dcx.early_error(format!(
                     "unknown print request `{req}`. Valid print requests are: {prints}"
                 ));
             }
@@ -2234,7 +2234,7 @@ fn collect_print_requests(
         let out = out.unwrap_or(OutFileName::Stdout);
         if let OutFileName::Real(path) = &out {
             if !printed_paths.insert(path.clone()) {
-                handler.early_error(format!(
+                early_dcx.early_error(format!(
                     "cannot print multiple outputs to the same path: {}",
                     path.display(),
                 ));
@@ -2247,15 +2247,12 @@ fn collect_print_requests(
     prints
 }
 
-pub fn parse_target_triple(
-    handler: &EarlyErrorHandler,
-    matches: &getopts::Matches,
-) -> TargetTriple {
+pub fn parse_target_triple(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> TargetTriple {
     match matches.opt_str("target") {
         Some(target) if target.ends_with(".json") => {
             let path = Path::new(&target);
             TargetTriple::from_path(path).unwrap_or_else(|_| {
-                handler.early_error(format!("target file {path:?} does not exist"))
+                early_dcx.early_error(format!("target file {path:?} does not exist"))
             })
         }
         Some(target) => TargetTriple::TargetTriple(target),
@@ -2264,7 +2261,7 @@ pub fn parse_target_triple(
 }
 
 fn parse_opt_level(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     matches: &getopts::Matches,
     cg: &CodegenOptions,
 ) -> OptLevel {
@@ -2294,7 +2291,7 @@ fn parse_opt_level(
             "s" => OptLevel::Size,
             "z" => OptLevel::SizeMin,
             arg => {
-                handler.early_error(format!(
+                early_dcx.early_error(format!(
                     "optimization level needs to be \
                             between 0-3, s or z (instead was `{arg}`)"
                 ));
@@ -2317,21 +2314,21 @@ fn select_debuginfo(matches: &getopts::Matches, cg: &CodegenOptions) -> DebugInf
 }
 
 fn parse_assert_incr_state(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     opt_assertion: &Option<String>,
 ) -> Option<IncrementalStateAssertion> {
     match opt_assertion {
         Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
         Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
         Some(s) => {
-            handler.early_error(format!("unexpected incremental state assertion value: {s}"))
+            early_dcx.early_error(format!("unexpected incremental state assertion value: {s}"))
         }
         None => None,
     }
 }
 
 fn parse_native_lib_kind(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     matches: &getopts::Matches,
     kind: &str,
 ) -> (NativeLibKind, Option<bool>) {
@@ -2351,22 +2348,22 @@ fn parse_native_lib_kind(
                 } else {
                     ", the `-Z unstable-options` flag must also be passed to use it"
                 };
-                handler.early_error(format!("library kind `link-arg` is unstable{why}"))
+                early_dcx.early_error(format!("library kind `link-arg` is unstable{why}"))
             }
             NativeLibKind::LinkArg
         }
-        _ => handler.early_error(format!(
+        _ => early_dcx.early_error(format!(
             "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
         )),
     };
     match modifiers {
         None => (kind, None),
-        Some(modifiers) => parse_native_lib_modifiers(handler, kind, modifiers, matches),
+        Some(modifiers) => parse_native_lib_modifiers(early_dcx, kind, modifiers, matches),
     }
 }
 
 fn parse_native_lib_modifiers(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     mut kind: NativeLibKind,
     modifiers: &str,
     matches: &getopts::Matches,
@@ -2375,7 +2372,7 @@ fn parse_native_lib_modifiers(
     for modifier in modifiers.split(',') {
         let (modifier, value) = match modifier.strip_prefix(['+', '-']) {
             Some(m) => (m, modifier.starts_with('+')),
-            None => handler.early_error(
+            None => early_dcx.early_error(
                 "invalid linking modifier syntax, expected '+' or '-' prefix \
                  before one of: bundle, verbatim, whole-archive, as-needed",
             ),
@@ -2388,20 +2385,20 @@ fn parse_native_lib_modifiers(
                 } else {
                     ", the `-Z unstable-options` flag must also be passed to use it"
                 };
-                handler.early_error(format!("linking modifier `{modifier}` is unstable{why}"))
+                early_dcx.early_error(format!("linking modifier `{modifier}` is unstable{why}"))
             }
         };
         let assign_modifier = |dst: &mut Option<bool>| {
             if dst.is_some() {
                 let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
-                handler.early_error(msg)
+                early_dcx.early_error(msg)
             } else {
                 *dst = Some(value);
             }
         };
         match (modifier, &mut kind) {
             ("bundle", NativeLibKind::Static { bundle, .. }) => assign_modifier(bundle),
-            ("bundle", _) => handler.early_error(
+            ("bundle", _) => early_dcx.early_error(
                 "linking modifier `bundle` is only compatible with `static` linking kind",
             ),
 
@@ -2410,7 +2407,7 @@ fn parse_native_lib_modifiers(
             ("whole-archive", NativeLibKind::Static { whole_archive, .. }) => {
                 assign_modifier(whole_archive)
             }
-            ("whole-archive", _) => handler.early_error(
+            ("whole-archive", _) => early_dcx.early_error(
                 "linking modifier `whole-archive` is only compatible with `static` linking kind",
             ),
 
@@ -2419,14 +2416,14 @@ fn parse_native_lib_modifiers(
                 report_unstable_modifier();
                 assign_modifier(as_needed)
             }
-            ("as-needed", _) => handler.early_error(
+            ("as-needed", _) => early_dcx.early_error(
                 "linking modifier `as-needed` is only compatible with \
                  `dylib` and `framework` linking kinds",
             ),
 
             // Note: this error also excludes the case with empty modifier
             // string, like `modifiers = ""`.
-            _ => handler.early_error(format!(
+            _ => early_dcx.early_error(format!(
                 "unknown linking modifier `{modifier}`, expected one \
                      of: bundle, verbatim, whole-archive, as-needed"
             )),
@@ -2436,7 +2433,7 @@ fn parse_native_lib_modifiers(
     (kind, verbatim)
 }
 
-fn parse_libs(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Vec<NativeLib> {
+fn parse_libs(early_dcx: &EarlyDiagCtxt, matches: &getopts::Matches) -> Vec<NativeLib> {
     matches
         .opt_strs("l")
         .into_iter()
@@ -2450,7 +2447,7 @@ fn parse_libs(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Vec<Na
             let (name, kind, verbatim) = match s.split_once('=') {
                 None => (s, NativeLibKind::Unspecified, None),
                 Some((kind, name)) => {
-                    let (kind, verbatim) = parse_native_lib_kind(handler, matches, kind);
+                    let (kind, verbatim) = parse_native_lib_kind(early_dcx, matches, kind);
                     (name.to_string(), kind, verbatim)
                 }
             };
@@ -2460,7 +2457,7 @@ fn parse_libs(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Vec<Na
                 Some((name, new_name)) => (name.to_string(), Some(new_name.to_owned())),
             };
             if name.is_empty() {
-                handler.early_error("library name must not be empty");
+                early_dcx.early_error("library name must not be empty");
             }
             NativeLib { name, new_name, kind, verbatim }
         })
@@ -2468,7 +2465,7 @@ fn parse_libs(handler: &EarlyErrorHandler, matches: &getopts::Matches) -> Vec<Na
 }
 
 pub fn parse_externs(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     matches: &getopts::Matches,
     unstable_opts: &UnstableOptions,
 ) -> Externs {
@@ -2496,7 +2493,7 @@ pub fn parse_externs(
         };
 
         if !is_ascii_ident(&name) {
-            let mut error = handler.early_struct_error(format!(
+            let mut error = early_dcx.early_struct_error(format!(
                 "crate name `{name}` passed to `--extern` is not a valid ASCII identifier"
             ));
             let adjusted_name = name.replace('-', "_");
@@ -2558,7 +2555,7 @@ pub fn parse_externs(
         let mut force = false;
         if let Some(opts) = options {
             if !is_unstable_enabled {
-                handler.early_error(
+                early_dcx.early_error(
                     "the `-Z unstable-options` flag must also be passed to \
                      enable `--extern` options",
                 );
@@ -2570,14 +2567,14 @@ pub fn parse_externs(
                         if let ExternLocation::ExactPaths(_) = &entry.location {
                             add_prelude = false;
                         } else {
-                            handler.early_error(
+                            early_dcx.early_error(
                                 "the `noprelude` --extern option requires a file path",
                             );
                         }
                     }
                     "nounused" => nounused_dep = true,
                     "force" => force = true,
-                    _ => handler.early_error(format!("unknown --extern option `{opt}`")),
+                    _ => early_dcx.early_error(format!("unknown --extern option `{opt}`")),
                 }
             }
         }
@@ -2596,7 +2593,7 @@ pub fn parse_externs(
 }
 
 fn parse_remap_path_prefix(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     matches: &getopts::Matches,
     unstable_opts: &UnstableOptions,
 ) -> Vec<(PathBuf, PathBuf)> {
@@ -2604,7 +2601,9 @@ fn parse_remap_path_prefix(
         .opt_strs("remap-path-prefix")
         .into_iter()
         .map(|remap| match remap.rsplit_once('=') {
-            None => handler.early_error("--remap-path-prefix must contain '=' between FROM and TO"),
+            None => {
+                early_dcx.early_error("--remap-path-prefix must contain '=' between FROM and TO")
+            }
             Some((from, to)) => (PathBuf::from(from), PathBuf::from(to)),
         })
         .collect();
@@ -2619,7 +2618,7 @@ fn parse_remap_path_prefix(
 }
 
 fn parse_logical_env(
-    handler: &mut EarlyErrorHandler,
+    early_dcx: &mut EarlyDiagCtxt,
     matches: &getopts::Matches,
 ) -> FxIndexMap<String, String> {
     let mut vars = FxIndexMap::default();
@@ -2628,7 +2627,7 @@ fn parse_logical_env(
         if let Some((name, val)) = arg.split_once('=') {
             vars.insert(name.to_string(), val.to_string());
         } else {
-            handler.early_error(format!("`--env`: specify value for variable `{arg}`"));
+            early_dcx.early_error(format!("`--env`: specify value for variable `{arg}`"));
         }
     }
 
@@ -2637,87 +2636,88 @@ fn parse_logical_env(
 
 // JUSTIFICATION: before wrapper fn is available
 #[allow(rustc::bad_opt_access)]
-pub fn build_session_options(
-    handler: &mut EarlyErrorHandler,
-    matches: &getopts::Matches,
-) -> Options {
-    let color = parse_color(handler, matches);
+pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::Matches) -> Options {
+    let color = parse_color(early_dcx, matches);
 
-    let edition = parse_crate_edition(handler, matches);
+    let edition = parse_crate_edition(early_dcx, matches);
 
     let JsonConfig {
         json_rendered,
         json_artifact_notifications,
         json_unused_externs,
         json_future_incompat,
-    } = parse_json(handler, matches);
+    } = parse_json(early_dcx, matches);
 
-    let error_format = parse_error_format(handler, matches, color, json_rendered);
+    let error_format = parse_error_format(early_dcx, matches, color, json_rendered);
 
-    handler.abort_if_error_and_set_error_format(error_format);
+    early_dcx.abort_if_error_and_set_error_format(error_format);
 
     let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_else(|_| {
-        handler.early_error("`--diagnostic-width` must be an positive integer");
+        early_dcx.early_error("`--diagnostic-width` must be an positive integer");
     });
 
     let unparsed_crate_types = matches.opt_strs("crate-type");
     let crate_types = parse_crate_types_from_list(unparsed_crate_types)
-        .unwrap_or_else(|e| handler.early_error(e));
+        .unwrap_or_else(|e| early_dcx.early_error(e));
 
-    let mut unstable_opts = UnstableOptions::build(handler, matches);
-    let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(handler, matches);
+    let mut unstable_opts = UnstableOptions::build(early_dcx, matches);
+    let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
 
-    check_error_format_stability(handler, &unstable_opts, error_format, json_rendered);
+    check_error_format_stability(early_dcx, &unstable_opts, error_format, json_rendered);
 
     if !unstable_opts.unstable_options && json_unused_externs.is_enabled() {
-        handler.early_error(
+        early_dcx.early_error(
             "the `-Z unstable-options` flag must also be passed to enable \
             the flag `--json=unused-externs`",
         );
     }
 
-    let output_types = parse_output_types(handler, &unstable_opts, matches);
+    let output_types = parse_output_types(early_dcx, &unstable_opts, matches);
 
-    let mut cg = CodegenOptions::build(handler, matches);
-    let (disable_local_thinlto, mut codegen_units) =
-        should_override_cgus_and_disable_thinlto(handler, &output_types, matches, cg.codegen_units);
+    let mut cg = CodegenOptions::build(early_dcx, matches);
+    let (disable_local_thinlto, mut codegen_units) = should_override_cgus_and_disable_thinlto(
+        early_dcx,
+        &output_types,
+        matches,
+        cg.codegen_units,
+    );
 
     if unstable_opts.threads == 0 {
-        handler.early_error("value for threads must be a positive non-zero integer");
+        early_dcx.early_error("value for threads must be a positive non-zero integer");
     }
 
     let fuel = unstable_opts.fuel.is_some() || unstable_opts.print_fuel.is_some();
     if fuel && unstable_opts.threads > 1 {
-        handler.early_error("optimization fuel is incompatible with multiple threads");
+        early_dcx.early_error("optimization fuel is incompatible with multiple threads");
     }
     if fuel && cg.incremental.is_some() {
-        handler.early_error("optimization fuel is incompatible with incremental compilation");
+        early_dcx.early_error("optimization fuel is incompatible with incremental compilation");
     }
 
     let incremental = cg.incremental.as_ref().map(PathBuf::from);
 
-    let assert_incr_state = parse_assert_incr_state(handler, &unstable_opts.assert_incr_state);
+    let assert_incr_state = parse_assert_incr_state(early_dcx, &unstable_opts.assert_incr_state);
 
     if unstable_opts.profile && incremental.is_some() {
-        handler.early_error("can't instrument with gcov profiling when compiling incrementally");
+        early_dcx.early_error("can't instrument with gcov profiling when compiling incrementally");
     }
     if unstable_opts.profile {
         match codegen_units {
             Some(1) => {}
             None => codegen_units = Some(1),
-            Some(_) => handler
+            Some(_) => early_dcx
                 .early_error("can't instrument with gcov profiling with multiple codegen units"),
         }
     }
 
     if cg.profile_generate.enabled() && cg.profile_use.is_some() {
-        handler.early_error("options `-C profile-generate` and `-C profile-use` are exclusive");
+        early_dcx.early_error("options `-C profile-generate` and `-C profile-use` are exclusive");
     }
 
     if unstable_opts.profile_sample_use.is_some()
         && (cg.profile_generate.enabled() || cg.profile_use.is_some())
     {
-        handler.early_error(
+        early_dcx.early_error(
             "option `-Z profile-sample-use` cannot be used with `-C profile-generate` or `-C profile-use`",
         );
     }
@@ -2730,7 +2730,7 @@ pub fn build_session_options(
         // Unstable values:
         Some(SymbolManglingVersion::Legacy) => {
             if !unstable_opts.unstable_options {
-                handler.early_error(
+                early_dcx.early_error(
                     "`-C symbol-mangling-version=legacy` requires `-Z unstable-options`",
                 );
             }
@@ -2747,7 +2747,7 @@ pub fn build_session_options(
         | InstrumentCoverage::ExceptUnusedFunctions
         | InstrumentCoverage::ExceptUnusedGenerics => {
             if !unstable_opts.unstable_options {
-                handler.early_error(
+                early_dcx.early_error(
                     "`-C instrument-coverage=branch` and `-C instrument-coverage=except-*` \
                     require `-Z unstable-options`",
                 );
@@ -2757,7 +2757,7 @@ pub fn build_session_options(
 
     if cg.instrument_coverage != InstrumentCoverage::Off {
         if cg.profile_generate.enabled() || cg.profile_use.is_some() {
-            handler.early_error(
+            early_dcx.early_error(
                 "option `-C instrument-coverage` is not compatible with either `-C profile-use` \
                 or `-C profile-generate`",
             );
@@ -2770,7 +2770,7 @@ pub fn build_session_options(
         match cg.symbol_mangling_version {
             None => cg.symbol_mangling_version = Some(SymbolManglingVersion::V0),
             Some(SymbolManglingVersion::Legacy) => {
-                handler.early_warn(
+                early_dcx.early_warn(
                     "-C instrument-coverage requires symbol mangling version `v0`, \
                     but `-C symbol-mangling-version=legacy` was specified",
                 );
@@ -2787,7 +2787,7 @@ pub fn build_session_options(
         match cg.lto {
             LtoCli::No | LtoCli::Unspecified => {}
             LtoCli::Yes | LtoCli::NoParam | LtoCli::Thin | LtoCli::Fat => {
-                handler.early_error("options `-C embed-bitcode=no` and `-C lto` are incompatible")
+                early_dcx.early_error("options `-C embed-bitcode=no` and `-C lto` are incompatible")
             }
         }
     }
@@ -2799,7 +2799,7 @@ pub fn build_session_options(
         let uses_unstable_self_contained_option =
             cg.link_self_contained.are_unstable_variants_set();
         if uses_unstable_self_contained_option {
-            handler.early_error(
+            early_dcx.early_error(
                 "only `-C link-self-contained` values `y`/`yes`/`on`/`n`/`no`/`off` are stable, \
                 the `-Z unstable-options` flag must also be passed to use the unstable values",
             );
@@ -2807,7 +2807,7 @@ pub fn build_session_options(
 
         if let Some(flavor) = cg.linker_flavor {
             if flavor.is_unstable() {
-                handler.early_error(format!(
+                early_dcx.early_error(format!(
                     "the linker flavor `{}` is unstable, the `-Z unstable-options` \
                         flag must also be passed to use the unstable values",
                     flavor.desc()
@@ -2824,18 +2824,18 @@ pub fn build_session_options(
             .map(|c| c.as_str().unwrap())
             .intersperse(", ")
             .collect();
-        handler.early_error(format!(
+        early_dcx.early_error(format!(
             "some `-C link-self-contained` components were both enabled and disabled: {names}"
         ));
     }
 
-    let prints = collect_print_requests(handler, &mut cg, &mut unstable_opts, matches);
+    let prints = collect_print_requests(early_dcx, &mut cg, &mut unstable_opts, matches);
 
     let cg = cg;
 
     let sysroot_opt = matches.opt_str("sysroot").map(|m| PathBuf::from(&m));
-    let target_triple = parse_target_triple(handler, matches);
-    let opt_level = parse_opt_level(handler, matches, &cg);
+    let target_triple = parse_target_triple(early_dcx, matches);
+    let opt_level = parse_opt_level(early_dcx, matches, &cg);
     // The `-g` and `-C debuginfo` flags specify the same setting, so we want to be able
     // to use them interchangeably. See the note above (regarding `-O` and `-C opt-level`)
     // for more details.
@@ -2845,35 +2845,36 @@ pub fn build_session_options(
 
     let mut search_paths = vec![];
     for s in &matches.opt_strs("L") {
-        search_paths.push(SearchPath::from_cli_opt(handler, s));
+        search_paths.push(SearchPath::from_cli_opt(early_dcx, s));
     }
 
-    let libs = parse_libs(handler, matches);
+    let libs = parse_libs(early_dcx, matches);
 
     let test = matches.opt_present("test");
 
     if !cg.remark.is_empty() && debuginfo == DebugInfo::None {
-        handler.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations");
+        early_dcx.early_warn("-C remark requires \"-C debuginfo=n\" to show source locations");
     }
 
     if cg.remark.is_empty() && unstable_opts.remark_dir.is_some() {
-        handler.early_warn("using -Z remark-dir without enabling remarks using e.g. -C remark=all");
+        early_dcx
+            .early_warn("using -Z remark-dir without enabling remarks using e.g. -C remark=all");
     }
 
-    let externs = parse_externs(handler, matches, &unstable_opts);
+    let externs = parse_externs(early_dcx, matches, &unstable_opts);
 
     let crate_name = matches.opt_str("crate-name");
 
-    let remap_path_prefix = parse_remap_path_prefix(handler, matches, &unstable_opts);
+    let remap_path_prefix = parse_remap_path_prefix(early_dcx, matches, &unstable_opts);
 
-    let pretty = parse_pretty(handler, &unstable_opts);
+    let pretty = parse_pretty(early_dcx, &unstable_opts);
 
     // query-dep-graph is required if dump-dep-graph is given #106736
     if unstable_opts.dump_dep_graph && !unstable_opts.query_dep_graph {
-        handler.early_error("can't dump dependency graph without `-Z query-dep-graph`");
+        early_dcx.early_error("can't dump dependency graph without `-Z query-dep-graph`");
     }
 
-    let logical_env = parse_logical_env(handler, matches);
+    let logical_env = parse_logical_env(early_dcx, matches);
 
     // Try to find a directory containing the Rust `src`, for more details see
     // the doc comment on the `real_rust_source_base_dir` field.
@@ -2904,7 +2905,7 @@ pub fn build_session_options(
     };
 
     let working_dir = std::env::current_dir().unwrap_or_else(|e| {
-        handler.early_error(format!("Current directory is invalid: {e}"));
+        early_dcx.early_error(format!("Current directory is invalid: {e}"));
     });
 
     let remap = file_path_mapping(remap_path_prefix.clone(), &unstable_opts);
@@ -2959,7 +2960,7 @@ pub fn build_session_options(
     }
 }
 
-fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) -> Option<PpMode> {
+fn parse_pretty(early_dcx: &EarlyDiagCtxt, unstable_opts: &UnstableOptions) -> Option<PpMode> {
     use PpMode::*;
 
     let first = match unstable_opts.unpretty.as_deref()? {
@@ -2979,7 +2980,7 @@ fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) ->
         "mir" => Mir,
         "stable-mir" => StableMir,
         "mir-cfg" => MirCFG,
-        name => handler.early_error(format!(
+        name => early_dcx.early_error(format!(
             "argument to `unpretty` must be one of `normal`, `identified`, \
                             `expanded`, `expanded,identified`, `expanded,hygiene`, \
                             `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
@@ -3026,7 +3027,7 @@ pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateTy
 
 pub mod nightly_options {
     use super::{OptionStability, RustcOptGroup};
-    use crate::EarlyErrorHandler;
+    use crate::EarlyDiagCtxt;
     use rustc_feature::UnstableFeatures;
 
     pub fn is_unstable_enabled(matches: &getopts::Matches) -> bool {
@@ -3043,7 +3044,7 @@ pub mod nightly_options {
     }
 
     pub fn check_nightly_options(
-        handler: &EarlyErrorHandler,
+        early_dcx: &EarlyDiagCtxt,
         matches: &getopts::Matches,
         flags: &[RustcOptGroup],
     ) {
@@ -3059,7 +3060,7 @@ pub mod nightly_options {
                 continue;
             }
             if opt.name != "Z" && !has_z_unstable_option {
-                handler.early_error(format!(
+                early_dcx.early_error(format!(
                     "the `-Z unstable-options` flag must also be passed to enable \
                          the flag `{}`",
                     opt.name
@@ -3075,17 +3076,17 @@ pub mod nightly_options {
                         "the option `{}` is only accepted on the nightly compiler",
                         opt.name
                     );
-                    let _ = handler.early_error_no_abort(msg);
+                    let _ = early_dcx.early_error_no_abort(msg);
                 }
                 OptionStability::Stable => {}
             }
         }
         if nightly_options_on_stable > 0 {
-            handler
+            early_dcx
                 .early_help("consider switching to a nightly toolchain: `rustup default nightly`");
-            handler.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
-            handler.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
-            handler.early_error(format!(
+            early_dcx.early_note("selecting a toolchain with `+toolchain` arguments require a rustup proxy; see <https://rust-lang.github.io/rustup/concepts/index.html>");
+            early_dcx.early_note("for more information about Rust's stability policy, see <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#unstable-features>");
+            early_dcx.early_error(format!(
                 "{} nightly option{} were parsed",
                 nightly_options_on_stable,
                 if nightly_options_on_stable > 1 { "s" } else { "" }
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index aab7595ef6e..c3360815ac9 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -17,9 +17,9 @@ impl<'a> IntoDiagnostic<'a> for FeatureGateError {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &'a rustc_errors::Handler,
+        dcx: &'a rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'a, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(self.explain);
+        let mut diag = dcx.struct_err(self.explain);
         diag.set_span(self.span);
         diag.code(error_code!(E0658));
         diag
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index e8ca556aa42..06b554e8e63 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -2,7 +2,7 @@ use crate::config::*;
 
 use crate::search_paths::SearchPath;
 use crate::utils::NativeLib;
-use crate::{lint, EarlyErrorHandler};
+use crate::{lint, EarlyDiagCtxt};
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::profiling::TimePassesFormat;
 use rustc_data_structures::stable_hasher::Hash64;
@@ -255,10 +255,10 @@ macro_rules! options {
 
     impl $struct_name {
         pub fn build(
-            handler: &EarlyErrorHandler,
+            early_dcx: &EarlyDiagCtxt,
             matches: &getopts::Matches,
         ) -> $struct_name {
-            build_options(handler, matches, $stat, $prefix, $outputname)
+            build_options(early_dcx, matches, $stat, $prefix, $outputname)
         }
 
         fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
@@ -319,7 +319,7 @@ type OptionSetter<O> = fn(&mut O, v: Option<&str>) -> bool;
 type OptionDescrs<O> = &'static [(&'static str, OptionSetter<O>, &'static str, &'static str)];
 
 fn build_options<O: Default>(
-    handler: &EarlyErrorHandler,
+    early_dcx: &EarlyDiagCtxt,
     matches: &getopts::Matches,
     descrs: OptionDescrs<O>,
     prefix: &str,
@@ -337,12 +337,12 @@ fn build_options<O: Default>(
             Some((_, setter, type_desc, _)) => {
                 if !setter(&mut op, value) {
                     match value {
-                        None => handler.early_error(
+                        None => early_dcx.early_error(
                             format!(
                                 "{outputname} option `{key}` requires {type_desc} ({prefix} {key}=<value>)"
                             ),
                         ),
-                        Some(value) => handler.early_error(
+                        Some(value) => early_dcx.early_error(
                             format!(
                                 "incorrect value `{value}` for {outputname} option `{key}` - {type_desc} was expected"
                             ),
@@ -350,7 +350,7 @@ fn build_options<O: Default>(
                     }
                 }
             }
-            None => handler.early_error(format!("unknown {outputname} option: `{key}`")),
+            None => early_dcx.early_error(format!("unknown {outputname} option: `{key}`")),
         }
     }
     return op;
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 525f00f5cd0..2cb47e3a932 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -11,7 +11,7 @@ use crate::lint::{
 use rustc_ast::node_id::NodeId;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc};
-use rustc_errors::{emitter::SilentEmitter, Handler};
+use rustc_errors::{emitter::SilentEmitter, DiagCtxt};
 use rustc_errors::{
     fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
     ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey,
@@ -103,8 +103,7 @@ pub fn feature_err_issue(
 
     // Cancel an earlier warning for this same error, if it exists.
     if let Some(span) = span.primary_span() {
-        if let Some(err) = sess.span_diagnostic.steal_diagnostic(span, StashKey::EarlySyntaxWarning)
-        {
+        if let Some(err) = sess.dcx.steal_diagnostic(span, StashKey::EarlySyntaxWarning) {
             err.cancel()
         }
     }
@@ -138,7 +137,7 @@ pub fn feature_warn_issue(
     issue: GateIssue,
     explain: &'static str,
 ) {
-    let mut err = sess.span_diagnostic.struct_span_warn(span, explain);
+    let mut err = sess.dcx.struct_span_warn(span, explain);
     add_feature_diagnostics_for_issue(&mut err, sess, feature, issue, false);
 
     // Decorate this as a future-incompatibility lint as in rustc_middle::lint::struct_lint_level
@@ -189,7 +188,7 @@ pub fn add_feature_diagnostics_for_issue(
 
 /// Info about a parsing session.
 pub struct ParseSess {
-    pub span_diagnostic: Handler,
+    pub dcx: DiagCtxt,
     pub unstable_features: UnstableFeatures,
     pub config: Cfg,
     pub check_config: CheckCfg,
@@ -227,13 +226,13 @@ impl ParseSess {
     pub fn new(locale_resources: Vec<&'static str>, file_path_mapping: FilePathMapping) -> Self {
         let fallback_bundle = fallback_fluent_bundle(locale_resources, false);
         let sm = Lrc::new(SourceMap::new(file_path_mapping));
-        let handler = Handler::with_tty_emitter(Some(sm.clone()), fallback_bundle);
-        ParseSess::with_span_handler(handler, sm)
+        let dcx = DiagCtxt::with_tty_emitter(Some(sm.clone()), fallback_bundle);
+        ParseSess::with_dcx(dcx, sm)
     }
 
-    pub fn with_span_handler(handler: Handler, source_map: Lrc<SourceMap>) -> Self {
+    pub fn with_dcx(dcx: DiagCtxt, source_map: Lrc<SourceMap>) -> Self {
         Self {
-            span_diagnostic: handler,
+            dcx,
             unstable_features: UnstableFeatures::from_environment(None),
             config: Cfg::default(),
             check_config: CheckCfg::default(),
@@ -256,10 +255,10 @@ impl ParseSess {
     pub fn with_silent_emitter(fatal_note: Option<String>) -> Self {
         let fallback_bundle = fallback_fluent_bundle(Vec::new(), false);
         let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-        let fatal_handler = Handler::with_tty_emitter(None, fallback_bundle).disable_warnings();
-        let handler = Handler::with_emitter(Box::new(SilentEmitter { fatal_handler, fatal_note }))
+        let fatal_dcx = DiagCtxt::with_tty_emitter(None, fallback_bundle).disable_warnings();
+        let dcx = DiagCtxt::with_emitter(Box::new(SilentEmitter { fatal_dcx, fatal_note }))
             .disable_warnings();
-        ParseSess::with_span_handler(handler, sm)
+        ParseSess::with_dcx(dcx, sm)
     }
 
     #[inline]
@@ -323,7 +322,7 @@ impl ParseSess {
         &'a self,
         err: impl IntoDiagnostic<'a>,
     ) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        err.into_diagnostic(&self.span_diagnostic)
+        err.into_diagnostic(&self.dcx)
     }
 
     #[track_caller]
@@ -336,7 +335,7 @@ impl ParseSess {
         &'a self,
         warning: impl IntoDiagnostic<'a, ()>,
     ) -> DiagnosticBuilder<'a, ()> {
-        warning.into_diagnostic(&self.span_diagnostic)
+        warning.into_diagnostic(&self.dcx)
     }
 
     #[track_caller]
@@ -349,7 +348,7 @@ impl ParseSess {
         &'a self,
         note: impl IntoDiagnostic<'a, Noted>,
     ) -> DiagnosticBuilder<'a, Noted> {
-        note.into_diagnostic(&self.span_diagnostic)
+        note.into_diagnostic(&self.dcx)
     }
 
     #[track_caller]
@@ -362,7 +361,7 @@ impl ParseSess {
         &'a self,
         fatal: impl IntoDiagnostic<'a, !>,
     ) -> DiagnosticBuilder<'a, !> {
-        fatal.into_diagnostic(&self.span_diagnostic)
+        fatal.into_diagnostic(&self.dcx)
     }
 
     #[track_caller]
@@ -376,18 +375,18 @@ impl ParseSess {
         &self,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        self.span_diagnostic.struct_err(msg)
+        self.dcx.struct_err(msg)
     }
 
     #[rustc_lint_diagnostics]
     #[track_caller]
     pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        self.span_diagnostic.struct_warn(msg)
+        self.dcx.struct_warn(msg)
     }
 
     #[rustc_lint_diagnostics]
     #[track_caller]
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
-        self.span_diagnostic.struct_fatal(msg)
+        self.dcx.struct_fatal(msg)
     }
 }
diff --git a/compiler/rustc_session/src/search_paths.rs b/compiler/rustc_session/src/search_paths.rs
index 07e78d1760e..8ed50f6a14f 100644
--- a/compiler/rustc_session/src/search_paths.rs
+++ b/compiler/rustc_session/src/search_paths.rs
@@ -1,5 +1,5 @@
 use crate::filesearch::make_target_lib_path;
-use crate::EarlyErrorHandler;
+use crate::EarlyDiagCtxt;
 use std::path::{Path, PathBuf};
 
 #[derive(Clone, Debug)]
@@ -46,7 +46,7 @@ impl PathKind {
 }
 
 impl SearchPath {
-    pub fn from_cli_opt(handler: &EarlyErrorHandler, path: &str) -> Self {
+    pub fn from_cli_opt(early_dcx: &EarlyDiagCtxt, path: &str) -> Self {
         let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") {
             (PathKind::Native, stripped)
         } else if let Some(stripped) = path.strip_prefix("crate=") {
@@ -61,7 +61,7 @@ impl SearchPath {
             (PathKind::All, path)
         };
         if path.is_empty() {
-            handler.early_error("empty search path given via `-L`");
+            early_dcx.early_error("empty search path given via `-L`");
         }
 
         let dir = PathBuf::from(path);
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 08a9b3d9fa0..7f168572f7d 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -22,9 +22,9 @@ use rustc_errors::emitter::{DynEmitter, EmitterWriter, HumanReadableErrorType};
 use rustc_errors::json::JsonEmitter;
 use rustc_errors::registry::Registry;
 use rustc_errors::{
-    error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage,
-    ErrorGuaranteed, FluentBundle, Handler, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted,
-    TerminalUrl,
+    error_code, fallback_fluent_bundle, DiagCtxt, DiagnosticBuilder, DiagnosticId,
+    DiagnosticMessage, ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle,
+    MultiSpan, Noted, TerminalUrl,
 };
 use rustc_macros::HashStable_Generic;
 pub use rustc_span::def_id::StableCrateId;
@@ -289,7 +289,7 @@ impl Session {
     /// Invoked all the way at the end to finish off diagnostics printing.
     pub fn finish_diagnostics(&self, registry: &Registry) {
         self.check_miri_unleashed_features();
-        self.diagnostic().print_error_count(registry);
+        self.dcx().print_error_count(registry);
         self.emit_future_breakage();
     }
 
@@ -298,11 +298,11 @@ impl Session {
             return;
         }
 
-        let diags = self.diagnostic().take_future_breakage_diagnostics();
+        let diags = self.dcx().take_future_breakage_diagnostics();
         if diags.is_empty() {
             return;
         }
-        self.diagnostic().emit_future_breakage_report(diags);
+        self.dcx().emit_future_breakage_report(diags);
     }
 
     /// Returns true if the crate is a testing one.
@@ -317,7 +317,7 @@ impl Session {
         sp: S,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, ()> {
-        self.diagnostic().struct_span_warn(sp, msg)
+        self.dcx().struct_span_warn(sp, msg)
     }
     #[rustc_lint_diagnostics]
     #[track_caller]
@@ -327,7 +327,7 @@ impl Session {
         msg: impl Into<DiagnosticMessage>,
         id: lint::LintExpectationId,
     ) -> DiagnosticBuilder<'_, ()> {
-        self.diagnostic().struct_span_warn_with_expectation(sp, msg, id)
+        self.dcx().struct_span_warn_with_expectation(sp, msg, id)
     }
     #[rustc_lint_diagnostics]
     #[track_caller]
@@ -337,12 +337,12 @@ impl Session {
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) -> DiagnosticBuilder<'_, ()> {
-        self.diagnostic().struct_span_warn_with_code(sp, msg, code)
+        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.diagnostic().struct_warn(msg)
+        self.dcx().struct_warn(msg)
     }
     #[rustc_lint_diagnostics]
     #[track_caller]
@@ -351,7 +351,7 @@ impl Session {
         msg: impl Into<DiagnosticMessage>,
         id: lint::LintExpectationId,
     ) -> DiagnosticBuilder<'_, ()> {
-        self.diagnostic().struct_warn_with_expectation(msg, id)
+        self.dcx().struct_warn_with_expectation(msg, id)
     }
     #[rustc_lint_diagnostics]
     #[track_caller]
@@ -360,12 +360,12 @@ impl Session {
         sp: S,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, ()> {
-        self.diagnostic().struct_span_allow(sp, msg)
+        self.dcx().struct_span_allow(sp, msg)
     }
     #[rustc_lint_diagnostics]
     #[track_caller]
     pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        self.diagnostic().struct_allow(msg)
+        self.dcx().struct_allow(msg)
     }
     #[rustc_lint_diagnostics]
     #[track_caller]
@@ -374,7 +374,7 @@ impl Session {
         msg: impl Into<DiagnosticMessage>,
         id: lint::LintExpectationId,
     ) -> DiagnosticBuilder<'_, ()> {
-        self.diagnostic().struct_expect(msg, id)
+        self.dcx().struct_expect(msg, id)
     }
     #[rustc_lint_diagnostics]
     #[track_caller]
@@ -383,7 +383,7 @@ impl Session {
         sp: S,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        self.diagnostic().struct_span_err(sp, msg)
+        self.dcx().struct_span_err(sp, msg)
     }
     #[rustc_lint_diagnostics]
     #[track_caller]
@@ -393,7 +393,7 @@ impl Session {
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        self.diagnostic().struct_span_err_with_code(sp, msg, code)
+        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]
@@ -411,7 +411,7 @@ impl Session {
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
-        self.diagnostic().struct_err_with_code(msg, code)
+        self.dcx().struct_err_with_code(msg, code)
     }
     #[rustc_lint_diagnostics]
     #[track_caller]
@@ -420,7 +420,7 @@ impl Session {
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) -> DiagnosticBuilder<'_, ()> {
-        self.diagnostic().struct_warn_with_code(msg, code)
+        self.dcx().struct_warn_with_code(msg, code)
     }
     #[rustc_lint_diagnostics]
     #[track_caller]
@@ -429,7 +429,7 @@ impl Session {
         sp: S,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, !> {
-        self.diagnostic().struct_span_fatal(sp, msg)
+        self.dcx().struct_span_fatal(sp, msg)
     }
     #[rustc_lint_diagnostics]
     pub fn struct_span_fatal_with_code<S: Into<MultiSpan>>(
@@ -438,17 +438,17 @@ impl Session {
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) -> DiagnosticBuilder<'_, !> {
-        self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
+        self.dcx().struct_span_fatal_with_code(sp, msg, code)
     }
     #[rustc_lint_diagnostics]
     pub fn struct_fatal(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, !> {
-        self.diagnostic().struct_fatal(msg)
+        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.diagnostic().span_fatal(sp, msg)
+        self.dcx().span_fatal(sp, msg)
     }
     #[rustc_lint_diagnostics]
     pub fn span_fatal_with_code<S: Into<MultiSpan>>(
@@ -457,11 +457,11 @@ impl Session {
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) -> ! {
-        self.diagnostic().span_fatal_with_code(sp, msg, code)
+        self.dcx().span_fatal_with_code(sp, msg, code)
     }
     #[rustc_lint_diagnostics]
     pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.diagnostic().fatal(msg)
+        self.dcx().fatal(msg)
     }
     #[rustc_lint_diagnostics]
     #[track_caller]
@@ -470,7 +470,7 @@ impl Session {
         sp: S,
         msg: impl Into<DiagnosticMessage>,
     ) -> ErrorGuaranteed {
-        self.diagnostic().span_err(sp, msg)
+        self.dcx().span_err(sp, msg)
     }
     #[rustc_lint_diagnostics]
     pub fn span_err_with_code<S: Into<MultiSpan>>(
@@ -479,13 +479,13 @@ impl Session {
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) -> ErrorGuaranteed {
-        self.diagnostic().span_err_with_code(sp, msg, code)
+        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.diagnostic().err(msg)
+        self.dcx().err(msg)
     }
     #[track_caller]
     pub fn create_err<'a>(
@@ -546,23 +546,23 @@ impl Session {
     }
     #[inline]
     pub fn err_count(&self) -> usize {
-        self.diagnostic().err_count()
+        self.dcx().err_count()
     }
     pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
-        self.diagnostic().has_errors()
+        self.dcx().has_errors()
     }
     pub fn has_errors_or_span_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
-        self.diagnostic().has_errors_or_span_delayed_bugs()
+        self.dcx().has_errors_or_span_delayed_bugs()
     }
     pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> {
-        self.diagnostic().is_compilation_going_to_fail()
+        self.dcx().is_compilation_going_to_fail()
     }
     pub fn abort_if_errors(&self) {
-        self.diagnostic().abort_if_errors();
+        self.dcx().abort_if_errors();
     }
     pub fn compile_status(&self) -> Result<(), ErrorGuaranteed> {
-        if let Some(reported) = self.diagnostic().has_errors_or_lint_errors() {
-            let _ = self.diagnostic().emit_stashed_diagnostics();
+        if let Some(reported) = self.dcx().has_errors_or_lint_errors() {
+            let _ = self.dcx().emit_stashed_diagnostics();
             Err(reported)
         } else {
             Ok(())
@@ -590,7 +590,7 @@ impl Session {
     #[allow(rustc::diagnostic_outside_of_impl)]
     #[track_caller]
     pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
-        self.diagnostic().span_warn(sp, msg)
+        self.dcx().span_warn(sp, msg)
     }
 
     #[rustc_lint_diagnostics]
@@ -602,14 +602,14 @@ impl Session {
         msg: impl Into<DiagnosticMessage>,
         code: DiagnosticId,
     ) {
-        self.diagnostic().span_warn_with_code(sp, msg, code)
+        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.diagnostic().warn(msg)
+        self.dcx().warn(msg)
     }
 
     /// Ensures that compilation cannot succeed.
@@ -634,7 +634,7 @@ impl Session {
         sp: S,
         msg: impl Into<DiagnosticMessage>,
     ) -> ErrorGuaranteed {
-        self.diagnostic().span_delayed_bug(sp, msg)
+        self.dcx().span_delayed_bug(sp, msg)
     }
 
     /// Used for code paths of expensive computations that should only take place when
@@ -651,14 +651,14 @@ impl Session {
             return;
         }
 
-        self.diagnostic().good_path_delayed_bug(msg)
+        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.diagnostic().note(msg)
+        self.dcx().note(msg)
     }
 
     #[track_caller]
@@ -666,19 +666,19 @@ impl Session {
     #[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.diagnostic().span_note(sp, msg)
+        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.diagnostic().struct_note(msg)
+        self.dcx().struct_note(msg)
     }
 
     #[inline]
-    pub fn diagnostic(&self) -> &Handler {
-        &self.parse_sess.span_diagnostic
+    pub fn dcx(&self) -> &DiagCtxt {
+        &self.parse_sess.dcx
     }
 
     #[inline]
@@ -881,7 +881,7 @@ impl Session {
                 let mut fuel = self.optimization_fuel.lock();
                 ret = fuel.remaining != 0;
                 if fuel.remaining == 0 && !fuel.out_of_fuel {
-                    if self.diagnostic().can_emit_warnings() {
+                    if self.dcx().can_emit_warnings() {
                         // We only call `msg` in case we can actually emit warnings.
                         // Otherwise, this could cause a `good_path_delayed_bug` to
                         // trigger (issue #79546).
@@ -1221,7 +1221,7 @@ impl Session {
     }
 
     pub fn teach(&self, code: &DiagnosticId) -> bool {
-        self.opts.unstable_opts.teach && self.diagnostic().must_teach(code)
+        self.opts.unstable_opts.teach && self.dcx().must_teach(code)
     }
 
     pub fn edition(&self) -> Edition {
@@ -1357,7 +1357,7 @@ fn default_emitter(
 // JUSTIFICATION: literally session construction
 #[allow(rustc::bad_opt_access)]
 pub fn build_session(
-    early_handler: EarlyErrorHandler,
+    early_dcx: EarlyDiagCtxt,
     sopts: config::Options,
     io: CompilerIO,
     bundle: Option<Lrc<rustc_errors::FluentBundle>>,
@@ -1387,13 +1387,13 @@ pub fn build_session(
         None => filesearch::get_or_default_sysroot().expect("Failed finding sysroot"),
     };
 
-    let target_cfg = config::build_target_config(&early_handler, &sopts, target_override, &sysroot);
+    let target_cfg = config::build_target_config(&early_dcx, &sopts, target_override, &sysroot);
     let host_triple = TargetTriple::from_triple(config::host_triple());
     let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| {
-        early_handler.early_error(format!("Error loading host specification: {e}"))
+        early_dcx.early_error(format!("Error loading host specification: {e}"))
     });
     for warning in target_warnings.warning_messages() {
-        early_handler.early_warn(warning)
+        early_dcx.early_warn(warning)
     }
 
     let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
@@ -1416,15 +1416,15 @@ pub fn build_session(
     );
     let emitter = default_emitter(&sopts, registry, source_map.clone(), bundle, fallback_bundle);
 
-    let mut span_diagnostic = Handler::with_emitter(emitter)
-        .with_flags(sopts.unstable_opts.diagnostic_handler_flags(can_emit_warnings));
+    let mut dcx = DiagCtxt::with_emitter(emitter)
+        .with_flags(sopts.unstable_opts.dcx_flags(can_emit_warnings));
     if let Some(ice_file) = ice_file {
-        span_diagnostic = span_diagnostic.with_ice_file(ice_file);
+        dcx = dcx.with_ice_file(ice_file);
     }
 
-    // Now that the proper handler has been constructed, drop the early handler
-    // to prevent accidental use.
-    drop(early_handler);
+    // Now that the proper handler has been constructed, drop early_dcx to
+    // prevent accidental use.
+    drop(early_dcx);
 
     let self_profiler = if let SwitchWithOptPath::Enabled(ref d) = sopts.unstable_opts.self_profile
     {
@@ -1440,7 +1440,7 @@ pub fn build_session(
         match profiler {
             Ok(profiler) => Some(Arc::new(profiler)),
             Err(e) => {
-                span_diagnostic.emit_warning(errors::FailedToCreateProfiler { err: e.to_string() });
+                dcx.emit_warning(errors::FailedToCreateProfiler { err: e.to_string() });
                 None
             }
         }
@@ -1448,7 +1448,7 @@ pub fn build_session(
         None
     };
 
-    let mut parse_sess = ParseSess::with_span_handler(span_diagnostic, source_map);
+    let mut parse_sess = ParseSess::with_dcx(dcx, source_map);
     parse_sess.assume_incomplete_release = sopts.unstable_opts.assume_incomplete_release;
 
     let host_triple = config::host_triple();
@@ -1725,54 +1725,54 @@ enum IncrCompSession {
     InvalidBecauseOfErrors { session_directory: PathBuf },
 }
 
-/// A wrapper around an [`Handler`] that is used for early error emissions.
-pub struct EarlyErrorHandler {
-    handler: Handler,
+/// A wrapper around an [`DiagCtxt`] that is used for early error emissions.
+pub struct EarlyDiagCtxt {
+    dcx: DiagCtxt,
 }
 
-impl EarlyErrorHandler {
+impl EarlyDiagCtxt {
     pub fn new(output: ErrorOutputType) -> Self {
         let emitter = mk_emitter(output);
-        Self { handler: Handler::with_emitter(emitter) }
+        Self { dcx: DiagCtxt::with_emitter(emitter) }
     }
 
     pub fn abort_if_errors(&self) {
-        self.handler.abort_if_errors()
+        self.dcx.abort_if_errors()
     }
 
-    /// Swap out the underlying handler once we acquire the user's preference on error emission
+    /// Swap out the underlying dcx once we acquire the user's preference on error emission
     /// format. Any errors prior to that will cause an abort and all stashed diagnostics of the
-    /// previous handler will be emitted.
+    /// previous dcx will be emitted.
     pub fn abort_if_error_and_set_error_format(&mut self, output: ErrorOutputType) {
-        self.handler.abort_if_errors();
+        self.dcx.abort_if_errors();
 
         let emitter = mk_emitter(output);
-        self.handler = Handler::with_emitter(emitter);
+        self.dcx = DiagCtxt::with_emitter(emitter);
     }
 
     #[allow(rustc::untranslatable_diagnostic)]
     #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn early_note(&self, msg: impl Into<DiagnosticMessage>) {
-        self.handler.struct_note(msg).emit()
+        self.dcx.struct_note(msg).emit()
     }
 
     #[allow(rustc::untranslatable_diagnostic)]
     #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn early_help(&self, msg: impl Into<DiagnosticMessage>) {
-        self.handler.struct_help(msg).emit()
+        self.dcx.struct_help(msg).emit()
     }
 
     #[allow(rustc::untranslatable_diagnostic)]
     #[allow(rustc::diagnostic_outside_of_impl)]
     #[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"]
     pub fn early_error_no_abort(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
-        self.handler.struct_err(msg).emit()
+        self.dcx.struct_err(msg).emit()
     }
 
     #[allow(rustc::untranslatable_diagnostic)]
     #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn early_error(&self, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.handler.struct_fatal(msg).emit()
+        self.dcx.struct_fatal(msg).emit()
     }
 
     #[allow(rustc::untranslatable_diagnostic)]
@@ -1781,13 +1781,13 @@ impl EarlyErrorHandler {
         &self,
         msg: impl Into<DiagnosticMessage>,
     ) -> DiagnosticBuilder<'_, !> {
-        self.handler.struct_fatal(msg)
+        self.dcx.struct_fatal(msg)
     }
 
     #[allow(rustc::untranslatable_diagnostic)]
     #[allow(rustc::diagnostic_outside_of_impl)]
     pub fn early_warn(&self, msg: impl Into<DiagnosticMessage>) {
-        self.handler.struct_warn(msg).emit()
+        self.dcx.struct_warn(msg).emit()
     }
 
     pub fn initialize_checked_jobserver(&self) {
@@ -1795,10 +1795,7 @@ impl EarlyErrorHandler {
         jobserver::initialize_checked(|err| {
             #[allow(rustc::untranslatable_diagnostic)]
             #[allow(rustc::diagnostic_outside_of_impl)]
-            self.handler
-                .struct_warn(err)
-                .note("the build environment is likely misconfigured")
-                .emit()
+            self.dcx.struct_warn(err).note("the build environment is likely misconfigured").emit()
         });
     }
 }
diff --git a/compiler/rustc_symbol_mangling/src/errors.rs b/compiler/rustc_symbol_mangling/src/errors.rs
index 2e081e55531..ff253b6f467 100644
--- a/compiler/rustc_symbol_mangling/src/errors.rs
+++ b/compiler/rustc_symbol_mangling/src/errors.rs
@@ -16,12 +16,12 @@ pub struct TestOutput {
 impl IntoDiagnostic<'_> for TestOutput {
     fn into_diagnostic(
         self,
-        handler: &'_ rustc_errors::Handler,
+        dcx: &'_ rustc_errors::DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
         let TestOutput { span, kind, content } = self;
 
         #[allow(rustc::untranslatable_diagnostic)]
-        let mut diag = handler.struct_err(format!("{kind}({content})"));
+        let mut diag = dcx.struct_err(format!("{kind}({content})"));
         diag.set_span(span);
         diag
     }
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index c1fb287d63e..b0ec8b3a4fa 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1,6 +1,6 @@
 use crate::fluent_generated as fluent;
 use rustc_errors::{
-    AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, Handler, IntoDiagnostic,
+    AddToDiagnostic, Applicability, DiagCtxt, Diagnostic, ErrorGuaranteed, IntoDiagnostic,
     SubdiagnosticMessage,
 };
 use rustc_macros::Diagnostic;
@@ -61,9 +61,9 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
     #[track_caller]
     fn into_diagnostic(
         self,
-        handler: &Handler,
+        dcx: &DiagCtxt,
     ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> {
-        let mut diag = handler.struct_err(fluent::trait_selection_negative_positive_conflict);
+        let mut diag = dcx.struct_err(fluent::trait_selection_negative_positive_conflict);
         diag.set_arg("trait_desc", self.trait_desc.print_only_trait_path().to_string());
         diag.set_arg(
             "self_desc",
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 5cc934e7bc5..9ee091bbd1e 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
@@ -3395,7 +3395,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         };
 
         if let Some(diag) =
-            self.tcx.sess.diagnostic().steal_diagnostic(self.tcx.def_span(def_id), StashKey::Cycle)
+            self.tcx.sess.dcx().steal_diagnostic(self.tcx.def_span(def_id), StashKey::Cycle)
         {
             diag.cancel();
         }
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 47a79bfa9ab..7ac37315fe0 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -594,9 +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
-                    .diagnostic()
-                    .span_delayed_bug(span, "auto traits cannot have generic parameters");
+                tcx.sess.dcx().span_delayed_bug(span, "auto traits cannot have generic parameters");
             }
             return false;
         }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 8e8b7ab346b..fb09d399b98 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -15,11 +15,11 @@ use rustc_session::config::{
 use rustc_session::getopts;
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
-use rustc_session::EarlyErrorHandler;
+use rustc_session::EarlyDiagCtxt;
 use rustc_span::edition::Edition;
 use rustc_target::spec::TargetTriple;
 
-use crate::core::new_handler;
+use crate::core::new_dcx;
 use crate::externalfiles::ExternalHtml;
 use crate::html;
 use crate::html::markdown::IdMap;
@@ -320,38 +320,38 @@ impl Options {
     /// Parses the given command-line for options. If an error message or other early-return has
     /// been printed, returns `Err` with the exit code.
     pub(crate) fn from_matches(
-        handler: &mut EarlyErrorHandler,
+        early_dcx: &mut EarlyDiagCtxt,
         matches: &getopts::Matches,
         args: Vec<String>,
     ) -> Result<(Options, RenderOptions), i32> {
         // Check for unstable options.
-        nightly_options::check_nightly_options(handler, matches, &opts());
+        nightly_options::check_nightly_options(early_dcx, matches, &opts());
 
         if args.is_empty() || matches.opt_present("h") || matches.opt_present("help") {
             crate::usage("rustdoc");
             return Err(0);
         } else if matches.opt_present("version") {
-            rustc_driver::version!(&handler, "rustdoc", matches);
+            rustc_driver::version!(&early_dcx, "rustdoc", matches);
             return Err(0);
         }
 
-        if rustc_driver::describe_flag_categories(handler, &matches) {
+        if rustc_driver::describe_flag_categories(early_dcx, &matches) {
             return Err(0);
         }
 
-        let color = config::parse_color(handler, matches);
+        let color = config::parse_color(early_dcx, matches);
         let config::JsonConfig { json_rendered, json_unused_externs, .. } =
-            config::parse_json(handler, matches);
-        let error_format = config::parse_error_format(handler, matches, color, json_rendered);
+            config::parse_json(early_dcx, matches);
+        let error_format = config::parse_error_format(early_dcx, matches, color, json_rendered);
         let diagnostic_width = matches.opt_get("diagnostic-width").unwrap_or_default();
 
-        let codegen_options = CodegenOptions::build(handler, matches);
-        let unstable_opts = UnstableOptions::build(handler, matches);
+        let codegen_options = CodegenOptions::build(early_dcx, matches);
+        let unstable_opts = UnstableOptions::build(early_dcx, matches);
 
-        let diag = new_handler(error_format, None, diagnostic_width, &unstable_opts);
+        let dcx = new_dcx(error_format, None, diagnostic_width, &unstable_opts);
 
         // check for deprecated options
-        check_deprecated_options(matches, &diag);
+        check_deprecated_options(matches, &dcx);
 
         if matches.opt_strs("passes") == ["list"] {
             println!("Available passes for running rustdoc:");
@@ -391,7 +391,7 @@ impl Options {
                 match kind.parse() {
                     Ok(kind) => emit.push(kind),
                     Err(()) => {
-                        diag.err(format!("unrecognized emission type: {kind}"));
+                        dcx.err(format!("unrecognized emission type: {kind}"));
                         return Err(1);
                     }
                 }
@@ -403,7 +403,7 @@ impl Options {
             && !matches.opt_present("show-coverage")
             && !nightly_options::is_unstable_enabled(matches)
         {
-            handler.early_error(
+            early_dcx.early_error(
                 "the -Z unstable-options flag must be passed to enable --output-format for documentation generation (see https://github.com/rust-lang/rust/issues/76578)",
             );
         }
@@ -421,7 +421,7 @@ impl Options {
             let paths = match theme::load_css_paths(content) {
                 Ok(p) => p,
                 Err(e) => {
-                    diag.struct_err(e).emit();
+                    dcx.struct_err(e).emit();
                     return Err(1);
                 }
             };
@@ -430,7 +430,7 @@ impl Options {
             println!("rustdoc: [check-theme] Starting tests! (Ignoring all other arguments)");
             for theme_file in to_check.iter() {
                 print!(" - Checking \"{theme_file}\"...");
-                let (success, differences) = theme::test_theme_against(theme_file, &paths, &diag);
+                let (success, differences) = theme::test_theme_against(theme_file, &paths, &dcx);
                 if !differences.is_empty() || !success {
                     println!(" FAILED");
                     errors += 1;
@@ -447,27 +447,27 @@ impl Options {
             return Err(0);
         }
 
-        let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(handler, matches);
+        let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
 
         let input = PathBuf::from(if describe_lints {
             "" // dummy, this won't be used
         } else if matches.free.is_empty() {
-            diag.struct_err("missing file operand").emit();
+            dcx.struct_err("missing file operand").emit();
             return Err(1);
         } else if matches.free.len() > 1 {
-            diag.struct_err("too many file operands").emit();
+            dcx.struct_err("too many file operands").emit();
             return Err(1);
         } else {
             &matches.free[0]
         });
 
         let libs =
-            matches.opt_strs("L").iter().map(|s| SearchPath::from_cli_opt(handler, s)).collect();
-        let externs = parse_externs(handler, matches, &unstable_opts);
+            matches.opt_strs("L").iter().map(|s| SearchPath::from_cli_opt(early_dcx, s)).collect();
+        let externs = parse_externs(early_dcx, matches, &unstable_opts);
         let extern_html_root_urls = match parse_extern_html_roots(matches) {
             Ok(ex) => ex,
             Err(err) => {
-                diag.struct_err(err).emit();
+                dcx.struct_err(err).emit();
                 return Err(1);
             }
         };
@@ -526,7 +526,7 @@ impl Options {
         let no_run = matches.opt_present("no-run");
 
         if !should_test && no_run {
-            diag.err("the `--test` flag must be passed to enable `--no-run`");
+            dcx.err("the `--test` flag must be passed to enable `--no-run`");
             return Err(1);
         }
 
@@ -534,7 +534,7 @@ impl Options {
         let output = matches.opt_str("output").map(|s| PathBuf::from(&s));
         let output = match (out_dir, output) {
             (Some(_), Some(_)) => {
-                diag.struct_err("cannot use both 'out-dir' and 'output' at once").emit();
+                dcx.struct_err("cannot use both 'out-dir' and 'output' at once").emit();
                 return Err(1);
             }
             (Some(out_dir), None) => out_dir,
@@ -549,7 +549,7 @@ impl Options {
 
         if let Some(ref p) = extension_css {
             if !p.is_file() {
-                diag.struct_err("option --extend-css argument must be a file").emit();
+                dcx.struct_err("option --extend-css argument must be a file").emit();
                 return Err(1);
             }
         }
@@ -567,7 +567,7 @@ impl Options {
             let paths = match theme::load_css_paths(content) {
                 Ok(p) => p,
                 Err(e) => {
-                    diag.struct_err(e).emit();
+                    dcx.struct_err(e).emit();
                     return Err(1);
                 }
             };
@@ -576,23 +576,23 @@ impl Options {
                 matches.opt_strs("theme").iter().map(|s| (PathBuf::from(&s), s.to_owned()))
             {
                 if !theme_file.is_file() {
-                    diag.struct_err(format!("invalid argument: \"{theme_s}\""))
+                    dcx.struct_err(format!("invalid argument: \"{theme_s}\""))
                         .help("arguments to --theme must be files")
                         .emit();
                     return Err(1);
                 }
                 if theme_file.extension() != Some(OsStr::new("css")) {
-                    diag.struct_err(format!("invalid argument: \"{theme_s}\""))
+                    dcx.struct_err(format!("invalid argument: \"{theme_s}\""))
                         .help("arguments to --theme must have a .css extension")
                         .emit();
                     return Err(1);
                 }
-                let (success, ret) = theme::test_theme_against(&theme_file, &paths, &diag);
+                let (success, ret) = theme::test_theme_against(&theme_file, &paths, &dcx);
                 if !success {
-                    diag.struct_err(format!("error loading theme file: \"{theme_s}\"")).emit();
+                    dcx.struct_err(format!("error loading theme file: \"{theme_s}\"")).emit();
                     return Err(1);
                 } else if !ret.is_empty() {
-                    diag.struct_warn(format!(
+                    dcx.struct_warn(format!(
                         "theme file \"{theme_s}\" is missing CSS rules from the default theme",
                     ))
                     .warn("the theme may appear incorrect when loaded")
@@ -605,7 +605,7 @@ impl Options {
             }
         }
 
-        let edition = config::parse_crate_edition(handler, matches);
+        let edition = config::parse_crate_edition(early_dcx, matches);
 
         let mut id_map = html::markdown::IdMap::new();
         let Some(external_html) = ExternalHtml::load(
@@ -615,7 +615,7 @@ impl Options {
             &matches.opt_strs("markdown-before-content"),
             &matches.opt_strs("markdown-after-content"),
             nightly_options::match_is_nightly_build(matches),
-            &diag,
+            &dcx,
             &mut id_map,
             edition,
             &None,
@@ -626,7 +626,7 @@ impl Options {
         match matches.opt_str("r").as_deref() {
             Some("rust") | None => {}
             Some(s) => {
-                diag.struct_err(format!("unknown input format: {s}")).emit();
+                dcx.struct_err(format!("unknown input format: {s}")).emit();
                 return Err(1);
             }
         }
@@ -634,19 +634,19 @@ impl Options {
         let index_page = matches.opt_str("index-page").map(|s| PathBuf::from(&s));
         if let Some(ref index_page) = index_page {
             if !index_page.is_file() {
-                diag.struct_err("option `--index-page` argument must be a file").emit();
+                dcx.struct_err("option `--index-page` argument must be a file").emit();
                 return Err(1);
             }
         }
 
-        let target = parse_target_triple(handler, matches);
+        let target = parse_target_triple(early_dcx, matches);
 
         let show_coverage = matches.opt_present("show-coverage");
 
         let crate_types = match parse_crate_types_from_list(matches.opt_strs("crate-type")) {
             Ok(types) => types,
             Err(e) => {
-                diag.struct_err(format!("unknown crate type: {e}")).emit();
+                dcx.struct_err(format!("unknown crate type: {e}")).emit();
                 return Err(1);
             }
         };
@@ -655,7 +655,7 @@ impl Options {
             Some(s) => match OutputFormat::try_from(s.as_str()) {
                 Ok(out_fmt) => {
                     if !out_fmt.is_json() && show_coverage {
-                        diag.struct_err(
+                        dcx.struct_err(
                             "html output format isn't supported for the --show-coverage option",
                         )
                         .emit();
@@ -664,7 +664,7 @@ impl Options {
                     out_fmt
                 }
                 Err(e) => {
-                    diag.struct_err(e).emit();
+                    dcx.struct_err(e).emit();
                     return Err(1);
                 }
             },
@@ -709,16 +709,16 @@ impl Options {
         let html_no_source = matches.opt_present("html-no-source");
 
         if generate_link_to_definition && (show_coverage || output_format != OutputFormat::Html) {
-            diag.struct_err(
+            dcx.struct_err(
                 "--generate-link-to-definition option can only be used with HTML output format",
             )
             .emit();
             return Err(1);
         }
 
-        let scrape_examples_options = ScrapeExamplesOptions::new(matches, &diag)?;
+        let scrape_examples_options = ScrapeExamplesOptions::new(matches, &dcx)?;
         let with_examples = matches.opt_strs("with-examples");
-        let call_locations = crate::scrape_examples::load_call_locations(with_examples, &diag)?;
+        let call_locations = crate::scrape_examples::load_call_locations(with_examples, &dcx)?;
 
         let unstable_features =
             rustc_feature::UnstableFeatures::from_environment(crate_name.as_deref());
@@ -803,12 +803,12 @@ impl Options {
 }
 
 /// Prints deprecation warnings for deprecated options
-fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Handler) {
+fn check_deprecated_options(matches: &getopts::Matches, dcx: &rustc_errors::DiagCtxt) {
     let deprecated_flags = [];
 
     for &flag in deprecated_flags.iter() {
         if matches.opt_present(flag) {
-            diag.struct_warn(format!("the `{flag}` flag is deprecated"))
+            dcx.struct_warn(format!("the `{flag}` flag is deprecated"))
                 .note(
                     "see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
                     for more information",
@@ -821,7 +821,7 @@ fn check_deprecated_options(matches: &getopts::Matches, diag: &rustc_errors::Han
 
     for &flag in removed_flags.iter() {
         if matches.opt_present(flag) {
-            let mut err = diag.struct_warn(format!("the `{flag}` flag no longer functions"));
+            let mut err = dcx.struct_warn(format!("the `{flag}` flag no longer functions"));
             err.note(
                 "see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
                 for more information",
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 0150496990d..4e904ffd768 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -120,16 +120,16 @@ impl<'tcx> DocContext<'tcx> {
     }
 }
 
-/// Creates a new diagnostic `Handler` that can be used to emit warnings and errors.
+/// Creates a new `DiagCtxt` that can be used to emit warnings and errors.
 ///
 /// If the given `error_format` is `ErrorOutputType::Json` and no `SourceMap` is given, a new one
-/// will be created for the handler.
-pub(crate) fn new_handler(
+/// will be created for the `DiagCtxt`.
+pub(crate) fn new_dcx(
     error_format: ErrorOutputType,
     source_map: Option<Lrc<source_map::SourceMap>>,
     diagnostic_width: Option<usize>,
     unstable_opts: &UnstableOptions,
-) -> rustc_errors::Handler {
+) -> rustc_errors::DiagCtxt {
     let fallback_bundle = rustc_errors::fallback_fluent_bundle(
         rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(),
         false,
@@ -169,8 +169,7 @@ pub(crate) fn new_handler(
         }
     };
 
-    rustc_errors::Handler::with_emitter(emitter)
-        .with_flags(unstable_opts.diagnostic_handler_flags(true))
+    rustc_errors::DiagCtxt::with_emitter(emitter).with_flags(unstable_opts.dcx_flags(true))
 }
 
 /// Parse, resolve, and typecheck the given crate.
@@ -386,9 +385,9 @@ pub(crate) fn run_global_ctxt(
         );
     }
 
-    fn report_deprecated_attr(name: &str, diag: &rustc_errors::Handler, sp: Span) {
+    fn report_deprecated_attr(name: &str, dcx: &rustc_errors::DiagCtxt, sp: Span) {
         let mut msg =
-            diag.struct_span_warn(sp, format!("the `#![doc({name})]` attribute is deprecated"));
+            dcx.struct_span_warn(sp, format!("the `#![doc({name})]` attribute is deprecated"));
         msg.note(
             "see issue #44136 <https://github.com/rust-lang/rust/issues/44136> \
             for more information",
@@ -408,19 +407,19 @@ pub(crate) fn run_global_ctxt(
     // Process all of the crate attributes, extracting plugin metadata along
     // with the passes which we are supposed to run.
     for attr in krate.module.attrs.lists(sym::doc) {
-        let diag = ctxt.sess().diagnostic();
+        let dcx = ctxt.sess().dcx();
 
         let name = attr.name_or_empty();
         // `plugins = "..."`, `no_default_passes`, and `passes = "..."` have no effect
         if attr.is_word() && name == sym::no_default_passes {
-            report_deprecated_attr("no_default_passes", diag, attr.span());
+            report_deprecated_attr("no_default_passes", dcx, attr.span());
         } else if attr.value_str().is_some() {
             match name {
                 sym::passes => {
-                    report_deprecated_attr("passes = \"...\"", diag, attr.span());
+                    report_deprecated_attr("passes = \"...\"", dcx, attr.span());
                 }
                 sym::plugins => {
-                    report_deprecated_attr("plugins = \"...\"", diag, attr.span());
+                    report_deprecated_attr("plugins = \"...\"", dcx, attr.span());
                 }
                 _ => (),
             }
@@ -448,7 +447,7 @@ pub(crate) fn run_global_ctxt(
 
     tcx.sess.time("check_lint_expectations", || tcx.check_expectations(Some(sym::rustdoc)));
 
-    if tcx.sess.diagnostic().has_errors_or_lint_errors().is_some() {
+    if tcx.sess.dcx().has_errors_or_lint_errors().is_some() {
         rustc_errors::FatalError.raise();
     }
 
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 172b7243627..c74f2ecb018 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -150,7 +150,7 @@ pub(crate) fn run(options: RustdocOptions) -> Result<(), ErrorGuaranteed> {
 
                     collector
                 });
-                if compiler.sess.diagnostic().has_errors_or_lint_errors().is_some() {
+                if compiler.sess.dcx().has_errors_or_lint_errors().is_some() {
                     FatalError.raise();
                 }
 
@@ -558,7 +558,7 @@ pub(crate) fn make_test(
     let result = rustc_driver::catch_fatal_errors(|| {
         rustc_span::create_session_if_not_set_then(edition, |_| {
             use rustc_errors::emitter::{Emitter, EmitterWriter};
-            use rustc_errors::Handler;
+            use rustc_errors::DiagCtxt;
             use rustc_parse::parser::ForceCollect;
             use rustc_span::source_map::FilePathMapping;
 
@@ -579,8 +579,8 @@ pub(crate) fn make_test(
             let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
 
             // FIXME(misdreavus): pass `-Z treat-err-as-bug` to the doctest parser
-            let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
-            let sess = ParseSess::with_span_handler(handler, sm);
+            let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings();
+            let sess = ParseSess::with_dcx(dcx, sm);
 
             let mut found_main = false;
             let mut found_extern_crate = crate_name.is_none();
@@ -638,10 +638,10 @@ pub(crate) fn make_test(
             }
 
             // Reset errors so that they won't be reported as compiler bugs when dropping the
-            // handler. Any errors in the tests will be reported when the test file is compiled,
+            // dcx. Any errors in the tests will be reported when the test file is compiled,
             // Note that we still need to cancel the errors above otherwise `DiagnosticBuilder`
             // will panic on drop.
-            sess.span_diagnostic.reset_err_count();
+            sess.dcx.reset_err_count();
 
             (found_main, found_extern_crate, found_macro)
         })
@@ -740,7 +740,7 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
     rustc_driver::catch_fatal_errors(|| {
         rustc_span::create_session_if_not_set_then(edition, |_| {
             use rustc_errors::emitter::EmitterWriter;
-            use rustc_errors::Handler;
+            use rustc_errors::DiagCtxt;
             use rustc_span::source_map::FilePathMapping;
 
             let filename = FileName::anon_source_code(source);
@@ -754,8 +754,8 @@ fn check_if_attr_is_complete(source: &str, edition: Edition) -> bool {
 
             let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
 
-            let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
-            let sess = ParseSess::with_span_handler(handler, sm);
+            let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings();
+            let sess = ParseSess::with_dcx(dcx, sm);
             let mut parser =
                 match maybe_new_parser_from_source_str(&sess, filename, source.to_owned()) {
                     Ok(p) => p,
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index b34b69b1f15..8bc0cdf3a95 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -27,15 +27,15 @@ impl ExternalHtml {
         md_before_content: &[String],
         md_after_content: &[String],
         nightly_build: bool,
-        diag: &rustc_errors::Handler,
+        dcx: &rustc_errors::DiagCtxt,
         id_map: &mut IdMap,
         edition: Edition,
         playground: &Option<Playground>,
     ) -> Option<ExternalHtml> {
         let codes = ErrorCodes::from(nightly_build);
-        let ih = load_external_files(in_header, diag)?;
-        let bc = load_external_files(before_content, diag)?;
-        let m_bc = load_external_files(md_before_content, diag)?;
+        let ih = load_external_files(in_header, dcx)?;
+        let bc = load_external_files(before_content, dcx)?;
+        let m_bc = load_external_files(md_before_content, dcx)?;
         let bc = format!(
             "{bc}{}",
             Markdown {
@@ -51,8 +51,8 @@ impl ExternalHtml {
             }
             .into_string()
         );
-        let ac = load_external_files(after_content, diag)?;
-        let m_ac = load_external_files(md_after_content, diag)?;
+        let ac = load_external_files(after_content, dcx)?;
+        let m_ac = load_external_files(md_after_content, dcx)?;
         let ac = format!(
             "{ac}{}",
             Markdown {
@@ -79,13 +79,13 @@ pub(crate) enum LoadStringError {
 
 pub(crate) fn load_string<P: AsRef<Path>>(
     file_path: P,
-    diag: &rustc_errors::Handler,
+    dcx: &rustc_errors::DiagCtxt,
 ) -> Result<String, LoadStringError> {
     let file_path = file_path.as_ref();
     let contents = match fs::read(file_path) {
         Ok(bytes) => bytes,
         Err(e) => {
-            diag.struct_err(format!(
+            dcx.struct_err(format!(
                 "error reading `{file_path}`: {e}",
                 file_path = file_path.display()
             ))
@@ -96,16 +96,16 @@ pub(crate) fn load_string<P: AsRef<Path>>(
     match str::from_utf8(&contents) {
         Ok(s) => Ok(s.to_string()),
         Err(_) => {
-            diag.struct_err(format!("error reading `{}`: not UTF-8", file_path.display())).emit();
+            dcx.struct_err(format!("error reading `{}`: not UTF-8", file_path.display())).emit();
             Err(LoadStringError::BadUtf8)
         }
     }
 }
 
-fn load_external_files(names: &[String], diag: &rustc_errors::Handler) -> Option<String> {
+fn load_external_files(names: &[String], dcx: &rustc_errors::DiagCtxt) -> Option<String> {
     let mut out = String::new();
     for name in names {
-        let Ok(s) = load_string(name, diag) else { return None };
+        let Ok(s) = load_string(name, dcx) else { return None };
         out.push_str(&s);
         out.push('\n');
     }
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 1c02e0ba76e..52803c2b005 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -82,7 +82,7 @@ use rustc_errors::ErrorGuaranteed;
 use rustc_interface::interface;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup};
-use rustc_session::{getopts, EarlyErrorHandler};
+use rustc_session::{getopts, EarlyDiagCtxt};
 
 use crate::clean::utils::DOC_RUST_LANG_ORG_CHANNEL;
 
@@ -157,7 +157,7 @@ pub fn main() {
         }
     }
 
-    let mut handler = EarlyErrorHandler::new(ErrorOutputType::default());
+    let mut early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
     let using_internal_features = rustc_driver::install_ice_hook(
         "https://github.com/rust-lang/rust/issues/new\
@@ -175,11 +175,11 @@ pub fn main() {
     // `debug_logging = true` is because all rustc logging goes to its version of tracing (the one
     // in the sysroot), and all of rustdoc's logging goes to its version (the one in Cargo.toml).
 
-    init_logging(&handler);
-    rustc_driver::init_logger(&handler, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG"));
+    init_logging(&early_dcx);
+    rustc_driver::init_logger(&early_dcx, rustc_log::LoggerConfig::from_env("RUSTDOC_LOG"));
 
-    let exit_code = rustc_driver::catch_with_exit_code(|| match get_args(&handler) {
-        Some(args) => main_args(&mut handler, &args, using_internal_features),
+    let exit_code = rustc_driver::catch_with_exit_code(|| match get_args(&early_dcx) {
+        Some(args) => main_args(&mut early_dcx, &args, using_internal_features),
         _ =>
         {
             #[allow(deprecated)]
@@ -189,15 +189,15 @@ pub fn main() {
     process::exit(exit_code);
 }
 
-fn init_logging(handler: &EarlyErrorHandler) {
+fn init_logging(early_dcx: &EarlyDiagCtxt) {
     let color_logs = match std::env::var("RUSTDOC_LOG_COLOR").as_deref() {
         Ok("always") => true,
         Ok("never") => false,
         Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(),
-        Ok(value) => handler.early_error(format!(
+        Ok(value) => early_dcx.early_error(format!(
             "invalid log color value '{value}': expected one of always, never, or auto",
         )),
-        Err(VarError::NotUnicode(value)) => handler.early_error(format!(
+        Err(VarError::NotUnicode(value)) => early_dcx.early_error(format!(
             "invalid log color value '{}': expected one of always, never, or auto",
             value.to_string_lossy()
         )),
@@ -220,13 +220,13 @@ fn init_logging(handler: &EarlyErrorHandler) {
     tracing::subscriber::set_global_default(subscriber).unwrap();
 }
 
-fn get_args(handler: &EarlyErrorHandler) -> Option<Vec<String>> {
+fn get_args(early_dcx: &EarlyDiagCtxt) -> Option<Vec<String>> {
     env::args_os()
         .enumerate()
         .map(|(i, arg)| {
             arg.into_string()
                 .map_err(|arg| {
-                    handler.early_warn(format!("Argument {i} is not valid Unicode: {arg:?}"));
+                    early_dcx.early_warn(format!("Argument {i} is not valid Unicode: {arg:?}"));
                 })
                 .ok()
         })
@@ -673,11 +673,11 @@ fn usage(argv0: &str) {
 /// A result type used by several functions under `main()`.
 type MainResult = Result<(), ErrorGuaranteed>;
 
-fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult {
+fn wrap_return(dcx: &rustc_errors::DiagCtxt, res: Result<(), String>) -> MainResult {
     match res {
-        Ok(()) => diag.has_errors().map_or(Ok(()), Err),
+        Ok(()) => dcx.has_errors().map_or(Ok(()), Err),
         Err(err) => {
-            let reported = diag.struct_err(err).emit();
+            let reported = dcx.struct_err(err).emit();
             Err(reported)
         }
     }
@@ -704,7 +704,7 @@ fn run_renderer<'tcx, T: formats::FormatRenderer<'tcx>>(
 }
 
 fn main_args(
-    handler: &mut EarlyErrorHandler,
+    early_dcx: &mut EarlyDiagCtxt,
     at_args: &[String],
     using_internal_features: Arc<AtomicBool>,
 ) -> MainResult {
@@ -718,7 +718,7 @@ fn main_args(
     // the compiler with @empty_file as argv[0] and no more arguments.
     let at_args = at_args.get(1..).unwrap_or_default();
 
-    let args = rustc_driver::args::arg_expand_all(handler, at_args);
+    let args = rustc_driver::args::arg_expand_all(early_dcx, at_args);
 
     let mut options = getopts::Options::new();
     for option in opts() {
@@ -727,13 +727,13 @@ fn main_args(
     let matches = match options.parse(&args) {
         Ok(m) => m,
         Err(err) => {
-            handler.early_error(err.to_string());
+            early_dcx.early_error(err.to_string());
         }
     };
 
     // Note that we discard any distinction between different non-zero exit
     // codes from `from_matches` here.
-    let (options, render_options) = match config::Options::from_matches(handler, &matches, args) {
+    let (options, render_options) = match config::Options::from_matches(early_dcx, &matches, args) {
         Ok(opts) => opts,
         Err(code) => {
             return if code == 0 {
@@ -745,12 +745,8 @@ fn main_args(
         }
     };
 
-    let diag = core::new_handler(
-        options.error_format,
-        None,
-        options.diagnostic_width,
-        &options.unstable_opts,
-    );
+    let diag =
+        core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
 
     match (options.should_test, options.markdown_input()) {
         (true, true) => return wrap_return(&diag, markdown::test(options)),
@@ -774,7 +770,7 @@ fn main_args(
     }
 
     // need to move these items separately because we lose them by the time the closure is called,
-    // but we can't create the Handler ahead of time because it's not Send
+    // but we can't create the dcx ahead of time because it's not Send
     let show_coverage = options.show_coverage;
     let run_check = options.run_check;
 
@@ -803,7 +799,7 @@ fn main_args(
 
         compiler.enter(|queries| {
             let mut gcx = abort_on_err(queries.global_ctxt(), sess);
-            if sess.diagnostic().has_errors_or_lint_errors().is_some() {
+            if sess.dcx().has_errors_or_lint_errors().is_some() {
                 sess.fatal("Compilation failed, aborting rustdoc");
             }
 
diff --git a/src/librustdoc/passes/check_custom_code_classes.rs b/src/librustdoc/passes/check_custom_code_classes.rs
index f246e2962fe..73f71cc062b 100644
--- a/src/librustdoc/passes/check_custom_code_classes.rs
+++ b/src/librustdoc/passes/check_custom_code_classes.rs
@@ -66,9 +66,8 @@ pub(crate) fn look_for_custom_classes<'tcx>(cx: &DocContext<'tcx>, item: &Item)
     if !tests.custom_classes_found.is_empty() {
         let span = item.attr_span(cx.tcx);
         let sess = &cx.tcx.sess.parse_sess;
-        let mut err = sess
-            .span_diagnostic
-            .struct_span_warn(span, "custom classes in code blocks will change behaviour");
+        let mut err =
+            sess.dcx.struct_span_warn(span, "custom classes in code blocks will change behaviour");
         add_feature_diagnostics_for_issue(
             &mut err,
             sess,
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index b6f73d3fdcd..df2e8584b84 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.diagnostic().has_errors_or_lint_errors().is_some() {
+    if tcx.sess.dcx().has_errors_or_lint_errors().is_some() {
         return krate;
     }
 
diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs
index b5583ae4520..ce42b9c204b 100644
--- a/src/librustdoc/passes/lint/check_code_block_syntax.rs
+++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs
@@ -3,7 +3,7 @@ use rustc_data_structures::sync::{Lock, Lrc};
 use rustc_errors::{
     emitter::Emitter,
     translation::{to_fluent_args, Translate},
-    Applicability, Diagnostic, Handler, LazyFallbackBundle,
+    Applicability, DiagCtxt, Diagnostic, LazyFallbackBundle,
 };
 use rustc_parse::parse_stream_from_source_str;
 use rustc_resolve::rustdoc::source_span_for_markdown_range;
@@ -42,9 +42,9 @@ fn check_rust_syntax(
     let emitter = BufferEmitter { buffer: Lrc::clone(&buffer), fallback_bundle };
 
     let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-    let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
+    let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings();
     let source = dox[code_block.code].to_owned();
-    let sess = ParseSess::with_span_handler(handler, sm);
+    let sess = ParseSess::with_dcx(dcx, sm);
 
     let edition = code_block.lang_string.edition.unwrap_or_else(|| cx.tcx.sess.edition());
     let expn_data =
diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs
index 14680fdb064..a343d7afcee 100644
--- a/src/librustdoc/scrape_examples.rs
+++ b/src/librustdoc/scrape_examples.rs
@@ -40,7 +40,7 @@ pub(crate) struct ScrapeExamplesOptions {
 impl ScrapeExamplesOptions {
     pub(crate) fn new(
         matches: &getopts::Matches,
-        diag: &rustc_errors::Handler,
+        dcx: &rustc_errors::DiagCtxt,
     ) -> Result<Option<Self>, i32> {
         let output_path = matches.opt_str("scrape-examples-output-path");
         let target_crates = matches.opt_strs("scrape-examples-target-crate");
@@ -52,11 +52,11 @@ impl ScrapeExamplesOptions {
                 scrape_tests,
             })),
             (Some(_), false, _) | (None, true, _) => {
-                diag.err("must use --scrape-examples-output-path and --scrape-examples-target-crate together");
+                dcx.err("must use --scrape-examples-output-path and --scrape-examples-target-crate together");
                 Err(1)
             }
             (None, false, true) => {
-                diag.err("must use --scrape-examples-output-path and --scrape-examples-target-crate with --scrape-tests");
+                dcx.err("must use --scrape-examples-output-path and --scrape-examples-target-crate with --scrape-tests");
                 Err(1)
             }
             (None, false, false) => Ok(None),
@@ -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.diagnostic().has_errors_or_lint_errors().is_some() {
+        if tcx.sess.dcx().has_errors_or_lint_errors().is_some() {
             return Err(String::from("Compilation failed, aborting rustdoc"));
         }
 
@@ -337,10 +337,11 @@ pub(crate) fn run(
     Ok(())
 }
 
-// Note: the Handler must be passed in explicitly because sess isn't available while parsing options
+// Note: the DiagCtxt must be passed in explicitly because sess isn't available while parsing
+// options.
 pub(crate) fn load_call_locations(
     with_examples: Vec<String>,
-    diag: &rustc_errors::Handler,
+    dcx: &rustc_errors::DiagCtxt,
 ) -> Result<AllCallLocations, i32> {
     let inner = || {
         let mut all_calls: AllCallLocations = FxHashMap::default();
@@ -358,7 +359,7 @@ pub(crate) fn load_call_locations(
     };
 
     inner().map_err(|e: String| {
-        diag.err(format!("failed to load examples: {e}"));
+        dcx.err(format!("failed to load examples: {e}"));
         1
     })
 }
diff --git a/src/librustdoc/theme.rs b/src/librustdoc/theme.rs
index 8c1acbd7347..98010b056c9 100644
--- a/src/librustdoc/theme.rs
+++ b/src/librustdoc/theme.rs
@@ -5,7 +5,7 @@ use std::iter::Peekable;
 use std::path::Path;
 use std::str::Chars;
 
-use rustc_errors::Handler;
+use rustc_errors::DiagCtxt;
 
 #[cfg(test)]
 mod tests;
@@ -236,7 +236,7 @@ pub(crate) fn get_differences(
 pub(crate) fn test_theme_against<P: AsRef<Path>>(
     f: &P,
     origin: &FxHashMap<String, CssPath>,
-    diag: &Handler,
+    dcx: &DiagCtxt,
 ) -> (bool, Vec<String>) {
     let against = match fs::read_to_string(f)
         .map_err(|e| e.to_string())
@@ -244,7 +244,7 @@ pub(crate) fn test_theme_against<P: AsRef<Path>>(
     {
         Ok(c) => c,
         Err(e) => {
-            diag.struct_err(e).emit();
+            dcx.struct_err(e).emit();
             return (false, vec![]);
         }
     };
diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs
index 42ff1210f23..907ea6d309c 100644
--- a/src/librustdoc/visit_ast.rs
+++ b/src/librustdoc/visit_ast.rs
@@ -163,7 +163,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
                     .iter()
                     .filter_map(|attr| {
                         Cfg::parse(attr.meta_item()?)
-                            .map_err(|e| self.cx.sess().diagnostic().span_err(e.span, e.msg))
+                            .map_err(|e| self.cx.sess().dcx().span_err(e.span, e.msg))
                             .ok()
                     })
                     .collect::<Vec<_>>()
diff --git a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
index e019523e609..c639813a3f9 100644
--- a/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/needless_doctest_main.rs
@@ -6,7 +6,7 @@ use clippy_utils::diagnostics::span_lint;
 use rustc_ast::{CoroutineKind, Fn, FnRetTy, Item, ItemKind};
 use rustc_data_structures::sync::Lrc;
 use rustc_errors::emitter::EmitterWriter;
-use rustc_errors::Handler;
+use rustc_errors::DiagCtxt;
 use rustc_lint::LateContext;
 use rustc_parse::maybe_new_parser_from_source_str;
 use rustc_parse::parser::ForceCollect;
@@ -45,10 +45,10 @@ pub fn check(
                 let fallback_bundle =
                     rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
                 let emitter = EmitterWriter::new(Box::new(io::sink()), fallback_bundle);
-                let handler = Handler::with_emitter(Box::new(emitter)).disable_warnings();
-                #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_span_handler
+                let dcx = DiagCtxt::with_emitter(Box::new(emitter)).disable_warnings();
+                #[expect(clippy::arc_with_non_send_sync)] // `Lrc` is expected by with_dcx
                 let sm = Lrc::new(SourceMap::new(FilePathMapping::empty()));
-                let sess = ParseSess::with_span_handler(handler, sm);
+                let sess = ParseSess::with_dcx(dcx, sm);
 
                 let mut parser = match maybe_new_parser_from_source_str(&sess, filename, code) {
                     Ok(p) => p,
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 49f0cad08e0..b944a299256 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -18,7 +18,7 @@ extern crate rustc_span;
 use rustc_interface::interface;
 use rustc_session::config::ErrorOutputType;
 use rustc_session::parse::ParseSess;
-use rustc_session::EarlyErrorHandler;
+use rustc_session::EarlyDiagCtxt;
 use rustc_span::symbol::Symbol;
 
 use std::env;
@@ -174,9 +174,9 @@ const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/ne
 #[allow(clippy::too_many_lines)]
 #[allow(clippy::ignored_unit_patterns)]
 pub fn main() {
-    let handler = EarlyErrorHandler::new(ErrorOutputType::default());
+    let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
-    rustc_driver::init_rustc_env_logger(&handler);
+    rustc_driver::init_rustc_env_logger(&early_dcx);
 
     let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| {
         // FIXME: this macro calls unwrap internally but is called in a panicking context!  It's not
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index 3a23ff7fe6a..865d7172cd3 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -173,7 +173,7 @@ fn parse_args() -> (OutputFormat, PathBuf) {
 
 fn main() {
     let handler =
-        rustc_session::EarlyErrorHandler::new(rustc_session::config::ErrorOutputType::default());
+        rustc_session::EarlyDiagCtxt::new(rustc_session::config::ErrorOutputType::default());
     rustc_driver::init_logger(&handler, rustc_log::LoggerConfig::from_env("RUST_LOG"));
     let (format, dst) = parse_args();
     let result = main_with_result(format, &dst);
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 8390309889d..f83847d13f1 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -35,7 +35,7 @@ use rustc_middle::{
 };
 use rustc_session::config::{CrateType, ErrorOutputType, OptLevel};
 use rustc_session::search_paths::PathKind;
-use rustc_session::{CtfeBacktrace, EarlyErrorHandler};
+use rustc_session::{CtfeBacktrace, EarlyDiagCtxt};
 
 use miri::{BacktraceStyle, BorrowTrackerMethod, ProvenanceMode, RetagFields};
 
@@ -69,8 +69,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls {
                 tcx.sess.fatal("miri cannot be run on programs that fail compilation");
             }
 
-            let handler = EarlyErrorHandler::new(tcx.sess.opts.error_format);
-            init_late_loggers(&handler, tcx);
+            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");
             }
@@ -215,7 +215,7 @@ fn rustc_logger_config() -> rustc_log::LoggerConfig {
     cfg
 }
 
-fn init_early_loggers(handler: &EarlyErrorHandler) {
+fn init_early_loggers(early_dcx: &EarlyDiagCtxt) {
     // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to
     // initialize them both, and we always initialize `miri`'s first.
     let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE");
@@ -224,15 +224,15 @@ fn init_early_loggers(handler: &EarlyErrorHandler) {
     // If it is not set, we avoid initializing now so that we can initialize later with our custom
     // settings, and *not* log anything for what happens before `miri` gets started.
     if env::var_os("RUSTC_LOG").is_some() {
-        rustc_driver::init_logger(handler, rustc_logger_config());
+        rustc_driver::init_logger(early_dcx, rustc_logger_config());
     }
 }
 
-fn init_late_loggers(handler: &EarlyErrorHandler, tcx: TyCtxt<'_>) {
+fn init_late_loggers(early_dcx: &EarlyDiagCtxt, tcx: TyCtxt<'_>) {
     // If `RUSTC_LOG` is not set, then `init_early_loggers` did not call
     // `rustc_driver::init_logger`, so we have to do this now.
     if env::var_os("RUSTC_LOG").is_none() {
-        rustc_driver::init_logger(handler, rustc_logger_config());
+        rustc_driver::init_logger(early_dcx, rustc_logger_config());
     }
 
     // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`.
@@ -300,7 +300,7 @@ fn parse_comma_list<T: FromStr>(input: &str) -> Result<Vec<T>, T::Err> {
 }
 
 fn main() {
-    let handler = EarlyErrorHandler::new(ErrorOutputType::default());
+    let early_dcx = EarlyDiagCtxt::new(ErrorOutputType::default());
 
     // Snapshot a copy of the environment before `rustc` starts messing with it.
     // (`install_ice_hook` might change `RUST_BACKTRACE`.)
@@ -311,7 +311,7 @@ fn main() {
         // Earliest rustc setup.
         let using_internal_features =
             rustc_driver::install_ice_hook(rustc_driver::DEFAULT_BUG_REPORT_URL, |_| ());
-        rustc_driver::init_rustc_env_logger(&handler);
+        rustc_driver::init_rustc_env_logger(&early_dcx);
 
         let target_crate = if crate_kind == "target" {
             true
@@ -335,7 +335,7 @@ fn main() {
         rustc_driver::install_ice_hook("https://github.com/rust-lang/miri/issues/new", |_| ());
 
     // Init loggers the Miri way.
-    init_early_loggers(&handler);
+    init_early_loggers(&early_dcx);
 
     // Parse our arguments and split them across `rustc` and `miri`.
     let mut miri_config = miri::MiriConfig::default();
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index e0f59144975..a70a9d4602e 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.diagnostic().note(
+        ecx.tcx.sess.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.diagnostic().note(
+        ecx.tcx.sess.dcx().note(
             "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace",
         );
     }
@@ -456,7 +456,7 @@ pub fn report_msg<'tcx>(
     let mut err = match diag_level {
         DiagLevel::Error => sess.struct_span_err(span, title).forget_guarantee(),
         DiagLevel::Warning => sess.struct_span_warn(span, title),
-        DiagLevel::Note => sess.diagnostic().struct_span_note(span, title),
+        DiagLevel::Note => sess.dcx().struct_span_note(span, title),
     };
 
     // Show main message.
diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs
index cbc4c90b8f9..bafef7b0f46 100644
--- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs
+++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs
@@ -67,7 +67,7 @@ fn parse_cfg_if_inner<'a>(
                 Ok(None) => continue,
                 Err(err) => {
                     err.cancel();
-                    parser.sess.span_diagnostic.reset_err_count();
+                    parser.sess.dcx.reset_err_count();
                     return Err(
                         "Expected item inside cfg_if block, but failed to parse it as an item",
                     );
diff --git a/src/tools/rustfmt/src/parse/macros/lazy_static.rs b/src/tools/rustfmt/src/parse/macros/lazy_static.rs
index a8c2feec453..8b1dc6694d6 100644
--- a/src/tools/rustfmt/src/parse/macros/lazy_static.rs
+++ b/src/tools/rustfmt/src/parse/macros/lazy_static.rs
@@ -16,8 +16,8 @@ pub(crate) fn parse_lazy_static(
         ($method:ident $(,)* $($arg:expr),* $(,)*) => {
             match parser.$method($($arg,)*) {
                 Ok(val) => {
-                    if parser.sess.span_diagnostic.has_errors().is_some() {
-                        parser.sess.span_diagnostic.reset_err_count();
+                    if parser.sess.dcx.has_errors().is_some() {
+                        parser.sess.dcx.reset_err_count();
                         return None;
                     } else {
                         val
@@ -25,7 +25,7 @@ pub(crate) fn parse_lazy_static(
                 }
                 Err(err) => {
                     err.cancel();
-                    parser.sess.span_diagnostic.reset_err_count();
+                    parser.sess.dcx.reset_err_count();
                     return None;
                 }
             }
diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs
index 7a802f7a88e..2dd2622174f 100644
--- a/src/tools/rustfmt/src/parse/macros/mod.rs
+++ b/src/tools/rustfmt/src/parse/macros/mod.rs
@@ -28,8 +28,8 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
             let mut cloned_parser = (*parser).clone();
             match $parser(&mut cloned_parser) {
                 Ok(x) => {
-                    if parser.sess.span_diagnostic.has_errors().is_some() {
-                        parser.sess.span_diagnostic.reset_err_count();
+                    if parser.sess.dcx.has_errors().is_some() {
+                        parser.sess.dcx.reset_err_count();
                     } else {
                         // Parsing succeeded.
                         *parser = cloned_parser;
@@ -38,7 +38,7 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
                 }
                 Err(e) => {
                     e.cancel();
-                    parser.sess.span_diagnostic.reset_err_count();
+                    parser.sess.dcx.reset_err_count();
                 }
             }
         };
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 06f9c4c6243..e8f7b422ada 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -4,7 +4,7 @@ use std::sync::atomic::{AtomicBool, Ordering};
 use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
 use rustc_errors::emitter::{DynEmitter, Emitter, EmitterWriter};
 use rustc_errors::translation::Translate;
-use rustc_errors::{ColorConfig, Diagnostic, Handler, Level as DiagnosticLevel};
+use rustc_errors::{ColorConfig, DiagCtxt, Diagnostic, Level as DiagnosticLevel};
 use rustc_session::parse::ParseSess as RawParseSess;
 use rustc_span::{
     source_map::{FilePathMapping, SourceMap},
@@ -118,13 +118,13 @@ impl From<Color> for ColorConfig {
     }
 }
 
-fn default_handler(
+fn default_dcx(
     source_map: Lrc<SourceMap>,
     ignore_path_set: Lrc<IgnorePathSet>,
     can_reset: Lrc<AtomicBool>,
     hide_parse_errors: bool,
     color: Color,
-) -> Handler {
+) -> DiagCtxt {
     let supports_color = term::stderr().map_or(false, |term| term.supports_color());
     let emit_color = if supports_color {
         ColorConfig::from(color)
@@ -141,7 +141,7 @@ fn default_handler(
         );
         Box::new(EmitterWriter::stderr(emit_color, fallback_bundle).sm(Some(source_map.clone())))
     };
-    Handler::with_emitter(Box::new(SilentOnIgnoredFilesEmitter {
+    DiagCtxt::with_emitter(Box::new(SilentOnIgnoredFilesEmitter {
         has_non_ignorable_parser_errors: false,
         source_map,
         emitter,
@@ -159,14 +159,14 @@ impl ParseSess {
         let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty()));
         let can_reset_errors = Lrc::new(AtomicBool::new(false));
 
-        let handler = default_handler(
+        let dcx = default_dcx(
             Lrc::clone(&source_map),
             Lrc::clone(&ignore_path_set),
             Lrc::clone(&can_reset_errors),
             config.hide_parse_errors(),
             config.color(),
         );
-        let parse_sess = RawParseSess::with_span_handler(handler, source_map);
+        let parse_sess = RawParseSess::with_dcx(dcx, source_map);
 
         Ok(ParseSess {
             parse_sess,
@@ -218,7 +218,7 @@ impl ParseSess {
     }
 
     pub(crate) fn set_silent_emitter(&mut self) {
-        self.parse_sess.span_diagnostic = Handler::with_emitter(silent_emitter());
+        self.parse_sess.dcx = DiagCtxt::with_emitter(silent_emitter());
     }
 
     pub(crate) fn span_to_filename(&self, span: Span) -> FileName {
@@ -285,7 +285,7 @@ impl ParseSess {
 impl ParseSess {
     pub(super) fn emit_diagnostics(&self, diagnostics: Vec<Diagnostic>) {
         for diagnostic in diagnostics {
-            self.parse_sess.span_diagnostic.emit_diagnostic(diagnostic);
+            self.parse_sess.dcx.emit_diagnostic(diagnostic);
         }
     }
 
@@ -294,11 +294,11 @@ impl ParseSess {
     }
 
     pub(super) fn has_errors(&self) -> bool {
-        self.parse_sess.span_diagnostic.has_errors().is_some()
+        self.parse_sess.dcx.has_errors().is_some()
     }
 
     pub(super) fn reset_errors(&self) {
-        self.parse_sess.span_diagnostic.reset_err_count();
+        self.parse_sess.dcx.reset_err_count();
     }
 }
 
diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs
index 7f545ead152..4b006151c64 100644
--- a/tests/ui-fulldeps/internal-lints/diagnostics.rs
+++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs
@@ -13,7 +13,7 @@ extern crate rustc_session;
 extern crate rustc_span;
 
 use rustc_errors::{
-    AddToDiagnostic, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, Handler,
+    AddToDiagnostic, DiagCtxt, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
     IntoDiagnostic, SubdiagnosticMessage,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
@@ -38,8 +38,8 @@ struct Note {
 pub struct UntranslatableInIntoDiagnostic;
 
 impl<'a> IntoDiagnostic<'a, ErrorGuaranteed> for UntranslatableInIntoDiagnostic {
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        handler.struct_err("untranslatable diagnostic")
+    fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        dcx.struct_err("untranslatable diagnostic")
         //~^ ERROR diagnostics should be created using translatable messages
     }
 }
@@ -47,8 +47,8 @@ impl<'a> IntoDiagnostic<'a, ErrorGuaranteed> for UntranslatableInIntoDiagnostic
 pub struct TranslatableInIntoDiagnostic;
 
 impl<'a> IntoDiagnostic<'a, ErrorGuaranteed> for TranslatableInIntoDiagnostic {
-    fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
-        handler.struct_err(crate::fluent_generated::no_crate_example)
+    fn into_diagnostic(self, dcx: &'a DiagCtxt) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        dcx.struct_err(crate::fluent_generated::no_crate_example)
     }
 }
 
@@ -75,11 +75,11 @@ impl AddToDiagnostic for TranslatableInAddToDiagnostic {
     }
 }
 
-pub fn make_diagnostics<'a>(handler: &'a Handler) {
-    let _diag = handler.struct_err(crate::fluent_generated::no_crate_example);
+pub fn make_diagnostics<'a>(dcx: &'a DiagCtxt) {
+    let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example);
     //~^ ERROR diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
 
-    let _diag = handler.struct_err("untranslatable diagnostic");
+    let _diag = dcx.struct_err("untranslatable diagnostic");
     //~^ ERROR diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
     //~^^ ERROR diagnostics should be created using translatable messages
 }
@@ -87,6 +87,6 @@ pub fn make_diagnostics<'a>(handler: &'a Handler) {
 // Check that `rustc_lint_diagnostics`-annotated functions aren't themselves linted.
 
 #[rustc_lint_diagnostics]
-pub fn skipped_because_of_annotation<'a>(handler: &'a Handler) {
-    let _diag = handler.struct_err("untranslatable diagnostic"); // okay!
+pub fn skipped_because_of_annotation<'a>(dcx: &'a DiagCtxt) {
+    let _diag = dcx.struct_err("untranslatable diagnostic"); // okay!
 }
diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.stderr b/tests/ui-fulldeps/internal-lints/diagnostics.stderr
index 8e0535e021b..d18db3cbbd3 100644
--- a/tests/ui-fulldeps/internal-lints/diagnostics.stderr
+++ b/tests/ui-fulldeps/internal-lints/diagnostics.stderr
@@ -1,8 +1,8 @@
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:42:17
+  --> $DIR/diagnostics.rs:42:13
    |
-LL |         handler.struct_err("untranslatable diagnostic")
-   |                 ^^^^^^^^^^
+LL |         dcx.struct_err("untranslatable diagnostic")
+   |             ^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/diagnostics.rs:6:9
@@ -17,10 +17,10 @@ LL |         diag.note("untranslatable diagnostic");
    |              ^^^^
 
 error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
-  --> $DIR/diagnostics.rs:79:25
+  --> $DIR/diagnostics.rs:79:21
    |
-LL |     let _diag = handler.struct_err(crate::fluent_generated::no_crate_example);
-   |                         ^^^^^^^^^^
+LL |     let _diag = dcx.struct_err(crate::fluent_generated::no_crate_example);
+   |                     ^^^^^^^^^^
    |
 note: the lint level is defined here
   --> $DIR/diagnostics.rs:7:9
@@ -29,16 +29,16 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
-  --> $DIR/diagnostics.rs:82:25
+  --> $DIR/diagnostics.rs:82:21
    |
-LL |     let _diag = handler.struct_err("untranslatable diagnostic");
-   |                         ^^^^^^^^^^
+LL |     let _diag = dcx.struct_err("untranslatable diagnostic");
+   |                     ^^^^^^^^^^
 
 error: diagnostics should be created using translatable messages
-  --> $DIR/diagnostics.rs:82:25
+  --> $DIR/diagnostics.rs:82:21
    |
-LL |     let _diag = handler.struct_err("untranslatable diagnostic");
-   |                         ^^^^^^^^^^
+LL |     let _diag = dcx.struct_err("untranslatable diagnostic");
+   |                     ^^^^^^^^^^
 
 error: aborting due to 5 previous errors