about summary refs log tree commit diff
path: root/compiler/rustc_hir_analysis/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_hir_analysis/src')
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs55
-rw-r--r--compiler/rustc_hir_analysis/src/check/cast.rs77
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs18
-rw-r--r--compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs17
-rw-r--r--compiler/rustc_hir_analysis/src/check/generator_interior.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/prelude2021.rs112
-rw-r--r--compiler/rustc_hir_analysis/src/check/method/probe.rs25
-rw-r--r--compiler/rustc_hir_analysis/src/check/pat.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/check/upvar.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/check_unused.rs20
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs23
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs5
15 files changed, 219 insertions, 209 deletions
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index afac75de2d9..5752b6a356d 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -649,9 +649,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     LATE_BOUND_LIFETIME_ARGUMENTS,
                     args.args[0].hir_id(),
                     multispan,
-                    |lint| {
-                        lint.build(msg).emit();
-                    },
+                    msg,
+                    |lint| lint,
                 );
             }
 
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 244018ebbeb..cf65bc19a5c 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2015,30 +2015,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         tcx.check_stability(item.def_id, Some(hir_ref_id), span, None);
 
         if let Some(variant_def_id) = variant_resolution {
-            tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| {
-                let mut err = lint.build("ambiguous associated item");
-                let mut could_refer_to = |kind: DefKind, def_id, also| {
-                    let note_msg = format!(
-                        "`{}` could{} refer to the {} defined here",
-                        assoc_ident,
-                        also,
-                        kind.descr(def_id)
-                    );
-                    err.span_note(tcx.def_span(def_id), &note_msg);
-                };
+            tcx.struct_span_lint_hir(
+                AMBIGUOUS_ASSOCIATED_ITEMS,
+                hir_ref_id,
+                span,
+                "ambiguous associated item",
+                |lint| {
+                    let mut could_refer_to = |kind: DefKind, def_id, also| {
+                        let note_msg = format!(
+                            "`{}` could{} refer to the {} defined here",
+                            assoc_ident,
+                            also,
+                            kind.descr(def_id)
+                        );
+                        lint.span_note(tcx.def_span(def_id), &note_msg);
+                    };
 
-                could_refer_to(DefKind::Variant, variant_def_id, "");
-                could_refer_to(kind, item.def_id, " also");
+                    could_refer_to(DefKind::Variant, variant_def_id, "");
+                    could_refer_to(kind, item.def_id, " also");
 
-                err.span_suggestion(
-                    span,
-                    "use fully-qualified syntax",
-                    format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
-                    Applicability::MachineApplicable,
-                );
+                    lint.span_suggestion(
+                        span,
+                        "use fully-qualified syntax",
+                        format!("<{} as {}>::{}", qself_ty, tcx.item_name(trait_did), assoc_ident),
+                        Applicability::MachineApplicable,
+                    );
 
-                err.emit();
-            });
+                    lint
+                },
+            );
         }
         Ok((ty, kind, item.def_id))
     }
@@ -3084,15 +3089,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                     BARE_TRAIT_OBJECTS,
                     self_ty.hir_id,
                     self_ty.span,
+                    msg,
                     |lint| {
-                        let mut diag = lint.build(msg);
-                        diag.multipart_suggestion_verbose(
+                        lint.multipart_suggestion_verbose(
                             "use `dyn`",
                             sugg,
                             Applicability::MachineApplicable,
                         );
-                        self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
-                        diag.emit();
+                        self.maybe_lint_blanket_trait_impl(&self_ty, lint);
+                        lint
                     },
                 );
             }
diff --git a/compiler/rustc_hir_analysis/src/check/cast.rs b/compiler/rustc_hir_analysis/src/check/cast.rs
index 81a979865ac..01badc133c9 100644
--- a/compiler/rustc_hir_analysis/src/check/cast.rs
+++ b/compiler/rustc_hir_analysis/src/check/cast.rs
@@ -33,7 +33,7 @@ use super::FnCtxt;
 use crate::hir::def_id::DefId;
 use crate::type_error_struct;
 use hir::def_id::LOCAL_CRATE;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode};
 use rustc_middle::mir::Mutability;
@@ -754,19 +754,25 @@ impl<'a, 'tcx> CastCheck<'tcx> {
         } else {
             ("", lint::builtin::TRIVIAL_CASTS)
         };
-        fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.span, |err| {
-            err.build(&format!(
-                "trivial {}cast: `{}` as `{}`",
-                adjective,
-                fcx.ty_to_string(t_expr),
-                fcx.ty_to_string(t_cast)
-            ))
-            .help(&format!(
-                "cast can be replaced by coercion; this might \
-                                   require {type_asc_or}a temporary variable"
-            ))
-            .emit();
-        });
+        fcx.tcx.struct_span_lint_hir(
+            lint,
+            self.expr.hir_id,
+            self.span,
+            DelayDm(|| {
+                format!(
+                    "trivial {}cast: `{}` as `{}`",
+                    adjective,
+                    fcx.ty_to_string(t_expr),
+                    fcx.ty_to_string(t_cast)
+                )
+            }),
+            |lint| {
+                lint.help(format!(
+                    "cast can be replaced by coercion; this might \
+                     require {type_asc_or}a temporary variable"
+                ))
+            },
+        );
     }
 
     #[instrument(skip(fcx), level = "debug")]
@@ -1074,12 +1080,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 lint::builtin::CENUM_IMPL_DROP_CAST,
                 self.expr.hir_id,
                 self.span,
-                |err| {
-                    err.build(&format!(
-                        "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
-                        self.expr_ty, self.cast_ty
-                    ))
-                    .emit();
+                DelayDm(|| format!(
+                    "cannot cast enum `{}` into integer `{}` because it implements `Drop`",
+                    self.expr_ty, self.cast_ty
+                )),
+                |lint| {
+                    lint
                 },
             );
         }
@@ -1090,12 +1096,11 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             lint::builtin::LOSSY_PROVENANCE_CASTS,
             self.expr.hir_id,
             self.span,
-            |err| {
-                let mut err = err.build(&format!(
+            DelayDm(|| format!(
                     "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`",
                     self.expr_ty, self.cast_ty
-                ));
-
+                )),
+            |lint| {
                 let msg = "use `.addr()` to obtain the address of a pointer";
 
                 let expr_prec = self.expr.precedence().order();
@@ -1114,9 +1119,9 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         (cast_span, format!(").addr(){scalar_cast}")),
                     ];
 
-                    err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
+                    lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
                 } else {
-                    err.span_suggestion(
+                    lint.span_suggestion(
                         cast_span,
                         msg,
                         format!(".addr(){scalar_cast}"),
@@ -1124,12 +1129,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                     );
                 }
 
-                err.help(
+                lint.help(
                     "if you can't comply with strict provenance and need to expose the pointer \
                     provenance you can use `.expose_addr()` instead"
                 );
 
-                err.emit();
+                lint
             },
         );
     }
@@ -1139,24 +1144,24 @@ impl<'a, 'tcx> CastCheck<'tcx> {
             lint::builtin::FUZZY_PROVENANCE_CASTS,
             self.expr.hir_id,
             self.span,
-            |err| {
-                let mut err = err.build(&format!(
-                    "strict provenance disallows casting integer `{}` to pointer `{}`",
-                    self.expr_ty, self.cast_ty
-                ));
+            DelayDm(|| format!(
+                "strict provenance disallows casting integer `{}` to pointer `{}`",
+                self.expr_ty, self.cast_ty
+            )),
+            |lint| {
                 let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address";
                 let suggestions = vec![
                     (self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")),
                     (self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")),
                 ];
 
-                err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
-                err.help(
+                lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect);
+                lint.help(
                     "if you can't comply with strict provenance and don't have a pointer with \
                     the correct provenance you can use `std::ptr::from_exposed_addr()` instead"
                  );
 
-                err.emit();
+                lint
             },
         );
     }
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index d82ee8f48c5..60a4904373e 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -48,9 +48,13 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab
             .emit();
         }
         None => {
-            tcx.struct_span_lint_hir(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| {
-                lint.build("use of calling convention not supported on this target").emit();
-            });
+            tcx.struct_span_lint_hir(
+                UNSUPPORTED_CALLING_CONVENTIONS,
+                hir_id,
+                span,
+                "use of calling convention not supported on this target",
+                |lint| lint,
+            );
         }
     }
 
@@ -510,10 +514,10 @@ fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
             UNINHABITED_STATIC,
             tcx.hir().local_def_id_to_hir_id(def_id),
             span,
+            "static of uninhabited type",
             |lint| {
-                lint.build("static of uninhabited type")
+                lint
                 .note("uninhabited statics cannot be initialized, and any access would be an immediate error")
-                .emit();
             },
         );
     }
@@ -1434,6 +1438,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
                 REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
                 tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
                 span,
+                "zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types",
                 |lint| {
                     let note = if non_exhaustive {
                         "is marked with `#[non_exhaustive]`"
@@ -1441,10 +1446,9 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
                         "contains private fields"
                     };
                     let field_ty = tcx.def_path_str_with_substs(def_id, substs);
-                    lint.build("zero-sized fields in repr(transparent) cannot contain external non-exhaustive types")
+                    lint
                         .note(format!("this {descr} contains `{field_ty}`, which {note}, \
                             and makes it not a breaking change to become non-zero-sized in the future."))
-                        .emit();
                 },
             )
         }
diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
index 4522678802b..4bd5e9f6ab5 100644
--- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
@@ -58,17 +58,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind);
 
-                self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| {
-                    let msg = format!("unreachable {}", kind);
-                    lint.build(&msg)
-                        .span_label(span, &msg)
-                        .span_label(
+                let msg = format!("unreachable {}", kind);
+                self.tcx().struct_span_lint_hir(
+                    lint::builtin::UNREACHABLE_CODE,
+                    id,
+                    span,
+                    &msg,
+                    |lint| {
+                        lint.span_label(span, &msg).span_label(
                             orig_span,
                             custom_note
                                 .unwrap_or("any code following this expression is unreachable"),
                         )
-                        .emit();
-                })
+                    },
+                )
             }
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior.rs b/compiler/rustc_hir_analysis/src/check/generator_interior.rs
index 254a19368bf..898419b5b23 100644
--- a/compiler/rustc_hir_analysis/src/check/generator_interior.rs
+++ b/compiler/rustc_hir_analysis/src/check/generator_interior.rs
@@ -6,7 +6,7 @@
 use self::drop_ranges::DropRanges;
 use super::FnCtxt;
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_errors::pluralize;
+use rustc_errors::{pluralize, DelayDm};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::DefId;
@@ -610,33 +610,33 @@ fn check_must_not_suspend_def(
             rustc_session::lint::builtin::MUST_NOT_SUSPEND,
             hir_id,
             data.source_span,
-            |lint| {
-                let msg = format!(
+            DelayDm(|| {
+                format!(
                     "{}`{}`{} held across a suspend point, but should not be",
                     data.descr_pre,
                     tcx.def_path_str(def_id),
                     data.descr_post,
-                );
-                let mut err = lint.build(&msg);
-
+                )
+            }),
+            |lint| {
                 // add span pointing to the offending yield/await
-                err.span_label(data.yield_span, "the value is held across this suspend point");
+                lint.span_label(data.yield_span, "the value is held across this suspend point");
 
                 // Add optional reason note
                 if let Some(note) = attr.value_str() {
                     // FIXME(guswynn): consider formatting this better
-                    err.span_note(data.source_span, note.as_str());
+                    lint.span_note(data.source_span, note.as_str());
                 }
 
                 // Add some quick suggestions on what to do
                 // FIXME: can `drop` work as a suggestion here as well?
-                err.span_help(
+                lint.span_help(
                     data.source_span,
                     "consider using a block (`{ ... }`) \
                     to shrink the value's scope, ending before the suspend point",
                 );
 
-                err.emit();
+                lint
             },
         );
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index d8fe63dbf08..c604c8af8d2 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -328,17 +328,16 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
                     lint::builtin::ASM_SUB_REGISTER,
                     expr.hir_id,
                     spans,
+                    "formatting may not be suitable for sub-register argument",
                     |lint| {
-                        let msg = "formatting may not be suitable for sub-register argument";
-                        let mut err = lint.build(msg);
-                        err.span_label(expr.span, "for this argument");
-                        err.help(&format!(
+                        lint.span_label(expr.span, "for this argument");
+                        lint.help(&format!(
                             "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`",
                         ));
-                        err.help(&format!(
+                        lint.help(&format!(
                             "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`",
                         ));
-                        err.emit();
+                        lint
                     },
                 );
             }
diff --git a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs b/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
index 392695cca68..ca4cdf5a0d0 100644
--- a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
@@ -82,14 +82,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 prelude_or_array_lint,
                 self_expr.hir_id,
                 self_expr.span,
+                format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
                 |lint| {
                     let sp = self_expr.span;
 
-                    let mut lint = lint.build(&format!(
-                        "trait method `{}` will become ambiguous in Rust 2021",
-                        segment.ident.name
-                    ));
-
                     let derefs = "*".repeat(pick.autoderefs);
 
                     let autoref = match pick.autoref_or_ptr_adjustment {
@@ -133,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         );
                     }
 
-                    lint.emit();
+                    lint
                 },
             );
         } else {
@@ -143,6 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 prelude_or_array_lint,
                 call_expr.hir_id,
                 call_expr.span,
+                format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
                 |lint| {
                     let sp = call_expr.span;
                     let trait_name = self.trait_path_or_bare_name(
@@ -151,11 +148,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         pick.item.container_id(self.tcx),
                     );
 
-                    let mut lint = lint.build(&format!(
-                        "trait method `{}` will become ambiguous in Rust 2021",
-                        segment.ident.name
-                    ));
-
                     let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp);
                     if precise {
                         let args = args
@@ -202,7 +194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         );
                     }
 
-                    lint.emit();
+                    lint
                 },
             );
         }
@@ -257,15 +249,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return;
         }
 
-        self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| {
-            // "type" refers to either a type or, more likely, a trait from which
-            // the associated function or method is from.
-            let container_id = pick.item.container_id(self.tcx);
-            let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
-            let trait_generics = self.tcx.generics_of(container_id);
-
-            let trait_name =
-                if trait_generics.params.len() <= trait_generics.has_self as usize {
+        self.tcx.struct_span_lint_hir(
+            RUST_2021_PRELUDE_COLLISIONS,
+            expr_id,
+            span,
+            format!(
+                "trait-associated function `{}` will become ambiguous in Rust 2021",
+                method_name.name
+            ),
+            |lint| {
+                // "type" refers to either a type or, more likely, a trait from which
+                // the associated function or method is from.
+                let container_id = pick.item.container_id(self.tcx);
+                let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
+                let trait_generics = self.tcx.generics_of(container_id);
+
+                let trait_name = if trait_generics.params.len() <= trait_generics.has_self as usize
+                {
                     trait_path
                 } else {
                     let counts = trait_generics.own_counts();
@@ -282,44 +282,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     )
                 };
 
-            let mut lint = lint.build(&format!(
-                "trait-associated function `{}` will become ambiguous in Rust 2021",
-                method_name.name
-            ));
-
-            let mut self_ty_name = self_ty_span
-                .find_ancestor_inside(span)
-                .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
-                .unwrap_or_else(|| self_ty.to_string());
-
-            // Get the number of generics the self type has (if an Adt) unless we can determine that
-            // the user has written the self type with generics already which we (naively) do by looking
-            // for a "<" in `self_ty_name`.
-            if !self_ty_name.contains('<') {
-                if let Adt(def, _) = self_ty.kind() {
-                    let generics = self.tcx.generics_of(def.did());
-                    if !generics.params.is_empty() {
-                        let counts = generics.own_counts();
-                        self_ty_name += &format!(
-                            "<{}>",
-                            std::iter::repeat("'_")
-                                .take(counts.lifetimes)
-                                .chain(std::iter::repeat("_").take(counts.types + counts.consts))
-                                .collect::<Vec<_>>()
-                                .join(", ")
-                        );
+                let mut self_ty_name = self_ty_span
+                    .find_ancestor_inside(span)
+                    .and_then(|span| self.sess().source_map().span_to_snippet(span).ok())
+                    .unwrap_or_else(|| self_ty.to_string());
+
+                // Get the number of generics the self type has (if an Adt) unless we can determine that
+                // the user has written the self type with generics already which we (naively) do by looking
+                // for a "<" in `self_ty_name`.
+                if !self_ty_name.contains('<') {
+                    if let Adt(def, _) = self_ty.kind() {
+                        let generics = self.tcx.generics_of(def.did());
+                        if !generics.params.is_empty() {
+                            let counts = generics.own_counts();
+                            self_ty_name += &format!(
+                                "<{}>",
+                                std::iter::repeat("'_")
+                                    .take(counts.lifetimes)
+                                    .chain(
+                                        std::iter::repeat("_").take(counts.types + counts.consts)
+                                    )
+                                    .collect::<Vec<_>>()
+                                    .join(", ")
+                            );
+                        }
                     }
                 }
-            }
-            lint.span_suggestion(
-                span,
-                "disambiguate the associated function",
-                format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
-                Applicability::MachineApplicable,
-            );
-
-            lint.emit();
-        });
+                lint.span_suggestion(
+                    span,
+                    "disambiguate the associated function",
+                    format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,),
+                    Applicability::MachineApplicable,
+                );
+
+                lint
+            },
+        );
     }
 
     fn trait_path_or_bare_name(
diff --git a/compiler/rustc_hir_analysis/src/check/method/probe.rs b/compiler/rustc_hir_analysis/src/check/method/probe.rs
index 6cd7ced01a3..a761a93dea4 100644
--- a/compiler/rustc_hir_analysis/src/check/method/probe.rs
+++ b/compiler/rustc_hir_analysis/src/check/method/probe.rs
@@ -409,9 +409,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         lint::builtin::TYVAR_BEHIND_RAW_POINTER,
                         scope_expr_id,
                         span,
-                        |lint| {
-                            lint.build("type annotations needed").emit();
-                        },
+                        "type annotations needed",
+                        |lint| lint,
                     );
                 }
             } else {
@@ -1358,24 +1357,24 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
         stable_pick: &Pick<'_>,
         unstable_candidates: &[(Candidate<'tcx>, Symbol)],
     ) {
+        let def_kind = stable_pick.item.kind.as_def_kind();
         self.tcx.struct_span_lint_hir(
             lint::builtin::UNSTABLE_NAME_COLLISIONS,
             self.scope_expr_id,
             self.span,
+            format!(
+                "{} {} with this name may be added to the standard library in the future",
+                def_kind.article(),
+                def_kind.descr(stable_pick.item.def_id),
+            ),
             |lint| {
-                let def_kind = stable_pick.item.kind.as_def_kind();
-                let mut diag = lint.build(&format!(
-                    "{} {} with this name may be added to the standard library in the future",
-                    def_kind.article(),
-                    def_kind.descr(stable_pick.item.def_id),
-                ));
                 match (stable_pick.item.kind, stable_pick.item.container) {
                     (ty::AssocKind::Fn, _) => {
                         // FIXME: This should be a `span_suggestion` instead of `help`
                         // However `self.span` only
                         // highlights the method name, so we can't use it. Also consider reusing
                         // the code from `report_method_error()`.
-                        diag.help(&format!(
+                        lint.help(&format!(
                             "call with fully qualified syntax `{}(...)` to keep using the current \
                              method",
                             self.tcx.def_path_str(stable_pick.item.def_id),
@@ -1383,7 +1382,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     }
                     (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => {
                         let def_id = stable_pick.item.container_id(self.tcx);
-                        diag.span_suggestion(
+                        lint.span_suggestion(
                             self.span,
                             "use the fully qualified path to the associated const",
                             format!(
@@ -1399,7 +1398,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                 }
                 if self.tcx.sess.is_nightly_build() {
                     for (candidate, feature) in unstable_candidates {
-                        diag.help(&format!(
+                        lint.help(&format!(
                             "add `#![feature({})]` to the crate attributes to enable `{}`",
                             feature,
                             self.tcx.def_path_str(candidate.item.def_id),
@@ -1407,7 +1406,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
                     }
                 }
 
-                diag.emit();
+                lint
             },
         );
     }
diff --git a/compiler/rustc_hir_analysis/src/check/pat.rs b/compiler/rustc_hir_analysis/src/check/pat.rs
index 8906b622b68..178326cfdc4 100644
--- a/compiler/rustc_hir_analysis/src/check/pat.rs
+++ b/compiler/rustc_hir_analysis/src/check/pat.rs
@@ -1790,10 +1790,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(),
         );
 
-        self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |build| {
-        let mut lint = build.build("some fields are not explicitly listed");
+        self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| {
         lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns));
-
         lint.help(
             "ensure that all fields are mentioned explicitly by adding the suggested fields",
         );
@@ -1801,7 +1799,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             "the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
             ty,
         ));
-        lint.emit();
+
+        lint
     });
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/upvar.rs b/compiler/rustc_hir_analysis/src/check/upvar.rs
index 0b207a6c0be..4f495641691 100644
--- a/compiler/rustc_hir_analysis/src/check/upvar.rs
+++ b/compiler/rustc_hir_analysis/src/check/upvar.rs
@@ -749,10 +749,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
                 closure_hir_id,
                 closure_head_span,
+                reasons.migration_message(),
                 |lint| {
-                    let mut diagnostics_builder = lint.build(
-                        &reasons.migration_message(),
-                    );
                     for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations {
                         // Labels all the usage of the captured variable and why they are responsible
                         // for migration being needed
@@ -760,13 +758,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             match &lint_note.captures_info {
                                 UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => {
                                     let cause_span = self.tcx.hir().span(*capture_expr_id);
-                                    diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
+                                    lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`",
                                         self.tcx.hir().name(*var_hir_id),
                                         captured_name,
                                     ));
                                 }
                                 UpvarMigrationInfo::CapturingNothing { use_span } => {
-                                    diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
+                                    lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect",
                                         self.tcx.hir().name(*var_hir_id),
                                     ));
                                 }
@@ -781,13 +779,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                                 match &lint_note.captures_info {
                                     UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
-                                        diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
+                                        lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure",
                                             self.tcx.hir().name(*var_hir_id),
                                             captured_name,
                                         ));
                                     }
                                     UpvarMigrationInfo::CapturingNothing { use_span: _ } => {
-                                        diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
+                                        lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure",
                                             v = self.tcx.hir().name(*var_hir_id),
                                         ));
                                     }
@@ -800,7 +798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 match &lint_note.captures_info {
                                     UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => {
                                         let var_name = self.tcx.hir().name(*var_hir_id);
-                                        diagnostics_builder.span_label(closure_head_span, format!("\
+                                        lint.span_label(closure_head_span, format!("\
                                         in Rust 2018, this closure implements {missing_trait} \
                                         as `{var_name}` implements {missing_trait}, but in Rust 2021, \
                                         this closure will no longer implement {missing_trait} \
@@ -814,7 +812,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             }
                         }
                     }
-                    diagnostics_builder.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
+                    lint.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>");
 
                     let diagnostic_msg = format!(
                         "add a dummy let to cause {} to be fully captured",
@@ -857,7 +855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // We take the indentation from the next non-empty line.
                             let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default();
                             let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0;
-                            diagnostics_builder.span_suggestion(
+                            lint.span_suggestion(
                                 closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
                                 &diagnostic_msg,
                                 format!("\n{indent}{migration_string};"),
@@ -868,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             // braces, but with more than just the opening
                             // brace on the first line. We put the `let`
                             // directly after the `{`.
-                            diagnostics_builder.span_suggestion(
+                            lint.span_suggestion(
                                 closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(),
                                 &diagnostic_msg,
                                 format!(" {migration_string};"),
@@ -877,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         } else {
                             // This is a closure without braces around the body.
                             // We add braces to add the `let` before the body.
-                            diagnostics_builder.multipart_suggestion(
+                            lint.multipart_suggestion(
                                 &diagnostic_msg,
                                 vec![
                                     (closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")),
@@ -887,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             );
                         }
                     } else {
-                        diagnostics_builder.span_suggestion(
+                        lint.span_suggestion(
                             closure_span,
                             &diagnostic_msg,
                             migration_string,
@@ -895,7 +893,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         );
                     }
 
-                    diagnostics_builder.emit();
+                    lint
                 },
             );
         }
diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs
index 1d23ed92921..922833f8580 100644
--- a/compiler/rustc_hir_analysis/src/check_unused.rs
+++ b/compiler/rustc_hir_analysis/src/check_unused.rs
@@ -29,14 +29,18 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
             continue;
         }
         let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() };
-        tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| {
-            let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
-                format!("unused import: `{}`", snippet)
-            } else {
-                "unused import".to_owned()
-            };
-            lint.build(&msg).emit();
-        });
+        let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) {
+            format!("unused import: `{}`", snippet)
+        } else {
+            "unused import".to_owned()
+        };
+        tcx.struct_span_lint_hir(
+            lint::builtin::UNUSED_IMPORTS,
+            item.hir_id(),
+            path.span,
+            msg,
+            |lint| lint,
+        );
     }
 
     unused_crates_lint(tcx);
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 7d15e5a7f3c..1307f74f210 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -2,7 +2,7 @@
 //! crate or pertains to a type defined in this crate.
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
+use rustc_errors::{struct_span_err, DelayDm};
 use rustc_errors::{Diagnostic, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_middle::ty::subst::GenericArgKind;
@@ -412,30 +412,31 @@ fn lint_auto_trait_impl<'tcx>(
         lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS,
         tcx.hir().local_def_id_to_hir_id(impl_def_id),
         tcx.def_span(impl_def_id),
-        |err| {
-            let item_span = tcx.def_span(self_type_did);
-            let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
-            let mut err = err.build(&format!(
+        DelayDm(|| {
+            format!(
                 "cross-crate traits with a default impl, like `{}`, \
                          should not be specialized",
                 tcx.def_path_str(trait_ref.def_id),
-            ));
+            )
+        }),
+        |lint| {
+            let item_span = tcx.def_span(self_type_did);
+            let self_descr = tcx.def_kind(self_type_did).descr(self_type_did);
             match arg {
                 ty::util::NotUniqueParam::DuplicateParam(arg) => {
-                    err.note(&format!("`{}` is mentioned multiple times", arg));
+                    lint.note(&format!("`{}` is mentioned multiple times", arg));
                 }
                 ty::util::NotUniqueParam::NotParam(arg) => {
-                    err.note(&format!("`{}` is not a generic parameter", arg));
+                    lint.note(&format!("`{}` is not a generic parameter", arg));
                 }
             }
-            err.span_note(
+            lint.span_note(
                 item_span,
                 &format!(
                     "try using the same sequence of generic parameters as the {} definition",
                     self_descr,
                 ),
-            );
-            err.emit();
+            )
         },
     );
 }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 8cd0a84274e..ab4b861b6cb 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -2067,11 +2067,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs {
                     lint::builtin::INLINE_NO_SANITIZE,
                     hir_id,
                     no_sanitize_span,
-                    |lint| {
-                        lint.build("`no_sanitize` will have no effect after inlining")
-                            .span_note(inline_span, "inlining requested here")
-                            .emit();
-                    },
+                    "`no_sanitize` will have no effect after inlining",
+                    |lint| lint.span_note(inline_span, "inlining requested here"),
                 )
             }
         }
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 1deff17e840..7ffacbecf5f 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -266,9 +266,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
                             lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
                             param.hir_id,
                             param.span,
-                            |lint| {
-                                lint.build(TYPE_DEFAULT_NOT_ALLOWED).emit();
-                            },
+                            TYPE_DEFAULT_NOT_ALLOWED,
+                            |lint| lint,
                         );
                     }
                     Defaults::Deny => {