]> git.lizzy.rs Git - rust.git/commitdiff
Refactor rustc lint API
authorMaybe Waffle <waffle.lapkin@gmail.com>
Fri, 16 Sep 2022 07:01:02 +0000 (11:01 +0400)
committerMaybe Waffle <waffle.lapkin@gmail.com>
Sat, 1 Oct 2022 10:03:06 +0000 (10:03 +0000)
64 files changed:
compiler/rustc_const_eval/src/const_eval/error.rs
compiler/rustc_error_messages/src/lib.rs
compiler/rustc_errors/src/diagnostic.rs
compiler/rustc_errors/src/lib.rs
compiler/rustc_hir_analysis/src/astconv/generics.rs
compiler/rustc_hir_analysis/src/astconv/mod.rs
compiler/rustc_hir_analysis/src/check/cast.rs
compiler/rustc_hir_analysis/src/check/check.rs
compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs
compiler/rustc_hir_analysis/src/check/generator_interior.rs
compiler/rustc_hir_analysis/src/check/intrinsicck.rs
compiler/rustc_hir_analysis/src/check/method/prelude2021.rs
compiler/rustc_hir_analysis/src/check/method/probe.rs
compiler/rustc_hir_analysis/src/check/pat.rs
compiler/rustc_hir_analysis/src/check/upvar.rs
compiler/rustc_hir_analysis/src/check_unused.rs
compiler/rustc_hir_analysis/src/coherence/orphan.rs
compiler/rustc_hir_analysis/src/collect.rs
compiler/rustc_hir_analysis/src/collect/generics_of.rs
compiler/rustc_lint/src/array_into_iter.rs
compiler/rustc_lint/src/builtin.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/early.rs
compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
compiler/rustc_lint/src/expect.rs
compiler/rustc_lint/src/hidden_unicode_codepoints.rs
compiler/rustc_lint/src/internal.rs
compiler/rustc_lint/src/let_underscore.rs
compiler/rustc_lint/src/levels.rs
compiler/rustc_lint/src/methods.rs
compiler/rustc_lint/src/non_ascii_idents.rs
compiler/rustc_lint/src/non_fmt_panic.rs
compiler/rustc_lint/src/nonstandard_style.rs
compiler/rustc_lint/src/noop_method_call.rs
compiler/rustc_lint/src/pass_by_value.rs
compiler/rustc_lint/src/redundant_semicolon.rs
compiler/rustc_lint/src/traits.rs
compiler/rustc_lint/src/types.rs
compiler/rustc_lint/src/unused.rs
compiler/rustc_macros/src/diagnostics/diagnostic.rs
compiler/rustc_middle/src/lint.rs
compiler/rustc_middle/src/middle/stability.rs
compiler/rustc_middle/src/ty/context.rs
compiler/rustc_mir_build/src/check_unsafety.rs
compiler/rustc_mir_build/src/lints.rs
compiler/rustc_mir_build/src/thir/pattern/check_match.rs
compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
compiler/rustc_mir_transform/src/check_const_item_mutation.rs
compiler/rustc_mir_transform/src/check_packed_ref.rs
compiler/rustc_mir_transform/src/check_unsafety.rs
compiler/rustc_mir_transform/src/const_prop_lint.rs
compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
compiler/rustc_mir_transform/src/function_item_references.rs
compiler/rustc_passes/src/check_attr.rs
compiler/rustc_passes/src/dead.rs
compiler/rustc_passes/src/liveness.rs
compiler/rustc_passes/src/naked_functions.rs
compiler/rustc_passes/src/stability.rs
compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
compiler/rustc_trait_selection/src/traits/specialize/mod.rs

index 09d53331b5b269310fc29249887f64f2e28de83d..09c92ae03619dcbb2195239edee7790af946b165 100644 (file)
@@ -233,10 +233,10 @@ fn struct_generic(
                 rustc_session::lint::builtin::CONST_ERR,
                 hir_id,
                 tcx.span,
+                message,
                 |lint| {
-                    let mut lint = lint.build(message);
-                    finish(&mut lint, Some(err_msg));
-                    lint.emit();
+                    finish(lint, Some(err_msg));
+                    lint
                 },
             );
             ErrorHandled::Linted
index ff33ae7e8f224edd0971202b11807c08a75422cf..fb7f89d7a28c0f8551f257564127991a275dbe3b 100644 (file)
@@ -357,6 +357,17 @@ fn from(s: S) -> Self {
     }
 }
 
+/// A workaround for "good path" ICEs when formatting types in disables lints.
+///
+/// Delays formatting until `.into(): DiagnosticMessage` is used.
+pub struct DelayDm<F>(pub F);
+
+impl<F: FnOnce() -> String> From<DelayDm<F>> for DiagnosticMessage {
+    fn from(DelayDm(f): DelayDm<F>) -> Self {
+        DiagnosticMessage::from(f())
+    }
+}
+
 /// Translating *into* a subdiagnostic message from a diagnostic message is a little strange - but
 /// the subdiagnostic functions (e.g. `span_label`) take a `SubdiagnosticMessage` and the
 /// subdiagnostic derive refers to typed identifiers that are `DiagnosticMessage`s, so need to be
index 5520e22e4767c720b8b3eb63dd28d2e2b7ac87fb..49dcc2ba021e4f94f01e6dd96a5f90599717c58c 100644 (file)
@@ -1,6 +1,6 @@
 use crate::snippet::Style;
 use crate::{
-    CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, MultiSpan,
+    CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, MultiSpan,
     SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
 };
 use rustc_ast as ast;
@@ -209,7 +209,12 @@ pub trait AddToDiagnostic {
 #[rustc_diagnostic_item = "DecorateLint"]
 pub trait DecorateLint<'a, G: EmissionGuarantee> {
     /// Decorate and emit a lint.
-    fn decorate_lint(self, diag: LintDiagnosticBuilder<'a, G>);
+    fn decorate_lint<'b>(
+        self,
+        diag: &'b mut DiagnosticBuilder<'a, G>,
+    ) -> &'b mut DiagnosticBuilder<'a, G>;
+
+    fn msg(&self) -> DiagnosticMessage;
 }
 
 #[must_use]
index d3effb7c1c0f4b914f45237930e5adcb13bc77db..c9f912fa7aab7a626b4650f1cf544410d0cf0ec3 100644 (file)
@@ -30,7 +30,7 @@
 use rustc_data_structures::sync::{self, Lock, Lrc};
 use rustc_data_structures::AtomicRef;
 pub use rustc_error_messages::{
-    fallback_fluent_bundle, fluent, fluent_bundle, DiagnosticMessage, FluentBundle,
+    fallback_fluent_bundle, fluent, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle,
     LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage,
     DEFAULT_LOCALE_RESOURCES,
 };
index afac75de2d96d8e831fab717695e89e896938bd7..5752b6a356de3315e0c2c27bda1f59183bf599b3 100644 (file)
@@ -649,9 +649,8 @@ pub(crate) fn prohibit_explicit_late_bound_lifetimes(
                     LATE_BOUND_LIFETIME_ARGUMENTS,
                     args.args[0].hir_id(),
                     multispan,
-                    |lint| {
-                        lint.build(msg).emit();
-                    },
+                    msg,
+                    |lint| lint,
                 );
             }
 
index 244018ebbeb7434cd6681b01319ca30a3f9c94ce..cf65bc19a5c83208f171039a7c8d2030a4d0d3fd 100644 (file)
@@ -2015,30 +2015,35 @@ pub fn associated_path_to_ty(
         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 @@ fn maybe_lint_bare_trait(&self, self_ty: &hir::Ty<'_>, in_path: bool) {
                     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
                     },
                 );
             }
index 81a979865acc3bef7e38809da9397e043c55c4a9..01badc133c918cb1a019d26a1325eb99ccee1c0c 100644 (file)
@@ -33,7 +33,7 @@
 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 @@ fn trivial_cast_lint(&self, fcx: &FnCtxt<'a, '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 @@ fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, '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 @@ fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::I
             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 @@ fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::I
                         (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 @@ fn lossy_provenance_ptr2int_lint(&self, fcx: &FnCtxt<'a, 'tcx>, t_c: ty::cast::I
                     );
                 }
 
-                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 @@ fn fuzzy_provenance_int2ptr_lint(&self, fcx: &FnCtxt<'a, '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
             },
         );
     }
index d82ee8f48c52bf790eccf82cb926e4f9af581ace..60a4904373e965dbf031c17a5378fee3801ed16f 100644 (file)
@@ -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 @@ fn check_non_exhaustive<'tcx>(
                 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 @@ fn check_non_exhaustive<'tcx>(
                         "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();
                 },
             )
         }
index 4522678802ba9b76c324824c8037510c01b76903..4bd5e9f6ab5797717435c00382acd4e8684c38bf 100644 (file)
@@ -58,17 +58,20 @@ pub(in super::super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, k
 
                 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();
-                })
+                    },
+                )
             }
         }
     }
index 254a19368bfe2bc6fbc4364021d6c1f32edec394..898419b5b237450ec2b62f9bc95001bbf6dbfaeb 100644 (file)
@@ -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
             },
         );
 
index d8fe63dbf084aee940e8bfb7a283a647c6e6b754..c604c8af8d25d6aff1f664f9637735484083e622 100644 (file)
@@ -328,17 +328,16 @@ fn check_asm_operand_type(
                     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
                     },
                 );
             }
index 392695cca6849fd09ad026dce49981875915c645..ca4cdf5a0d01c9b010216e0936f8d33f1ae10303 100644 (file)
@@ -82,14 +82,10 @@ pub(super) fn lint_dot_call_from_2018(
                 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 @@ pub(super) fn lint_dot_call_from_2018(
                         );
                     }
 
-                    lint.emit();
+                    lint
                 },
             );
         } else {
@@ -143,6 +139,7 @@ pub(super) fn lint_dot_call_from_2018(
                 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 @@ pub(super) fn lint_dot_call_from_2018(
                         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 @@ pub(super) fn lint_dot_call_from_2018(
                         );
                     }
 
-                    lint.emit();
+                    lint
                 },
             );
         }
@@ -257,15 +249,23 @@ pub(super) fn lint_fully_qualified_call_from_2018(
             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 @@ pub(super) fn lint_fully_qualified_call_from_2018(
                     )
                 };
 
-            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(
index 6cd7ced01a3bfd66a3fed3efb0732d2cfc46d9c1..a761a93dea4b6882b9987218631c9f7f418a9f47 100644 (file)
@@ -409,9 +409,8 @@ fn probe_op<OP, R>(
                         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 @@ fn emit_unstable_name_collision_hint(
         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 @@ fn emit_unstable_name_collision_hint(
                     }
                     (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 @@ fn emit_unstable_name_collision_hint(
                 }
                 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 @@ fn emit_unstable_name_collision_hint(
                     }
                 }
 
-                diag.emit();
+                lint
             },
         );
     }
index 8906b622b68e4d8291ed407169e3fec202b5fabb..178326cfdc4fb96e79b030a69b94eb7696047441 100644 (file)
@@ -1790,10 +1790,8 @@ fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String {
             &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 @@ fn joined_uncovered_patterns(witnesses: &[&Ident]) -> String {
             "the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
             ty,
         ));
-        lint.emit();
+
+        lint
     });
     }
 
index 0b207a6c0bee1d8fbf3b5a1941bf565075c2ebc0..4f4956416917331b61a62f8eddce02459bc4eaa6 100644 (file)
@@ -749,10 +749,8 @@ fn perform_2229_migration_anaysis(
                 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 @@ fn perform_2229_migration_anaysis(
                             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 @@ fn perform_2229_migration_anaysis(
 
                                 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 @@ fn perform_2229_migration_anaysis(
                                 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 @@ fn perform_2229_migration_anaysis(
                             }
                         }
                     }
-                    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 @@ fn perform_2229_migration_anaysis(
                             // 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 @@ fn perform_2229_migration_anaysis(
                             // 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 @@ fn perform_2229_migration_anaysis(
                         } 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 @@ fn perform_2229_migration_anaysis(
                             );
                         }
                     } else {
-                        diagnostics_builder.span_suggestion(
+                        lint.span_suggestion(
                             closure_span,
                             &diagnostic_msg,
                             migration_string,
@@ -895,7 +893,7 @@ fn perform_2229_migration_anaysis(
                         );
                     }
 
-                    diagnostics_builder.emit();
+                    lint
                 },
             );
         }
index 1d23ed9292180263f7be92f54688ad83f178f3e1..922833f85806cb30fae864152be3d04e0d02e00e 100644 (file)
@@ -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);
index 7d15e5a7f3c223fb2c851191a002d8becc051ac4..1307f74f2107196135377179bc27ddde2130440f 100644 (file)
@@ -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();
+            )
         },
     );
 }
index 8cd0a84274ec5507c37e6be95190828457bda060..ab4b861b6cb6081299a2dff365f08c3b120ac205 100644 (file)
@@ -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"),
                 )
             }
         }
index 1deff17e8408049e51036d58bf1d8867e4e814c8..7ffacbecf5f021d2cbfb8e3709c13e70f59650b7 100644 (file)
@@ -266,9 +266,8 @@ enum Defaults {
                             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 => {
index b97f8acb37f8442d7152d0e12f01fe9fac4db493..bd6b637f76fcdd88a9526b2cff54c7ada93343df 100644 (file)
@@ -118,37 +118,41 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
                 // to an array or to a slice.
                 _ => bug!("array type coerced to something other than array or slice"),
             };
-            cx.struct_span_lint(ARRAY_INTO_ITER, call.ident.span, |lint| {
-                let mut diag = lint.build(fluent::lint::array_into_iter);
-                diag.set_arg("target", target);
-                diag.span_suggestion(
-                    call.ident.span,
-                    fluent::lint::use_iter_suggestion,
-                    "iter",
-                    Applicability::MachineApplicable,
-                );
-                if self.for_expr_span == expr.span {
+            cx.struct_span_lint(
+                ARRAY_INTO_ITER,
+                call.ident.span,
+                fluent::lint::array_into_iter,
+                |diag| {
+                    diag.set_arg("target", target);
                     diag.span_suggestion(
-                        receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
-                        fluent::lint::remove_into_iter_suggestion,
-                        "",
-                        Applicability::MaybeIncorrect,
+                        call.ident.span,
+                        fluent::lint::use_iter_suggestion,
+                        "iter",
+                        Applicability::MachineApplicable,
                     );
-                } else if receiver_ty.is_array() {
-                    diag.multipart_suggestion(
-                        fluent::lint::use_explicit_into_iter_suggestion,
-                        vec![
-                            (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
-                            (
-                                receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
-                                ")".into(),
-                            ),
-                        ],
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-                diag.emit();
-            })
+                    if self.for_expr_span == expr.span {
+                        diag.span_suggestion(
+                            receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+                            fluent::lint::remove_into_iter_suggestion,
+                            "",
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else if receiver_ty.is_array() {
+                        diag.multipart_suggestion(
+                            fluent::lint::use_explicit_into_iter_suggestion,
+                            vec![
+                                (expr.span.shrink_to_lo(), "IntoIterator::into_iter(".into()),
+                                (
+                                    receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+                                    ")".into(),
+                                ),
+                            ],
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
+                    diag
+                },
+            )
         }
     }
 }
index 5d69c35ebfced90a07dd94323f31dd0383f189c1..f28cfbd8b4c46ada549d67685bc848a72bebc933 100644 (file)
@@ -33,8 +33,8 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_errors::{
-    fluent, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
-    LintDiagnosticBuilder, MultiSpan,
+    fluent, Applicability, DelayDm, Diagnostic, DiagnosticBuilder, DiagnosticMessage,
+    DiagnosticStyledString, MultiSpan,
 };
 use rustc_feature::{deprecated_attributes, AttributeGate, BuiltinAttribute, GateIssue, Stability};
 use rustc_hir as hir;
@@ -103,9 +103,12 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
             && !lit.span.from_expansion()
         {
             let condition_span = e.span.with_hi(cond.span.hi());
-            cx.struct_span_lint(WHILE_TRUE, condition_span, |lint| {
-                lint.build(fluent::lint::builtin_while_true)
-                    .span_suggestion_short(
+            cx.struct_span_lint(
+                            WHILE_TRUE,
+                            condition_span,
+                fluent::lint::builtin_while_true,
+                            |lint| {
+                    lint.span_suggestion_short(
                         condition_span,
                         fluent::lint::suggestion,
                         format!(
@@ -117,8 +120,8 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
                         ),
                         Applicability::MachineApplicable,
                     )
-                    .emit();
-            })
+                },
+            )
         }
     }
 }
@@ -154,9 +157,12 @@ fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
         for leaf in ty.walk() {
             if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
                 if leaf_ty.is_box() {
-                    cx.struct_span_lint(BOX_POINTERS, span, |lint| {
-                        lint.build(fluent::lint::builtin_box_pointers).set_arg("ty", ty).emit();
-                    });
+                    cx.struct_span_lint(
+                        BOX_POINTERS,
+                        span,
+                        fluent::lint::builtin_box_pointers,
+                        |lint| lint.set_arg("ty", ty),
+                    );
                 }
             }
         }
@@ -255,19 +261,21 @@ fn check_pat(&mut self, cx: &LateContext<'_>, pat: &hir::Pat<'_>) {
                     if cx.tcx.find_field_index(ident, &variant)
                         == Some(cx.tcx.field_index(fieldpat.hir_id, cx.typeck_results()))
                     {
-                        cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS, fieldpat.span, |lint| {
-                            let suggested_ident =
-                                format!("{}{}", binding_annot.prefix_str(), ident);
-                            lint.build(fluent::lint::builtin_non_shorthand_field_patterns)
-                                .set_arg("ident", ident.clone())
-                                .span_suggestion(
+                        cx.struct_span_lint(
+                            NON_SHORTHAND_FIELD_PATTERNS,
+                            fieldpat.span,
+                            fluent::lint::builtin_non_shorthand_field_patterns,
+                            |lint| {
+                                let suggested_ident =
+                                    format!("{}{}", binding_annot.prefix_str(), ident);
+                                lint.set_arg("ident", ident.clone()).span_suggestion(
                                     fieldpat.span,
                                     fluent::lint::suggestion,
                                     suggested_ident,
                                     Applicability::MachineApplicable,
                                 )
-                                .emit();
-                        });
+                            },
+                        );
                     }
                 }
             }
@@ -307,14 +315,17 @@ fn report_unsafe(
         &self,
         cx: &EarlyContext<'_>,
         span: Span,
-        decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+        msg: impl Into<DiagnosticMessage>,
+        decorate: impl for<'a, 'b> FnOnce(
+            &'b mut DiagnosticBuilder<'a, ()>,
+        ) -> &'b mut DiagnosticBuilder<'a, ()>,
     ) {
         // This comes from a macro that has `#[allow_internal_unsafe]`.
         if span.allows_unsafe() {
             return;
         }
 
-        cx.struct_span_lint(UNSAFE_CODE, span, decorate);
+        cx.struct_span_lint(UNSAFE_CODE, span, msg, decorate);
     }
 
     fn report_overridden_symbol_name(
@@ -323,8 +334,8 @@ fn report_overridden_symbol_name(
         span: Span,
         msg: DiagnosticMessage,
     ) {
-        self.report_unsafe(cx, span, |lint| {
-            lint.build(msg).note(fluent::lint::builtin_overridden_symbol_name).emit();
+        self.report_unsafe(cx, span, msg, |lint| {
+            lint.note(fluent::lint::builtin_overridden_symbol_name)
         })
     }
 
@@ -334,8 +345,8 @@ fn report_overridden_symbol_section(
         span: Span,
         msg: DiagnosticMessage,
     ) {
-        self.report_unsafe(cx, span, |lint| {
-            lint.build(msg).note(fluent::lint::builtin_overridden_symbol_section).emit();
+        self.report_unsafe(cx, span, msg, |lint| {
+            lint.note(fluent::lint::builtin_overridden_symbol_section)
         })
     }
 }
@@ -343,9 +354,12 @@ fn report_overridden_symbol_section(
 impl EarlyLintPass for UnsafeCode {
     fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
         if attr.has_name(sym::allow_internal_unsafe) {
-            self.report_unsafe(cx, attr.span, |lint| {
-                lint.build(fluent::lint::builtin_allow_internal_unsafe).emit();
-            });
+            self.report_unsafe(
+                cx,
+                attr.span,
+                fluent::lint::builtin_allow_internal_unsafe,
+                |lint| lint,
+            );
         }
     }
 
@@ -353,24 +367,20 @@ fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
         if let ast::ExprKind::Block(ref blk, _) = e.kind {
             // Don't warn about generated blocks; that'll just pollute the output.
             if blk.rules == ast::BlockCheckMode::Unsafe(ast::UserProvided) {
-                self.report_unsafe(cx, blk.span, |lint| {
-                    lint.build(fluent::lint::builtin_unsafe_block).emit();
-                });
+                self.report_unsafe(cx, blk.span, fluent::lint::builtin_unsafe_block, |lint| lint);
             }
         }
     }
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         match it.kind {
-            ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => self
-                .report_unsafe(cx, it.span, |lint| {
-                    lint.build(fluent::lint::builtin_unsafe_trait).emit();
-                }),
+            ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => {
+                self.report_unsafe(cx, it.span, fluent::lint::builtin_unsafe_trait, |lint| lint)
+            }
 
-            ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => self
-                .report_unsafe(cx, it.span, |lint| {
-                    lint.build(fluent::lint::builtin_unsafe_impl).emit();
-                }),
+            ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => {
+                self.report_unsafe(cx, it.span, fluent::lint::builtin_unsafe_impl, |lint| lint)
+            }
 
             ast::ItemKind::Fn(..) => {
                 if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
@@ -463,9 +473,7 @@ fn check_fn(&mut self, cx: &EarlyContext<'_>, fk: FnKind<'_>, span: Span, _: ast
                 FnCtxt::Assoc(_) if body.is_none() => fluent::lint::builtin_decl_unsafe_method,
                 FnCtxt::Assoc(_) => fluent::lint::builtin_impl_unsafe_method,
             };
-            self.report_unsafe(cx, span, |lint| {
-                lint.build(msg).emit();
-            });
+            self.report_unsafe(cx, span, msg, |lint| lint);
         }
     }
 }
@@ -566,12 +574,12 @@ fn check_missing_docs_attrs(
         let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id));
         let has_doc = attrs.iter().any(has_doc);
         if !has_doc {
-            cx.struct_span_lint(MISSING_DOCS, cx.tcx.def_span(def_id), |lint| {
-                lint.build(fluent::lint::builtin_missing_doc)
-                    .set_arg("article", article)
-                    .set_arg("desc", desc)
-                    .emit();
-            });
+            cx.struct_span_lint(
+                MISSING_DOCS,
+                cx.tcx.def_span(def_id),
+                fluent::lint::builtin_missing_doc,
+                |lint| lint.set_arg("article", article).set_arg("desc", desc),
+            );
         }
     }
 }
@@ -758,9 +766,12 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
         )
         .is_ok()
         {
-            cx.struct_span_lint(MISSING_COPY_IMPLEMENTATIONS, item.span, |lint| {
-                lint.build(fluent::lint::builtin_missing_copy_impl).emit();
-            })
+            cx.struct_span_lint(
+                MISSING_COPY_IMPLEMENTATIONS,
+                item.span,
+                fluent::lint::builtin_missing_copy_impl,
+                |lint| lint,
+            )
         }
     }
 }
@@ -834,11 +845,12 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
         }
 
         if !self.impling_types.as_ref().unwrap().contains(&item.def_id.def_id) {
-            cx.struct_span_lint(MISSING_DEBUG_IMPLEMENTATIONS, item.span, |lint| {
-                lint.build(fluent::lint::builtin_missing_debug_impl)
-                    .set_arg("debug", cx.tcx.def_path_str(debug))
-                    .emit();
-            });
+            cx.struct_span_lint(
+                MISSING_DEBUG_IMPLEMENTATIONS,
+                item.span,
+                fluent::lint::builtin_missing_debug_impl,
+                |lint| lint.set_arg("debug", cx.tcx.def_path_str(debug)),
+            );
         }
     }
 }
@@ -906,24 +918,26 @@ fn check_trait_item(&mut self, cx: &EarlyContext<'_>, it: &ast::AssocItem) {
             for arg in sig.decl.inputs.iter() {
                 if let ast::PatKind::Ident(_, ident, None) = arg.pat.kind {
                     if ident.name == kw::Empty {
-                        cx.struct_span_lint(ANONYMOUS_PARAMETERS, arg.pat.span, |lint| {
-                            let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
-
-                            let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
-                                (snip.as_str(), Applicability::MachineApplicable)
-                            } else {
-                                ("<type>", Applicability::HasPlaceholders)
-                            };
+                        let ty_snip = cx.sess().source_map().span_to_snippet(arg.ty.span);
 
-                            lint.build(fluent::lint::builtin_anonymous_params)
-                                .span_suggestion(
+                        let (ty_snip, appl) = if let Ok(ref snip) = ty_snip {
+                            (snip.as_str(), Applicability::MachineApplicable)
+                        } else {
+                            ("<type>", Applicability::HasPlaceholders)
+                        };
+                        cx.struct_span_lint(
+                            ANONYMOUS_PARAMETERS,
+                            arg.pat.span,
+                            fluent::lint::builtin_anonymous_params,
+                            |lint| {
+                                lint.span_suggestion(
                                     arg.pat.span,
                                     fluent::lint::suggestion,
                                     format!("_: {}", ty_snip),
                                     appl,
                                 )
-                                .emit();
-                        })
+                            },
+                        )
                     }
                 }
             }
@@ -958,38 +972,44 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
                     _,
                 ) = gate
                 {
-                    cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
-                        // FIXME(davidtwco) translatable deprecated attr
-                        lint.build(fluent::lint::builtin_deprecated_attr_link)
-                            .set_arg("name", name)
-                            .set_arg("reason", reason)
-                            .set_arg("link", link)
-                            .span_suggestion_short(
-                                attr.span,
-                                suggestion.map(|s| s.into()).unwrap_or(
-                                    fluent::lint::builtin_deprecated_attr_default_suggestion,
-                                ),
-                                "",
-                                Applicability::MachineApplicable,
-                            )
-                            .emit();
-                    });
+                    // FIXME(davidtwco) translatable deprecated attr
+                    cx.struct_span_lint(
+                        DEPRECATED,
+                        attr.span,
+                        fluent::lint::builtin_deprecated_attr_link,
+                        |lint| {
+                            lint.set_arg("name", name)
+                                .set_arg("reason", reason)
+                                .set_arg("link", link)
+                                .span_suggestion_short(
+                                    attr.span,
+                                    suggestion.map(|s| s.into()).unwrap_or(
+                                        fluent::lint::builtin_deprecated_attr_default_suggestion,
+                                    ),
+                                    "",
+                                    Applicability::MachineApplicable,
+                                )
+                        },
+                    );
                 }
                 return;
             }
         }
         if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
-            cx.struct_span_lint(DEPRECATED, attr.span, |lint| {
-                lint.build(fluent::lint::builtin_deprecated_attr_used)
-                    .set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
-                    .span_suggestion_short(
-                        attr.span,
-                        fluent::lint::builtin_deprecated_attr_default_suggestion,
-                        "",
-                        Applicability::MachineApplicable,
-                    )
-                    .emit();
-            });
+            cx.struct_span_lint(
+                DEPRECATED,
+                attr.span,
+                fluent::lint::builtin_deprecated_attr_used,
+                |lint| {
+                    lint.set_arg("name", pprust::path_to_string(&attr.get_normal_item().path))
+                        .span_suggestion_short(
+                            attr.span,
+                            fluent::lint::builtin_deprecated_attr_default_suggestion,
+                            "",
+                            Applicability::MachineApplicable,
+                        )
+                },
+            );
         }
     }
 }
@@ -1016,20 +1036,21 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
         let span = sugared_span.take().unwrap_or(attr.span);
 
         if is_doc_comment || attr.has_name(sym::doc) {
-            cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
-                let mut err = lint.build(fluent::lint::builtin_unused_doc_comment);
-                err.set_arg("kind", node_kind);
-                err.span_label(node_span, fluent::lint::label);
-                match attr.kind {
-                    AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
-                        err.help(fluent::lint::plain_help);
-                    }
-                    AttrKind::DocComment(CommentKind::Block, _) => {
-                        err.help(fluent::lint::block_help);
-                    }
-                }
-                err.emit();
-            });
+            cx.struct_span_lint(
+                UNUSED_DOC_COMMENTS,
+                span,
+                fluent::lint::builtin_unused_doc_comment,
+                |lint| {
+                    lint.set_arg("kind", node_kind).span_label(node_span, fluent::lint::label).help(
+                        match attr.kind {
+                            AttrKind::DocComment(CommentKind::Line, _) | AttrKind::Normal(..) => {
+                                fluent::lint::plain_help
+                            }
+                            AttrKind::DocComment(CommentKind::Block, _) => fluent::lint::block_help,
+                        },
+                    )
+                },
+            );
         }
     }
 }
@@ -1143,9 +1164,12 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
                 match param.kind {
                     GenericParamKind::Lifetime { .. } => {}
                     GenericParamKind::Type { .. } | GenericParamKind::Const { .. } => {
-                        cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS, span, |lint| {
-                            lint.build(fluent::lint::builtin_no_mangle_generic)
-                                .span_suggestion_short(
+                        cx.struct_span_lint(
+                            NO_MANGLE_GENERIC_ITEMS,
+                            span,
+                            fluent::lint::builtin_no_mangle_generic,
+                            |lint| {
+                                lint.span_suggestion_short(
                                     no_mangle_attr.span,
                                     fluent::lint::suggestion,
                                     "",
@@ -1153,8 +1177,8 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
                                     // fix may be to monomorphize source by hand
                                     Applicability::MaybeIncorrect,
                                 )
-                                .emit();
-                        });
+                            },
+                        );
                         break;
                     }
                 }
@@ -1170,27 +1194,29 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
                 if cx.sess().contains_name(attrs, sym::no_mangle) {
                     // Const items do not refer to a particular location in memory, and therefore
                     // don't have anything to attach a symbol to
-                    cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| {
-                        let mut err = lint.build(fluent::lint::builtin_const_no_mangle);
-
-                        // account for "pub const" (#45562)
-                        let start = cx
-                            .tcx
-                            .sess
-                            .source_map()
-                            .span_to_snippet(it.span)
-                            .map(|snippet| snippet.find("const").unwrap_or(0))
-                            .unwrap_or(0) as u32;
-                        // `const` is 5 chars
-                        let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
-                        err.span_suggestion(
-                            const_span,
-                            fluent::lint::suggestion,
-                            "pub static",
-                            Applicability::MachineApplicable,
-                        );
-                        err.emit();
-                    });
+                    cx.struct_span_lint(
+                        NO_MANGLE_CONST_ITEMS,
+                        it.span,
+                        fluent::lint::builtin_const_no_mangle,
+                        |lint| {
+                            // account for "pub const" (#45562)
+                            let start = cx
+                                .tcx
+                                .sess
+                                .source_map()
+                                .span_to_snippet(it.span)
+                                .map(|snippet| snippet.find("const").unwrap_or(0))
+                                .unwrap_or(0) as u32;
+                            // `const` is 5 chars
+                            let const_span = it.span.with_hi(BytePos(it.span.lo().0 + start + 5));
+                            lint.span_suggestion(
+                                const_span,
+                                fluent::lint::suggestion,
+                                "pub static",
+                                Applicability::MachineApplicable,
+                            )
+                        },
+                    );
                 }
             }
             hir::ItemKind::Impl(hir::Impl { generics, items, .. }) => {
@@ -1250,9 +1276,12 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
             get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind()))
         {
             if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not {
-                cx.struct_span_lint(MUTABLE_TRANSMUTES, expr.span, |lint| {
-                    lint.build(fluent::lint::builtin_mutable_transmutes).emit();
-                });
+                cx.struct_span_lint(
+                    MUTABLE_TRANSMUTES,
+                    expr.span,
+                    fluent::lint::builtin_mutable_transmutes,
+                    |lint| lint,
+                );
             }
         }
 
@@ -1300,9 +1329,12 @@ fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
         if attr.has_name(sym::feature) {
             if let Some(items) = attr.meta_item_list() {
                 for item in items {
-                    cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
-                        lint.build(fluent::lint::builtin_unstable_features).emit();
-                    });
+                    cx.struct_span_lint(
+                        UNSTABLE_FEATURES,
+                        item.span(),
+                        fluent::lint::builtin_unstable_features,
+                        |lint| lint,
+                    );
                 }
             }
         }
@@ -1361,21 +1393,25 @@ fn perform_lint(
                 applicability = Applicability::MaybeIncorrect;
             }
             let def_span = cx.tcx.def_span(def_id);
-            cx.struct_span_lint(UNREACHABLE_PUB, def_span, |lint| {
-                let mut err = lint.build(fluent::lint::builtin_unreachable_pub);
-                err.set_arg("what", what);
-
-                err.span_suggestion(
-                    vis_span,
-                    fluent::lint::suggestion,
-                    "pub(crate)",
-                    applicability,
-                );
-                if exportable {
-                    err.help(fluent::lint::help);
-                }
-                err.emit();
-            });
+            cx.struct_span_lint(
+                UNREACHABLE_PUB,
+                def_span,
+                fluent::lint::builtin_unreachable_pub,
+                |lint| {
+                    lint.set_arg("what", what);
+
+                    lint.span_suggestion(
+                        vis_span,
+                        fluent::lint::suggestion,
+                        "pub(crate)",
+                        applicability,
+                    );
+                    if exportable {
+                        lint.help(fluent::lint::help);
+                    }
+                    lint
+                },
+            );
         }
     }
 }
@@ -1505,36 +1541,34 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
 
         let mut suggested_changing_assoc_types = false;
         if !where_spans.is_empty() {
-            cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
-                let mut err = lint.build(fluent::lint::builtin_type_alias_where_clause);
-                err.set_span(where_spans);
-                err.span_suggestion(
+            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint::builtin_type_alias_where_clause, |lint| {
+                lint.set_span(where_spans);
+                lint.span_suggestion(
                     type_alias_generics.where_clause_span,
                     fluent::lint::suggestion,
                     "",
                     Applicability::MachineApplicable,
                 );
                 if !suggested_changing_assoc_types {
-                    TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+                    TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
                     suggested_changing_assoc_types = true;
                 }
-                err.emit();
+                lint
             });
         }
 
         if !inline_spans.is_empty() {
-            cx.lint(TYPE_ALIAS_BOUNDS, |lint| {
-                let mut err = lint.build(fluent::lint::builtin_type_alias_generic_bounds);
-                err.set_span(inline_spans);
-                err.multipart_suggestion(
+            cx.lint(TYPE_ALIAS_BOUNDS, fluent::lint::builtin_type_alias_generic_bounds, |lint| {
+                lint.set_span(inline_spans);
+                lint.multipart_suggestion(
                     fluent::lint::suggestion,
                     inline_sugg,
                     Applicability::MachineApplicable,
                 );
                 if !suggested_changing_assoc_types {
-                    TypeAliasBounds::suggest_changing_assoc_types(ty, &mut err);
+                    TypeAliasBounds::suggest_changing_assoc_types(ty, lint);
                 }
-                err.emit();
+                lint
             });
         }
     }
@@ -1633,12 +1667,15 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
                     TypeWellFormedFromEnv(..) => continue,
                 };
                 if predicate.is_global() {
-                    cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| {
-                        lint.build(fluent::lint::builtin_trivial_bounds)
-                            .set_arg("predicate_kind_name", predicate_kind_name)
-                            .set_arg("predicate", predicate)
-                            .emit();
-                    });
+                    cx.struct_span_lint(
+                        TRIVIAL_BOUNDS,
+                        span,
+                        fluent::lint::builtin_trivial_bounds,
+                        |lint| {
+                            lint.set_arg("predicate_kind_name", predicate_kind_name)
+                                .set_arg("predicate", predicate)
+                        },
+                    );
                 }
             }
         }
@@ -1754,15 +1791,13 @@ fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)>
                         replace,
                     });
                 } else {
-                    cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, |lint| {
-                        lint.build(msg)
-                            .span_suggestion(
-                                pat.span,
-                                suggestion,
-                                replace,
-                                Applicability::MachineApplicable,
-                            )
-                            .emit();
+                    cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, pat.span, msg, |lint| {
+                        lint.span_suggestion(
+                            pat.span,
+                            suggestion,
+                            replace,
+                            Applicability::MachineApplicable,
+                        )
                     });
                 }
             } else {
@@ -1774,15 +1809,13 @@ fn matches_ellipsis_pat(pat: &ast::Pat) -> Option<(Option<&Expr>, &Expr, Span)>
                         replace: replace.to_string(),
                     });
                 } else {
-                    cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, |lint| {
-                        lint.build(msg)
-                            .span_suggestion_short(
-                                join,
-                                suggestion,
-                                replace,
-                                Applicability::MachineApplicable,
-                            )
-                            .emit();
+                    cx.struct_span_lint(ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, join, msg, |lint| {
+                        lint.span_suggestion_short(
+                            join,
+                            suggestion,
+                            replace,
+                            Applicability::MachineApplicable,
+                        )
                     });
                 }
             };
@@ -1863,9 +1896,12 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
 
         let attrs = cx.tcx.hir().attrs(it.hir_id());
         if let Some(attr) = cx.sess().find_by_name(attrs, sym::rustc_test_marker) {
-            cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| {
-                lint.build(fluent::lint::builtin_unnameable_test_items).emit();
-            });
+            cx.struct_span_lint(
+                UNNAMEABLE_TEST_ITEMS,
+                attr.span,
+                fluent::lint::builtin_unnameable_test_items,
+                |lint| lint,
+            );
         }
     }
 
@@ -1981,18 +2017,19 @@ fn check_ident_token(
             return;
         }
 
-        cx.struct_span_lint(KEYWORD_IDENTS, ident.span, |lint| {
-            lint.build(fluent::lint::builtin_keyword_idents)
-                .set_arg("kw", ident.clone())
-                .set_arg("next", next_edition)
-                .span_suggestion(
+        cx.struct_span_lint(
+            KEYWORD_IDENTS,
+            ident.span,
+            fluent::lint::builtin_keyword_idents,
+            |lint| {
+                lint.set_arg("kw", ident.clone()).set_arg("next", next_edition).span_suggestion(
                     ident.span,
                     fluent::lint::suggestion,
                     format!("r#{}", ident),
                     Applicability::MachineApplicable,
                 )
-                .emit();
-        });
+            },
+        );
     }
 }
 
@@ -2243,10 +2280,12 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
             }
 
             if !lint_spans.is_empty() {
-                cx.struct_span_lint(EXPLICIT_OUTLIVES_REQUIREMENTS, lint_spans.clone(), |lint| {
-                    lint.build(fluent::lint::builtin_explicit_outlives)
-                        .set_arg("count", bound_count)
-                        .multipart_suggestion(
+                cx.struct_span_lint(
+                    EXPLICIT_OUTLIVES_REQUIREMENTS,
+                    lint_spans.clone(),
+                    fluent::lint::builtin_explicit_outlives,
+                    |lint| {
+                        lint.set_arg("count", bound_count).multipart_suggestion(
                             fluent::lint::suggestion,
                             lint_spans
                                 .into_iter()
@@ -2254,8 +2293,8 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
                                 .collect::<Vec<_>>(),
                             Applicability::MachineApplicable,
                         )
-                        .emit();
-                });
+                    },
+                );
             }
         }
     }
@@ -2302,18 +2341,24 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
             .chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
             .filter(|(&name, _)| features.incomplete(name))
             .for_each(|(&name, &span)| {
-                cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
-                    let mut builder = lint.build(fluent::lint::builtin_incomplete_features);
-                    builder.set_arg("name", name);
-                    if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) {
-                        builder.set_arg("n", n);
-                        builder.note(fluent::lint::note);
-                    }
-                    if HAS_MIN_FEATURES.contains(&name) {
-                        builder.help(fluent::lint::help);
-                    }
-                    builder.emit();
-                })
+                cx.struct_span_lint(
+                    INCOMPLETE_FEATURES,
+                    span,
+                    fluent::lint::builtin_incomplete_features,
+                    |lint| {
+                        lint.set_arg("name", name);
+                        if let Some(n) =
+                            rustc_feature::find_feature_issue(name, GateIssue::Language)
+                        {
+                            lint.set_arg("n", n);
+                            lint.note(fluent::lint::note);
+                        }
+                        if HAS_MIN_FEATURES.contains(&name) {
+                            lint.help(fluent::lint::help);
+                        }
+                        lint
+                    },
+                )
             });
     }
 }
@@ -2628,28 +2673,37 @@ fn ty_find_init_error<'tcx>(
                 with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init))
             {
                 // FIXME(davidtwco): make translatable
-                cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| {
-                    let mut err = lint.build(&format!(
-                        "the type `{}` does not permit {}",
-                        conjured_ty,
-                        match init {
-                            InitKind::Zeroed => "zero-initialization",
-                            InitKind::Uninit => "being left uninitialized",
-                        },
-                    ));
-                    err.span_label(expr.span, "this code causes undefined behavior when executed");
-                    err.span_label(
-                        expr.span,
-                        "help: use `MaybeUninit<T>` instead, \
+                cx.struct_span_lint(
+                    INVALID_VALUE,
+                    expr.span,
+                    DelayDm(|| {
+                        format!(
+                            "the type `{}` does not permit {}",
+                            conjured_ty,
+                            match init {
+                                InitKind::Zeroed => "zero-initialization",
+                                InitKind::Uninit => "being left uninitialized",
+                            },
+                        )
+                    }),
+                    |lint| {
+                        lint.span_label(
+                            expr.span,
+                            "this code causes undefined behavior when executed",
+                        );
+                        lint.span_label(
+                            expr.span,
+                            "help: use `MaybeUninit<T>` instead, \
                             and only call `assume_init` after initialization is done",
-                    );
-                    if let Some(span) = span {
-                        err.span_note(span, &msg);
-                    } else {
-                        err.note(&msg);
-                    }
-                    err.emit();
-                });
+                        );
+                        if let Some(span) = span {
+                            lint.span_note(span, &msg);
+                        } else {
+                            lint.note(&msg);
+                        }
+                        lint
+                    },
+                );
             }
         }
     }
@@ -2995,31 +3049,35 @@ fn check_foreign_item(&mut self, cx: &LateContext<'tcx>, this_fi: &hir::ForeignI
                             SymbolName::Link(_, annot_span) => fi.span.to(annot_span),
                         };
                     // Finally, emit the diagnostic.
+
+                    let msg = if orig.get_name() == this_fi.ident.name {
+                        fluent::lint::builtin_clashing_extern_same_name
+                    } else {
+                        fluent::lint::builtin_clashing_extern_diff_name
+                    };
                     tcx.struct_span_lint_hir(
                         CLASHING_EXTERN_DECLARATIONS,
                         this_fi.hir_id(),
                         get_relevant_span(this_fi),
+                        msg,
                         |lint| {
                             let mut expected_str = DiagnosticStyledString::new();
                             expected_str.push(existing_decl_ty.fn_sig(tcx).to_string(), false);
                             let mut found_str = DiagnosticStyledString::new();
                             found_str.push(this_decl_ty.fn_sig(tcx).to_string(), true);
 
-                            lint.build(if orig.get_name() == this_fi.ident.name {
-                                fluent::lint::builtin_clashing_extern_same_name
-                            } else {
-                                fluent::lint::builtin_clashing_extern_diff_name
-                            })
-                            .set_arg("this_fi", this_fi.ident.name)
-                            .set_arg("orig", orig.get_name())
-                            .span_label(
-                                get_relevant_span(orig_fi),
-                                fluent::lint::previous_decl_label,
-                            )
-                            .span_label(get_relevant_span(this_fi), fluent::lint::mismatch_label)
-                            // FIXME(davidtwco): translatable expected/found
-                            .note_expected_found(&"", expected_str, &"", found_str)
-                            .emit();
+                            lint.set_arg("this_fi", this_fi.ident.name)
+                                .set_arg("orig", orig.get_name())
+                                .span_label(
+                                    get_relevant_span(orig_fi),
+                                    fluent::lint::previous_decl_label,
+                                )
+                                .span_label(
+                                    get_relevant_span(this_fi),
+                                    fluent::lint::mismatch_label,
+                                )
+                                // FIXME(davidtwco): translatable expected/found
+                                .note_expected_found(&"", expected_str, &"", found_str)
                         },
                     );
                 }
@@ -3100,11 +3158,12 @@ fn is_zero(expr: &hir::Expr<'_>) -> bool {
 
         if let rustc_hir::ExprKind::Unary(rustc_hir::UnOp::Deref, expr_deref) = expr.kind {
             if is_null_ptr(cx, expr_deref) {
-                cx.struct_span_lint(DEREF_NULLPTR, expr.span, |lint| {
-                    let mut err = lint.build(fluent::lint::builtin_deref_nullptr);
-                    err.span_label(expr.span, fluent::lint::label);
-                    err.emit();
-                });
+                cx.struct_span_lint(
+                    DEREF_NULLPTR,
+                    expr.span,
+                    fluent::lint::builtin_deref_nullptr,
+                    |lint| lint.span_label(expr.span, fluent::lint::label),
+                );
             }
         }
     }
@@ -3214,9 +3273,8 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
                     cx.lookup_with_diagnostics(
                             NAMED_ASM_LABELS,
                             Some(target_spans),
-                            |diag| {
-                                diag.build(fluent::lint::builtin_asm_labels).emit();
-                            },
+                            fluent::lint::builtin_asm_labels,
+                            |lint| lint,
                             BuiltinLintDiagnostics::NamedAsmLabel(
                                 "only local labels of the form `<number>:` should be used in inline asm"
                                     .to_string(),
@@ -3288,16 +3346,14 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &ast::Crate) {
                 }
 
                 match item.ident.name.as_str() {
-                    "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
-                        lint.build("found module declaration for lib.rs")
+                    "lib" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for lib.rs", |lint| {
+                        lint
                             .note("lib.rs is the root of this crate's library target")
                             .help("to refer to it from other targets, use the library's name as the path")
-                            .emit()
                     }),
-                    "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, |lint| {
-                        lint.build("found module declaration for main.rs")
+                    "main" => cx.struct_span_lint(SPECIAL_MODULE_NAME, item.span, "found module declaration for main.rs", |lint| {
+                        lint
                             .note("a binary crate cannot be used as library")
-                            .emit()
                     }),
                     _ => continue
                 }
@@ -3317,24 +3373,27 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
         for &(name, value) in cfg {
             if let Some(names_valid) = &check_cfg.names_valid {
                 if !names_valid.contains(&name) {
-                    cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| {
-                        diag.build(fluent::lint::builtin_unexpected_cli_config_name)
-                            .help(fluent::lint::help)
-                            .set_arg("name", name)
-                            .emit();
-                    });
+                    cx.lookup(
+                        UNEXPECTED_CFGS,
+                        None::<MultiSpan>,
+                        fluent::lint::builtin_unexpected_cli_config_name,
+                        |diag| diag.help(fluent::lint::help).set_arg("name", name),
+                    );
                 }
             }
             if let Some(value) = value {
                 if let Some(values) = &check_cfg.values_valid.get(&name) {
                     if !values.contains(&value) {
-                        cx.lookup(UNEXPECTED_CFGS, None::<MultiSpan>, |diag| {
-                            diag.build(fluent::lint::builtin_unexpected_cli_config_value)
-                                .help(fluent::lint::help)
-                                .set_arg("name", name)
-                                .set_arg("value", value)
-                                .emit();
-                        });
+                        cx.lookup(
+                            UNEXPECTED_CFGS,
+                            None::<MultiSpan>,
+                            fluent::lint::builtin_unexpected_cli_config_value,
+                            |diag| {
+                                diag.help(fluent::lint::help)
+                                    .set_arg("name", name)
+                                    .set_arg("value", value)
+                            },
+                        );
                     }
                 }
             }
index cbab56f2066f01ad8b23ed774920b6b3f97d3b10..9df6e0f534e61d61a442b174c110a32b337af93d 100644 (file)
 use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync;
-use rustc_errors::add_elided_lifetime_in_path_suggestion;
-use rustc_errors::{
-    Applicability, DecorateLint, LintDiagnosticBuilder, MultiSpan, SuggestionStyle,
-};
+use rustc_errors::{add_elided_lifetime_in_path_suggestion, DiagnosticBuilder, DiagnosticMessage};
+use rustc_errors::{Applicability, DecorateLint, MultiSpan, SuggestionStyle};
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId};
@@ -580,13 +578,14 @@ fn lookup_with_diagnostics(
         &self,
         lint: &'static Lint,
         span: Option<impl Into<MultiSpan>>,
-        decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+        msg: impl Into<DiagnosticMessage>,
+        decorate: impl for<'a, 'b> FnOnce(
+            &'b mut DiagnosticBuilder<'a, ()>,
+        ) -> &'b mut DiagnosticBuilder<'a, ()>,
         diagnostic: BuiltinLintDiagnostics,
     ) {
-        self.lookup(lint, span, |lint| {
-            // We first generate a blank diagnostic.
-            let mut db = lint.build("");
-
+        // We first generate a blank diagnostic.
+        self.lookup(lint, span, msg,|db| {
             // Now, set up surrounding context.
             let sess = self.sess();
             match diagnostic {
@@ -660,7 +659,7 @@ fn lookup_with_diagnostics(
                 ) => {
                     add_elided_lifetime_in_path_suggestion(
                         sess.source_map(),
-                        &mut db,
+                        db,
                         n,
                         path_span,
                         incl_angl_brckt,
@@ -696,7 +695,7 @@ fn lookup_with_diagnostics(
                     }
                 }
                 BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) => {
-                    stability::deprecation_suggestion(&mut db, "macro", suggestion, span)
+                    stability::deprecation_suggestion(db, "macro", suggestion, span)
                 }
                 BuiltinLintDiagnostics::UnusedDocComment(span) => {
                     db.span_label(span, "rustdoc does not generate documentation for macro invocations");
@@ -867,7 +866,7 @@ fn lookup_with_diagnostics(
                 }
             }
             // Rewrap `db`, and pass control to the user.
-            decorate(LintDiagnosticBuilder::new(db));
+            decorate(db)
         });
     }
 
@@ -877,7 +876,10 @@ fn lookup<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
         span: Option<S>,
-        decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+        msg: impl Into<DiagnosticMessage>,
+        decorate: impl for<'a, 'b> FnOnce(
+            &'b mut DiagnosticBuilder<'a, ()>,
+        ) -> &'b mut DiagnosticBuilder<'a, ()>,
     );
 
     /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`,
@@ -888,31 +890,39 @@ fn emit_spanned_lint<S: Into<MultiSpan>>(
         span: S,
         decorator: impl for<'a> DecorateLint<'a, ()>,
     ) {
-        self.lookup(lint, Some(span), |diag| decorator.decorate_lint(diag));
+        self.lookup(lint, Some(span), decorator.msg(), |diag| decorator.decorate_lint(diag));
     }
 
     fn struct_span_lint<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
         span: S,
-        decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+        msg: impl Into<DiagnosticMessage>,
+        decorate: impl for<'a, 'b> FnOnce(
+            &'b mut DiagnosticBuilder<'a, ()>,
+        ) -> &'b mut DiagnosticBuilder<'a, ()>,
     ) {
-        self.lookup(lint, Some(span), decorate);
+        self.lookup(lint, Some(span), msg, decorate);
     }
 
     /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically
     /// generated by `#[derive(LintDiagnostic)]`).
     fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a, ()>) {
-        self.lookup(lint, None as Option<Span>, |diag| decorator.decorate_lint(diag));
+        self.lookup(lint, None as Option<Span>, decorator.msg(), |diag| {
+            decorator.decorate_lint(diag)
+        });
     }
 
     /// Emit a lint at the appropriate level, with no associated span.
     fn lint(
         &self,
         lint: &'static Lint,
-        decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+        msg: DiagnosticMessage,
+        decorate: impl for<'a, 'b> FnOnce(
+            &'b mut DiagnosticBuilder<'a, ()>,
+        ) -> &'b mut DiagnosticBuilder<'a, ()>,
     ) {
-        self.lookup(lint, None as Option<Span>, decorate);
+        self.lookup(lint, None as Option<Span>, msg, decorate);
     }
 
     /// This returns the lint level for the given lint at the current location.
@@ -975,13 +985,16 @@ fn lookup<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
         span: Option<S>,
-        decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+        msg: impl Into<DiagnosticMessage>,
+        decorate: impl for<'a, 'b> FnOnce(
+            &'b mut DiagnosticBuilder<'a, ()>,
+        ) -> &'b mut DiagnosticBuilder<'a, ()>,
     ) {
         let hir_id = self.last_node_with_lint_attrs;
 
         match span {
-            Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, decorate),
-            None => self.tcx.struct_lint_node(lint, hir_id, decorate),
+            Some(s) => self.tcx.struct_span_lint_hir(lint, hir_id, s, msg, decorate),
+            None => self.tcx.struct_lint_node(lint, hir_id, msg, decorate),
         }
     }
 
@@ -1006,9 +1019,12 @@ fn lookup<S: Into<MultiSpan>>(
         &self,
         lint: &'static Lint,
         span: Option<S>,
-        decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+        msg: impl Into<DiagnosticMessage>,
+        decorate: impl for<'a, 'b> FnOnce(
+            &'b mut DiagnosticBuilder<'a, ()>,
+        ) -> &'b mut DiagnosticBuilder<'a, ()>,
     ) {
-        self.builder.struct_lint(lint, span.map(|s| s.into()), decorate)
+        self.builder.struct_lint(lint, span.map(|s| s.into()), msg, decorate)
     }
 
     fn get_lint_level(&self, lint: &'static Lint) -> Level {
index 96ecd79a69cfb3603cae46f45a7c06064ab331a8..18d30e1435be8f74937e544d3ccfbe050ea2ea47 100644 (file)
@@ -43,9 +43,8 @@ fn check_id(&mut self, id: ast::NodeId) {
             self.context.lookup_with_diagnostics(
                 lint_id.lint,
                 Some(span),
-                |lint| {
-                    lint.build(msg).emit();
-                },
+                msg,
+                |lint| lint,
                 diagnostic,
             );
         }
index f41ee6404992d197175b8c6d33e97b9696137780..e8d307814b9d50c6834cdfae1e15e41a660af470 100644 (file)
@@ -50,26 +50,24 @@ fn enforce_mem_discriminant(
 ) {
     let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
     if is_non_enum(ty_param) {
-        cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, expr_span, |builder| {
-            builder
-                .build(fluent::lint::enum_intrinsics_mem_discriminant)
-                .set_arg("ty_param", ty_param)
-                .span_note(args_span, fluent::lint::note)
-                .emit();
-        });
+        cx.struct_span_lint(
+            ENUM_INTRINSICS_NON_ENUMS,
+            expr_span,
+            fluent::lint::enum_intrinsics_mem_discriminant,
+            |lint| lint.set_arg("ty_param", ty_param).span_note(args_span, fluent::lint::note),
+        );
     }
 }
 
 fn enforce_mem_variant_count(cx: &LateContext<'_>, func_expr: &hir::Expr<'_>, span: Span) {
     let ty_param = cx.typeck_results().node_substs(func_expr.hir_id).type_at(0);
     if is_non_enum(ty_param) {
-        cx.struct_span_lint(ENUM_INTRINSICS_NON_ENUMS, span, |builder| {
-            builder
-                .build(fluent::lint::enum_intrinsics_mem_variant)
-                .set_arg("ty_param", ty_param)
-                .note(fluent::lint::note)
-                .emit();
-        });
+        cx.struct_span_lint(
+            ENUM_INTRINSICS_NON_ENUMS,
+            span,
+            fluent::lint::enum_intrinsics_mem_variant,
+            |lint| lint.set_arg("ty_param", ty_param).note(fluent::lint::note),
+        );
     }
 }
 
index 699e81543188f4f44f5c674f8c228ade46986409..af13f453a509842c7272078359464f8e5f53cda6 100644 (file)
@@ -43,17 +43,17 @@ fn emit_unfulfilled_expectation_lint(
         builtin::UNFULFILLED_LINT_EXPECTATIONS,
         hir_id,
         expectation.emission_span,
-        |diag| {
-            let mut diag = diag.build(fluent::lint::expectation);
+        fluent::lint::expectation,
+        |lint| {
             if let Some(rationale) = expectation.reason {
-                diag.note(rationale.as_str());
+                lint.note(rationale.as_str());
             }
 
             if expectation.is_unfulfilled_lint_expectations {
-                diag.note(fluent::lint::note);
+                lint.note(fluent::lint::note);
             }
 
-            diag.emit();
+            lint
         },
     );
 }
index 8f22221324a6e64343208b0bc84987485fffd145..42557068bd3d7e585f4354acfeb327ad619e684e 100644 (file)
@@ -60,52 +60,56 @@ fn lint_text_direction_codepoint(
             })
             .collect();
 
-        cx.struct_span_lint(TEXT_DIRECTION_CODEPOINT_IN_LITERAL, span, |lint| {
-            let mut err = lint.build(fluent::lint::hidden_unicode_codepoints);
-            err.set_arg("label", label);
-            err.set_arg("count", spans.len());
-            err.span_label(span, fluent::lint::label);
-            err.note(fluent::lint::note);
-            if point_at_inner_spans {
-                for (c, span) in &spans {
-                    err.span_label(*span, format!("{:?}", c));
+        cx.struct_span_lint(
+            TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
+            span,
+            fluent::lint::hidden_unicode_codepoints,
+            |lint| {
+                lint.set_arg("label", label);
+                lint.set_arg("count", spans.len());
+                lint.span_label(span, fluent::lint::label);
+                lint.note(fluent::lint::note);
+                if point_at_inner_spans {
+                    for (c, span) in &spans {
+                        lint.span_label(*span, format!("{:?}", c));
+                    }
                 }
-            }
-            if point_at_inner_spans && !spans.is_empty() {
-                err.multipart_suggestion_with_style(
-                    fluent::lint::suggestion_remove,
-                    spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
-                    Applicability::MachineApplicable,
-                    SuggestionStyle::HideCodeAlways,
-                );
-                err.multipart_suggestion(
-                    fluent::lint::suggestion_escape,
-                    spans
-                        .into_iter()
-                        .map(|(c, span)| {
-                            let c = format!("{:?}", c);
-                            (span, c[1..c.len() - 1].to_string())
-                        })
-                        .collect(),
-                    Applicability::MachineApplicable,
-                );
-            } else {
-                // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
-                // should do the same here to provide the same good suggestions as we do for
-                // literals above.
-                err.set_arg(
-                    "escaped",
-                    spans
-                        .into_iter()
-                        .map(|(c, _)| format!("{:?}", c))
-                        .collect::<Vec<String>>()
-                        .join(", "),
-                );
-                err.note(fluent::lint::suggestion_remove);
-                err.note(fluent::lint::no_suggestion_note_escape);
-            }
-            err.emit();
-        });
+                if point_at_inner_spans && !spans.is_empty() {
+                    lint.multipart_suggestion_with_style(
+                        fluent::lint::suggestion_remove,
+                        spans.iter().map(|(_, span)| (*span, "".to_string())).collect(),
+                        Applicability::MachineApplicable,
+                        SuggestionStyle::HideCodeAlways,
+                    );
+                    lint.multipart_suggestion(
+                        fluent::lint::suggestion_escape,
+                        spans
+                            .into_iter()
+                            .map(|(c, span)| {
+                                let c = format!("{:?}", c);
+                                (span, c[1..c.len() - 1].to_string())
+                            })
+                            .collect(),
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    // FIXME: in other suggestions we've reversed the inner spans of doc comments. We
+                    // should do the same here to provide the same good suggestions as we do for
+                    // literals above.
+                    lint.set_arg(
+                        "escaped",
+                        spans
+                            .into_iter()
+                            .map(|(c, _)| format!("{:?}", c))
+                            .collect::<Vec<String>>()
+                            .join(", "),
+                    );
+                    lint.note(fluent::lint::suggestion_remove);
+                    lint.note(fluent::lint::no_suggestion_note_escape);
+                }
+                lint
+            },
+        );
     }
 }
 impl EarlyLintPass for HiddenUnicodeCodepoints {
index d8a03024d132334d424361582457a34816612e6c..ed28620fc3619a30ad9a12f06d066a4c6ddc3fd1 100644 (file)
@@ -34,13 +34,16 @@ fn check_path(&mut self, cx: &LateContext<'_>, path: &Path<'_>, hir_id: HirId) {
             Some(sym::HashSet) => "FxHashSet",
             _ => return,
         };
-        cx.struct_span_lint(DEFAULT_HASH_TYPES, path.span, |lint| {
-            lint.build(fluent::lint::default_hash_types)
-                .set_arg("preferred", replace)
-                .set_arg("used", cx.tcx.item_name(def_id))
-                .note(fluent::lint::note)
-                .emit();
-        });
+        cx.struct_span_lint(
+            DEFAULT_HASH_TYPES,
+            path.span,
+            fluent::lint::default_hash_types,
+            |lint| {
+                lint.set_arg("preferred", replace)
+                    .set_arg("used", cx.tcx.item_name(def_id))
+                    .note(fluent::lint::note)
+            },
+        );
     }
 }
 
@@ -80,12 +83,12 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let Ok(Some(instance)) = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs) {
             let def_id = instance.def_id();
             if cx.tcx.has_attr(def_id, sym::rustc_lint_query_instability) {
-                cx.struct_span_lint(POTENTIAL_QUERY_INSTABILITY, span, |lint| {
-                    lint.build(fluent::lint::query_instability)
-                        .set_arg("query", cx.tcx.item_name(def_id))
-                        .note(fluent::lint::note)
-                        .emit();
-                })
+                cx.struct_span_lint(
+                    POTENTIAL_QUERY_INSTABILITY,
+                    span,
+                    fluent::lint::query_instability,
+                    |lint| lint.set_arg("query", cx.tcx.item_name(def_id)).note(fluent::lint::note),
+                )
             }
         }
     }
@@ -123,15 +126,14 @@ fn check_path(
             let span = path.span.with_hi(
                 segment.args.map_or(segment.ident.span, |a| a.span_ext).hi()
             );
-            cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
-                lint.build(fluent::lint::tykind_kind)
+            cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, fluent::lint::tykind_kind, |lint| {
+                lint
                     .span_suggestion(
                         span,
                         fluent::lint::suggestion,
                         "ty",
                         Applicability::MaybeIncorrect, // ty maybe needs an import
                     )
-                    .emit();
             });
         }
     }
@@ -140,76 +142,77 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
         match &ty.kind {
             TyKind::Path(QPath::Resolved(_, path)) => {
                 if lint_ty_kind_usage(cx, &path.res) {
-                    cx.struct_span_lint(USAGE_OF_TY_TYKIND, path.span, |lint| {
-                        let hir = cx.tcx.hir();
-                        match hir.find(hir.get_parent_node(ty.hir_id)) {
-                            Some(Node::Pat(Pat {
-                                kind:
-                                    PatKind::Path(qpath)
-                                    | PatKind::TupleStruct(qpath, ..)
-                                    | PatKind::Struct(qpath, ..),
-                                ..
-                            })) => {
-                                if let QPath::TypeRelative(qpath_ty, ..) = qpath
-                                    && qpath_ty.hir_id == ty.hir_id
-                                {
-                                    lint.build(fluent::lint::tykind_kind)
-                                        .span_suggestion(
-                                            path.span,
-                                            fluent::lint::suggestion,
-                                            "ty",
-                                            Applicability::MaybeIncorrect, // ty maybe needs an import
-                                        )
-                                        .emit();
-                                    return;
-                                }
+                    let hir = cx.tcx.hir();
+                    let span = match hir.find(hir.get_parent_node(ty.hir_id)) {
+                        Some(Node::Pat(Pat {
+                            kind:
+                                PatKind::Path(qpath)
+                                | PatKind::TupleStruct(qpath, ..)
+                                | PatKind::Struct(qpath, ..),
+                            ..
+                        })) => {
+                            if let QPath::TypeRelative(qpath_ty, ..) = qpath
+                                && qpath_ty.hir_id == ty.hir_id
+                            {
+                                Some(path.span)
+                            } else {
+                                None
                             }
-                            Some(Node::Expr(Expr {
-                                kind: ExprKind::Path(qpath),
-                                ..
-                            })) => {
-                                if let QPath::TypeRelative(qpath_ty, ..) = qpath
-                                    && qpath_ty.hir_id == ty.hir_id
-                                {
-                                    lint.build(fluent::lint::tykind_kind)
-                                        .span_suggestion(
-                                            path.span,
-                                            fluent::lint::suggestion,
-                                            "ty",
-                                            Applicability::MaybeIncorrect, // ty maybe needs an import
-                                        )
-                                        .emit();
-                                    return;
-                                }
+                        }
+                        Some(Node::Expr(Expr {
+                            kind: ExprKind::Path(qpath),
+                            ..
+                        })) => {
+                            if let QPath::TypeRelative(qpath_ty, ..) = qpath
+                                && qpath_ty.hir_id == ty.hir_id
+                            {
+                                Some(path.span)
+                            } else {
+                                None
                             }
-                            // Can't unify these two branches because qpath below is `&&` and above is `&`
-                            // and `A | B` paths don't play well together with adjustments, apparently.
-                            Some(Node::Expr(Expr {
-                                kind: ExprKind::Struct(qpath, ..),
-                                ..
-                            })) => {
-                                if let QPath::TypeRelative(qpath_ty, ..) = qpath
-                                    && qpath_ty.hir_id == ty.hir_id
-                                {
-                                    lint.build(fluent::lint::tykind_kind)
-                                        .span_suggestion(
-                                            path.span,
-                                            fluent::lint::suggestion,
-                                            "ty",
-                                            Applicability::MaybeIncorrect, // ty maybe needs an import
-                                        )
-                                        .emit();
-                                    return;
-                                }
+                        }
+                        // Can't unify these two branches because qpath below is `&&` and above is `&`
+                        // and `A | B` paths don't play well together with adjustments, apparently.
+                        Some(Node::Expr(Expr {
+                            kind: ExprKind::Struct(qpath, ..),
+                            ..
+                        })) => {
+                            if let QPath::TypeRelative(qpath_ty, ..) = qpath
+                                && qpath_ty.hir_id == ty.hir_id
+                            {
+                                Some(path.span)
+                            } else {
+                                None
                             }
-                            _ => {}
                         }
-                        lint.build(fluent::lint::tykind).help(fluent::lint::help).emit();
-                    })
+                        _ => None
+                    };
+
+                    match span {
+                        Some(span) => {
+                            cx.struct_span_lint(
+                                USAGE_OF_TY_TYKIND,
+                                path.span,
+                                fluent::lint::tykind_kind,
+                                |lint| lint.span_suggestion(
+                                    span,
+                                    fluent::lint::suggestion,
+                                    "ty",
+                                    Applicability::MaybeIncorrect, // ty maybe needs an import
+                                )
+                            )
+                        },
+                        None => cx.struct_span_lint(
+                            USAGE_OF_TY_TYKIND,
+                            path.span,
+                            fluent::lint::tykind,
+                            |lint| lint.help(fluent::lint::help)
+                        )
+                    }
                 } else if !ty.span.from_expansion() && let Some(t) = is_ty_or_ty_ctxt(cx, &path) {
                     if path.segments.len() > 1 {
-                        cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, |lint| {
-                            lint.build(fluent::lint::ty_qualified)
+                        cx.struct_span_lint(USAGE_OF_QUALIFIED_TY, path.span, fluent::lint::ty_qualified, |lint| {
+                            lint
                                 .set_arg("ty", t.clone())
                                 .span_suggestion(
                                     path.span,
@@ -218,7 +221,6 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx Ty<'tcx>) {
                                     // The import probably needs to be changed
                                     Applicability::MaybeIncorrect,
                                 )
-                                .emit();
                         })
                     }
                 }
@@ -308,11 +310,8 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
                         cx.struct_span_lint(
                             LINT_PASS_IMPL_WITHOUT_MACRO,
                             lint_pass.path.span,
-                            |lint| {
-                                lint.build(fluent::lint::lintpass_by_hand)
-                                    .help(fluent::lint::help)
-                                    .emit();
-                            },
+                            fluent::lint::lintpass_by_hand,
+                            |lint| lint.help(fluent::lint::help),
                         )
                     }
                 }
@@ -349,12 +348,12 @@ fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
                         if is_doc_keyword(v) {
                             return;
                         }
-                        cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| {
-                            lint.build(fluent::lint::non_existant_doc_keyword)
-                                .set_arg("keyword", v)
-                                .help(fluent::lint::help)
-                                .emit();
-                        });
+                        cx.struct_span_lint(
+                            EXISTING_DOC_KEYWORD,
+                            attr.span,
+                            fluent::lint::non_existant_doc_keyword,
+                            |lint| lint.set_arg("keyword", v).help(fluent::lint::help),
+                        );
                     }
                 }
             }
@@ -412,9 +411,12 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         }
         debug!(?found_impl);
         if !found_parent_with_attr && !found_impl {
-            cx.struct_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, |lint| {
-                lint.build(fluent::lint::diag_out_of_impl).emit();
-            })
+            cx.struct_span_lint(
+                DIAGNOSTIC_OUTSIDE_OF_IMPL,
+                span,
+                fluent::lint::diag_out_of_impl,
+                |lint| lint,
+            )
         }
 
         let mut found_diagnostic_message = false;
@@ -430,9 +432,12 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
         }
         debug!(?found_diagnostic_message);
         if !found_parent_with_attr && !found_diagnostic_message {
-            cx.struct_span_lint(UNTRANSLATABLE_DIAGNOSTIC, span, |lint| {
-                lint.build(fluent::lint::untranslatable_diag).emit();
-            })
+            cx.struct_span_lint(
+                UNTRANSLATABLE_DIAGNOSTIC,
+                span,
+                fluent::lint::untranslatable_diag,
+                |lint| lint,
+            )
         }
     }
 }
@@ -464,8 +469,8 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
                 let Some(literal) = item.literal()  &&
                 let ast::LitKind::Str(val, _) = literal.kind
             {
-                cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, |lint| {
-                    lint.build(val.as_str()).emit(); }
+                cx.struct_span_lint(BAD_OPT_ACCESS, expr.span, val.as_str(), |lint|
+                    lint
                 );
             }
         }
index 7e885e6c51aad42261b5da1eeb11ee618712875c..78f355ec3d0ae309716db0b02da3e1dc1e0161c0 100644 (file)
@@ -1,5 +1,5 @@
 use crate::{LateContext, LateLintPass, LintContext};
-use rustc_errors::{Applicability, LintDiagnosticBuilder, MultiSpan};
+use rustc_errors::{Applicability, DiagnosticBuilder, MultiSpan};
 use rustc_hir as hir;
 use rustc_middle::ty;
 use rustc_span::Symbol;
@@ -128,48 +128,41 @@ fn check_local(&mut self, cx: &LateContext<'_>, local: &hir::Local<'_>) {
                     init.span,
                     "this binding will immediately drop the value assigned to it".to_string(),
                 );
-                cx.struct_span_lint(LET_UNDERSCORE_LOCK, span, |lint| {
-                    build_and_emit_lint(
-                        lint,
-                        local,
-                        init.span,
-                        "non-binding let on a synchronization lock",
-                    )
-                })
+                cx.struct_span_lint(
+                    LET_UNDERSCORE_LOCK,
+                    span,
+                    "non-binding let on a synchronization lock",
+                    |lint| build_lint(lint, local, init.span),
+                )
             } else {
-                cx.struct_span_lint(LET_UNDERSCORE_DROP, local.span, |lint| {
-                    build_and_emit_lint(
-                        lint,
-                        local,
-                        init.span,
-                        "non-binding let on a type that implements `Drop`",
-                    );
-                })
+                cx.struct_span_lint(
+                    LET_UNDERSCORE_DROP,
+                    local.span,
+                    "non-binding let on a type that implements `Drop`",
+                    |lint| build_lint(lint, local, init.span),
+                )
             }
         }
     }
 }
 
-fn build_and_emit_lint(
-    lint: LintDiagnosticBuilder<'_, ()>,
+fn build_lint<'a, 'b>(
+    lint: &'a mut DiagnosticBuilder<'b, ()>,
     local: &hir::Local<'_>,
     init_span: rustc_span::Span,
-    msg: &str,
-) {
-    lint.build(msg)
-        .span_suggestion_verbose(
-            local.pat.span,
-            "consider binding to an unused variable to avoid immediately dropping the value",
-            "_unused",
-            Applicability::MachineApplicable,
-        )
-        .multipart_suggestion(
-            "consider immediately dropping the value",
-            vec![
-                (local.span.until(init_span), "drop(".to_string()),
-                (init_span.shrink_to_hi(), ")".to_string()),
-            ],
-            Applicability::MachineApplicable,
-        )
-        .emit();
+) -> &'a mut DiagnosticBuilder<'b, ()> {
+    lint.span_suggestion_verbose(
+        local.pat.span,
+        "consider binding to an unused variable to avoid immediately dropping the value",
+        "_unused",
+        Applicability::MachineApplicable,
+    )
+    .multipart_suggestion(
+        "consider immediately dropping the value",
+        vec![
+            (local.span.until(init_span), "drop(".to_string()),
+            (init_span.shrink_to_hi(), ")".to_string()),
+        ],
+        Applicability::MachineApplicable,
+    )
 }
index 1e16ac51e9e5de807f6178de339e694c8f2b006d..8238235082381729518cc1148b5742fc5e42d6ea 100644 (file)
@@ -3,7 +3,7 @@
 use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{Applicability, Diagnostic, LintDiagnosticBuilder, MultiSpan};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::{intravisit, HirId};
 use rustc_middle::hir::nested_filter;
@@ -214,14 +214,14 @@ fn insert_spec(&mut self, id: LintId, (level, src): LevelAndSource) {
                     self.struct_lint(
                         FORBIDDEN_LINT_GROUPS,
                         Some(src.span().into()),
-                        |diag_builder| {
-                            let mut diag_builder = diag_builder.build(&format!(
-                                "{}({}) incompatible with previous forbid",
-                                level.as_str(),
-                                src.name(),
-                            ));
-                            decorate_diag(&mut diag_builder);
-                            diag_builder.emit();
+                        format!(
+                            "{}({}) incompatible with previous forbid",
+                            level.as_str(),
+                            src.name(),
+                        ),
+                        |lint| {
+                            decorate_diag(lint);
+                            lint
                         },
                     );
                 }
@@ -466,20 +466,18 @@ pub(crate) fn push(
                                     lvl,
                                     src,
                                     Some(sp.into()),
+                                    format!(
+                                        "lint name `{}` is deprecated \
+                                         and may not have an effect in the future.",
+                                        name
+                                    ),
                                     |lint| {
-                                        let msg = format!(
-                                            "lint name `{}` is deprecated \
-                                             and may not have an effect in the future.",
-                                            name
-                                        );
-                                        lint.build(&msg)
-                                            .span_suggestion(
-                                                sp,
-                                                "change it to",
-                                                new_lint_name,
-                                                Applicability::MachineApplicable,
-                                            )
-                                            .emit();
+                                        lint.span_suggestion(
+                                            sp,
+                                            "change it to",
+                                            new_lint_name,
+                                            Applicability::MachineApplicable,
+                                        )
                                     },
                                 );
 
@@ -533,17 +531,17 @@ pub(crate) fn push(
                             renamed_lint_level,
                             src,
                             Some(sp.into()),
+                            msg,
                             |lint| {
-                                let mut err = lint.build(msg);
                                 if let Some(new_name) = &renamed {
-                                    err.span_suggestion(
+                                    lint.span_suggestion(
                                         sp,
                                         "use the new name",
                                         new_name,
                                         Applicability::MachineApplicable,
                                     );
                                 }
-                                err.emit();
+                                lint
                             },
                         );
                     }
@@ -555,23 +553,30 @@ pub(crate) fn push(
                             Some(self.current_specs()),
                             self.sess,
                         );
-                        struct_lint_level(self.sess, lint, level, src, Some(sp.into()), |lint| {
-                            let name = if let Some(tool_ident) = tool_ident {
-                                format!("{}::{}", tool_ident.name, name)
-                            } else {
-                                name.to_string()
-                            };
-                            let mut db = lint.build(format!("unknown lint: `{}`", name));
-                            if let Some(suggestion) = suggestion {
-                                db.span_suggestion(
-                                    sp,
-                                    "did you mean",
-                                    suggestion,
-                                    Applicability::MachineApplicable,
-                                );
-                            }
-                            db.emit();
-                        });
+                        let name = if let Some(tool_ident) = tool_ident {
+                            format!("{}::{}", tool_ident.name, name)
+                        } else {
+                            name.to_string()
+                        };
+                        struct_lint_level(
+                            self.sess,
+                            lint,
+                            level,
+                            src,
+                            Some(sp.into()),
+                            format!("unknown lint: `{}`", name),
+                            |lint| {
+                                if let Some(suggestion) = suggestion {
+                                    lint.span_suggestion(
+                                        sp,
+                                        "did you mean",
+                                        suggestion,
+                                        Applicability::MachineApplicable,
+                                    );
+                                }
+                                lint
+                            },
+                        );
                     }
                 }
                 // If this lint was renamed, apply the new lint instead of ignoring the attribute.
@@ -621,14 +626,12 @@ pub(crate) fn push(
                     lint_level,
                     lint_src,
                     Some(lint_attr_span.into()),
-                    |lint| {
-                        let mut db = lint.build(&format!(
-                            "{}({}) is ignored unless specified at crate level",
-                            level.as_str(),
-                            lint_attr_name
-                        ));
-                        db.emit();
-                    },
+                    format!(
+                        "{}({}) is ignored unless specified at crate level",
+                        level.as_str(),
+                        lint_attr_name
+                    ),
+                    |lint| lint,
                 );
                 // don't set a separate error for every lint in the group
                 break;
@@ -665,13 +668,21 @@ fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool {
             if !self.sess.features_untracked().enabled(feature) {
                 let lint = builtin::UNKNOWN_LINTS;
                 let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
-                struct_lint_level(self.sess, lint, level, src, Some(span.into()), |lint_db| {
-                    let mut db =
-                        lint_db.build(&format!("unknown lint: `{}`", lint_id.lint.name_lower()));
-                    db.note(&format!("the `{}` lint is unstable", lint_id.lint.name_lower(),));
-                    add_feature_diagnostics(&mut db, &self.sess.parse_sess, feature);
-                    db.emit();
-                });
+                struct_lint_level(
+                    self.sess,
+                    lint,
+                    level,
+                    src,
+                    Some(span.into()),
+                    format!("unknown lint: `{}`", lint_id.lint.name_lower()),
+                    |lint| {
+                        lint.note(
+                            &format!("the `{}` lint is unstable", lint_id.lint.name_lower(),),
+                        );
+                        add_feature_diagnostics(lint, &self.sess.parse_sess, feature);
+                        lint
+                    },
+                );
                 return false;
             }
         }
@@ -694,10 +705,13 @@ pub fn struct_lint(
         &self,
         lint: &'static Lint,
         span: Option<MultiSpan>,
-        decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+        msg: impl Into<DiagnosticMessage>,
+        decorate: impl for<'a, 'b> FnOnce(
+            &'b mut DiagnosticBuilder<'a, ()>,
+        ) -> &'b mut DiagnosticBuilder<'a, ()>,
     ) {
         let (level, src) = self.lint_level(lint);
-        struct_lint_level(self.sess, lint, level, src, span, decorate)
+        struct_lint_level(self.sess, lint, level, src, span, msg, decorate)
     }
 
     /// Registers the ID provided with the current set of lints stored in
index 5f7f03480c043b07e58815012b35ff2b8418705c..313119637bc9c1a10686797a1d1ae43d1524bfca 100644 (file)
@@ -90,14 +90,17 @@ fn lint_cstring_as_ptr(
         if cx.tcx.is_diagnostic_item(sym::Result, def.did()) {
             if let ty::Adt(adt, _) = substs.type_at(0).kind() {
                 if cx.tcx.is_diagnostic_item(sym::cstring_type, adt.did()) {
-                    cx.struct_span_lint(TEMPORARY_CSTRING_AS_PTR, as_ptr_span, |diag| {
-                        diag.build(fluent::lint::cstring_ptr)
-                            .span_label(as_ptr_span, fluent::lint::as_ptr_label)
-                            .span_label(unwrap.span, fluent::lint::unwrap_label)
-                            .note(fluent::lint::note)
-                            .help(fluent::lint::help)
-                            .emit();
-                    });
+                    cx.struct_span_lint(
+                        TEMPORARY_CSTRING_AS_PTR,
+                        as_ptr_span,
+                        fluent::lint::cstring_ptr,
+                        |diag| {
+                            diag.span_label(as_ptr_span, fluent::lint::as_ptr_label)
+                                .span_label(unwrap.span, fluent::lint::unwrap_label)
+                                .note(fluent::lint::note)
+                                .help(fluent::lint::help)
+                        },
+                    );
                 }
             }
         }
index 764003e61a6dfb0991ee2c5c4c143417015fc0df..b2626efb6d73a901fec3b333fc14cb15bd8f5472 100644 (file)
@@ -180,15 +180,21 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
                 continue;
             }
             has_non_ascii_idents = true;
-            cx.struct_span_lint(NON_ASCII_IDENTS, sp, |lint| {
-                lint.build(fluent::lint::identifier_non_ascii_char).emit();
-            });
+            cx.struct_span_lint(
+                NON_ASCII_IDENTS,
+                sp,
+                fluent::lint::identifier_non_ascii_char,
+                |lint| lint,
+            );
             if check_uncommon_codepoints
                 && !symbol_str.chars().all(GeneralSecurityProfile::identifier_allowed)
             {
-                cx.struct_span_lint(UNCOMMON_CODEPOINTS, sp, |lint| {
-                    lint.build(fluent::lint::identifier_uncommon_codepoints).emit();
-                })
+                cx.struct_span_lint(
+                    UNCOMMON_CODEPOINTS,
+                    sp,
+                    fluent::lint::identifier_uncommon_codepoints,
+                    |lint| lint,
+                )
             }
         }
 
@@ -216,13 +222,16 @@ fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
                     .entry(skeleton_sym)
                     .and_modify(|(existing_symbol, existing_span, existing_is_ascii)| {
                         if !*existing_is_ascii || !is_ascii {
-                            cx.struct_span_lint(CONFUSABLE_IDENTS, sp, |lint| {
-                                lint.build(fluent::lint::confusable_identifier_pair)
-                                    .set_arg("existing_sym", *existing_symbol)
-                                    .set_arg("sym", symbol)
-                                    .span_label(*existing_span, fluent::lint::label)
-                                    .emit();
-                            });
+                            cx.struct_span_lint(
+                                CONFUSABLE_IDENTS,
+                                sp,
+                                fluent::lint::confusable_identifier_pair,
+                                |lint| {
+                                    lint.set_arg("existing_sym", *existing_symbol)
+                                        .set_arg("sym", symbol)
+                                        .span_label(*existing_span, fluent::lint::label)
+                                },
+                            );
                         }
                         if *existing_is_ascii && !is_ascii {
                             *existing_symbol = symbol;
@@ -322,22 +331,25 @@ enum ScriptSetUsage {
                 }
 
                 for ((sp, ch_list), script_set) in lint_reports {
-                    cx.struct_span_lint(MIXED_SCRIPT_CONFUSABLES, sp, |lint| {
-                        let mut includes = String::new();
-                        for (idx, ch) in ch_list.into_iter().enumerate() {
-                            if idx != 0 {
-                                includes += ", ";
+                    cx.struct_span_lint(
+                        MIXED_SCRIPT_CONFUSABLES,
+                        sp,
+                        fluent::lint::mixed_script_confusables,
+                        |lint| {
+                            let mut includes = String::new();
+                            for (idx, ch) in ch_list.into_iter().enumerate() {
+                                if idx != 0 {
+                                    includes += ", ";
+                                }
+                                let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
+                                includes += &char_info;
                             }
-                            let char_info = format!("'{}' (U+{:04X})", ch, ch as u32);
-                            includes += &char_info;
-                        }
-                        lint.build(fluent::lint::mixed_script_confusables)
-                            .set_arg("set", script_set.to_string())
-                            .set_arg("includes", includes)
-                            .note(fluent::lint::includes_note)
-                            .note(fluent::lint::note)
-                            .emit();
-                    });
+                            lint.set_arg("set", script_set.to_string())
+                                .set_arg("includes", includes)
+                                .note(fluent::lint::includes_note)
+                                .note(fluent::lint::note)
+                        },
+                    );
                 }
             }
         }
index cdad2d2e8f93e0d4bb18fa0c53032ef7bb085bfb..9d2a23f2b5fb644bfb1792556c9c898c74919528 100644 (file)
@@ -119,21 +119,19 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
         arg_span = expn.call_site;
     }
 
-    cx.struct_span_lint(NON_FMT_PANICS, arg_span, |lint| {
-        let mut l = lint.build(fluent::lint::non_fmt_panic);
-        l.set_arg("name", symbol);
-        l.note(fluent::lint::note);
-        l.note(fluent::lint::more_info_note);
+    cx.struct_span_lint(NON_FMT_PANICS, arg_span, fluent::lint::non_fmt_panic, |lint| {
+        lint.set_arg("name", symbol);
+        lint.note(fluent::lint::note);
+        lint.note(fluent::lint::more_info_note);
         if !is_arg_inside_call(arg_span, span) {
             // No clue where this argument is coming from.
-            l.emit();
-            return;
+            return lint;
         }
         if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
             // A case of `panic!(format!(..))`.
-            l.note(fluent::lint::supports_fmt_note);
+            lint.note(fluent::lint::supports_fmt_note);
             if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
-                l.multipart_suggestion(
+                lint.multipart_suggestion(
                     fluent::lint::supports_fmt_suggestion,
                     vec![
                         (arg_span.until(open.shrink_to_hi()), "".into()),
@@ -180,15 +178,15 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
             };
 
             if suggest_display {
-                l.span_suggestion_verbose(
+                lint.span_suggestion_verbose(
                     arg_span.shrink_to_lo(),
                     fluent::lint::display_suggestion,
                     "\"{}\", ",
                     fmt_applicability,
                 );
             } else if suggest_debug {
-                l.set_arg("ty", ty);
-                l.span_suggestion_verbose(
+                lint.set_arg("ty", ty);
+                lint.span_suggestion_verbose(
                     arg_span.shrink_to_lo(),
                     fluent::lint::debug_suggestion,
                     "\"{:?}\", ",
@@ -198,8 +196,8 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
 
             if suggest_panic_any {
                 if let Some((open, close, del)) = find_delimiters(cx, span) {
-                    l.set_arg("already_suggested", suggest_display || suggest_debug);
-                    l.multipart_suggestion(
+                    lint.set_arg("already_suggested", suggest_display || suggest_debug);
+                    lint.multipart_suggestion(
                         fluent::lint::panic_suggestion,
                         if del == '(' {
                             vec![(span.until(open), "std::panic::panic_any".into())]
@@ -214,7 +212,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
                 }
             }
         }
-        l.emit();
+        lint
     });
 }
 
@@ -258,26 +256,30 @@ fn check_panic_str<'tcx>(
                 .map(|span| fmt_span.from_inner(InnerSpan::new(span.start, span.end)))
                 .collect(),
         };
-        cx.struct_span_lint(NON_FMT_PANICS, arg_spans, |lint| {
-            let mut l = lint.build(fluent::lint::non_fmt_panic_unused);
-            l.set_arg("count", n_arguments);
-            l.note(fluent::lint::note);
-            if is_arg_inside_call(arg.span, span) {
-                l.span_suggestion(
-                    arg.span.shrink_to_hi(),
-                    fluent::lint::add_args_suggestion,
-                    ", ...",
-                    Applicability::HasPlaceholders,
-                );
-                l.span_suggestion(
-                    arg.span.shrink_to_lo(),
-                    fluent::lint::add_fmt_suggestion,
-                    "\"{}\", ",
-                    Applicability::MachineApplicable,
-                );
-            }
-            l.emit();
-        });
+        cx.struct_span_lint(
+            NON_FMT_PANICS,
+            arg_spans,
+            fluent::lint::non_fmt_panic_unused,
+            |lint| {
+                lint.set_arg("count", n_arguments);
+                lint.note(fluent::lint::note);
+                if is_arg_inside_call(arg.span, span) {
+                    lint.span_suggestion(
+                        arg.span.shrink_to_hi(),
+                        fluent::lint::add_args_suggestion,
+                        ", ...",
+                        Applicability::HasPlaceholders,
+                    );
+                    lint.span_suggestion(
+                        arg.span.shrink_to_lo(),
+                        fluent::lint::add_fmt_suggestion,
+                        "\"{}\", ",
+                        Applicability::MachineApplicable,
+                    );
+                }
+                lint
+            },
+        );
     } else {
         let brace_spans: Option<Vec<_>> =
             snippet.filter(|s| s.starts_with('"') || s.starts_with("r#")).map(|s| {
@@ -287,20 +289,24 @@ fn check_panic_str<'tcx>(
                     .collect()
             });
         let count = brace_spans.as_ref().map(|v| v.len()).unwrap_or(/* any number >1 */ 2);
-        cx.struct_span_lint(NON_FMT_PANICS, brace_spans.unwrap_or_else(|| vec![span]), |lint| {
-            let mut l = lint.build(fluent::lint::non_fmt_panic_braces);
-            l.set_arg("count", count);
-            l.note(fluent::lint::note);
-            if is_arg_inside_call(arg.span, span) {
-                l.span_suggestion(
-                    arg.span.shrink_to_lo(),
-                    fluent::lint::suggestion,
-                    "\"{}\", ",
-                    Applicability::MachineApplicable,
-                );
-            }
-            l.emit();
-        });
+        cx.struct_span_lint(
+            NON_FMT_PANICS,
+            brace_spans.unwrap_or_else(|| vec![span]),
+            fluent::lint::non_fmt_panic_braces,
+            |lint| {
+                lint.set_arg("count", count);
+                lint.note(fluent::lint::note);
+                if is_arg_inside_call(arg.span, span) {
+                    lint.span_suggestion(
+                        arg.span.shrink_to_lo(),
+                        fluent::lint::suggestion,
+                        "\"{}\", ",
+                        Applicability::MachineApplicable,
+                    );
+                }
+                lint
+            },
+        );
     }
 }
 
index 768ad84838b154cb0e8ceebc91d323ab72ca74e5..9f800e9c8c9a19520f9c6852199b4665195ed363 100644 (file)
@@ -136,26 +136,30 @@ fn check_case(&self, cx: &EarlyContext<'_>, sort: &str, ident: &Ident) {
         let name = ident.name.as_str();
 
         if !is_camel_case(name) {
-            cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| {
-                let mut err = lint.build(fluent::lint::non_camel_case_type);
-                let cc = to_camel_case(name);
-                // We cannot provide meaningful suggestions
-                // if the characters are in the category of "Lowercase Letter".
-                if *name != cc {
-                    err.span_suggestion(
-                        ident.span,
-                        fluent::lint::suggestion,
-                        to_camel_case(name),
-                        Applicability::MaybeIncorrect,
-                    );
-                } else {
-                    err.span_label(ident.span, fluent::lint::label);
-                }
+            cx.struct_span_lint(
+                NON_CAMEL_CASE_TYPES,
+                ident.span,
+                fluent::lint::non_camel_case_type,
+                |lint| {
+                    let cc = to_camel_case(name);
+                    // We cannot provide meaningful suggestions
+                    // if the characters are in the category of "Lowercase Letter".
+                    if *name != cc {
+                        lint.span_suggestion(
+                            ident.span,
+                            fluent::lint::suggestion,
+                            to_camel_case(name),
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        lint.span_label(ident.span, fluent::lint::label);
+                    }
 
-                err.set_arg("sort", sort);
-                err.set_arg("name", name);
-                err.emit();
-            })
+                    lint.set_arg("sort", sort);
+                    lint.set_arg("name", name);
+                    lint
+                },
+            )
         }
     }
 }
@@ -280,9 +284,8 @@ fn is_snake_case(ident: &str) -> bool {
         let name = ident.name.as_str();
 
         if !is_snake_case(name) {
-            cx.struct_span_lint(NON_SNAKE_CASE, ident.span, |lint| {
+            cx.struct_span_lint(NON_SNAKE_CASE, ident.span, fluent::lint::non_snake_case, |lint| {
                 let sc = NonSnakeCase::to_snake_case(name);
-                let mut err = lint.build(fluent::lint::non_snake_case);
                 // We cannot provide meaningful suggestions
                 // if the characters are in the category of "Uppercase Letter".
                 if name != sc {
@@ -297,30 +300,30 @@ fn is_snake_case(ident: &str) -> bool {
                             if sc_ident.name.can_be_raw() {
                                 (fluent::lint::rename_or_convert_suggestion, sc_ident.to_string())
                             } else {
-                                err.note(fluent::lint::cannot_convert_note);
+                                lint.note(fluent::lint::cannot_convert_note);
                                 (fluent::lint::rename_suggestion, String::new())
                             }
                         } else {
                             (fluent::lint::convert_suggestion, sc.clone())
                         };
 
-                        err.span_suggestion(
+                        lint.span_suggestion(
                             ident.span,
                             message,
                             suggestion,
                             Applicability::MaybeIncorrect,
                         );
                     } else {
-                        err.help(fluent::lint::help);
+                        lint.help(fluent::lint::help);
                     }
                 } else {
-                    err.span_label(ident.span, fluent::lint::label);
+                    lint.span_label(ident.span, fluent::lint::label);
                 }
 
-                err.set_arg("sort", sort);
-                err.set_arg("name", name);
-                err.set_arg("sc", sc);
-                err.emit();
+                lint.set_arg("sort", sort);
+                lint.set_arg("name", name);
+                lint.set_arg("sc", sc);
+                lint
             });
         }
     }
@@ -478,26 +481,30 @@ impl NonUpperCaseGlobals {
     fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &Ident) {
         let name = ident.name.as_str();
         if name.chars().any(|c| c.is_lowercase()) {
-            cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| {
-                let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
-                let mut err = lint.build(fluent::lint::non_upper_case_global);
-                // We cannot provide meaningful suggestions
-                // if the characters are in the category of "Lowercase Letter".
-                if *name != uc {
-                    err.span_suggestion(
-                        ident.span,
-                        fluent::lint::suggestion,
-                        uc,
-                        Applicability::MaybeIncorrect,
-                    );
-                } else {
-                    err.span_label(ident.span, fluent::lint::label);
-                }
+            cx.struct_span_lint(
+                NON_UPPER_CASE_GLOBALS,
+                ident.span,
+                fluent::lint::non_upper_case_global,
+                |lint| {
+                    let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
+                    // We cannot provide meaningful suggestions
+                    // if the characters are in the category of "Lowercase Letter".
+                    if *name != uc {
+                        lint.span_suggestion(
+                            ident.span,
+                            fluent::lint::suggestion,
+                            uc,
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        lint.span_label(ident.span, fluent::lint::label);
+                    }
 
-                err.set_arg("sort", sort);
-                err.set_arg("name", name);
-                err.emit();
-            })
+                    lint.set_arg("sort", sort);
+                    lint.set_arg("name", name);
+                    lint
+                },
+            )
         }
     }
 }
index d1449496d331578be434f7053145359d05767316..19188d5c376513a418f392aee7f8baa4c7d4de38 100644 (file)
@@ -90,13 +90,11 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         }
         let expr_span = expr.span;
         let span = expr_span.with_lo(receiver.span.hi());
-        cx.struct_span_lint(NOOP_METHOD_CALL, span, |lint| {
-            lint.build(fluent::lint::noop_method_call)
-                .set_arg("method", call.ident.name)
+        cx.struct_span_lint(NOOP_METHOD_CALL, span, fluent::lint::noop_method_call, |lint| {
+            lint.set_arg("method", call.ident.name)
                 .set_arg("receiver_ty", receiver_ty)
                 .span_label(span, fluent::lint::label)
                 .note(fluent::lint::note)
-                .emit();
         });
     }
 }
index af5e5faf1f568aef60d44de98c57acafe0b69615..7e5a20a3bc16a87401294374dadc12b1861e9792 100644 (file)
@@ -29,18 +29,20 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
                     }
                 }
                 if let Some(t) = path_for_pass_by_value(cx, &inner_ty) {
-                    cx.struct_span_lint(PASS_BY_VALUE, ty.span, |lint| {
-                        lint.build(fluent::lint::pass_by_value)
-                            .set_arg("ty", t.clone())
-                            .span_suggestion(
+                    cx.struct_span_lint(
+                        PASS_BY_VALUE,
+                        ty.span,
+                        fluent::lint::pass_by_value,
+                        |lint| {
+                            lint.set_arg("ty", t.clone()).span_suggestion(
                                 ty.span,
                                 fluent::lint::suggestion,
                                 t,
                                 // Changing type of function argument
                                 Applicability::MaybeIncorrect,
                             )
-                            .emit();
-                    })
+                        },
+                    )
                 }
             }
             _ => {}
index 26f41345383f91bad2218eca90e7048bd5385a51..46c84550e9f5f758b5be45d31fa13044b6b9d35f 100644 (file)
@@ -48,11 +48,18 @@ fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, boo
             return;
         }
 
-        cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| {
-            lint.build(fluent::lint::redundant_semicolons)
-                .set_arg("multiple", multiple)
-                .span_suggestion(span, fluent::lint::suggestion, "", Applicability::MaybeIncorrect)
-                .emit();
-        });
+        cx.struct_span_lint(
+            REDUNDANT_SEMICOLONS,
+            span,
+            fluent::lint::redundant_semicolons,
+            |lint| {
+                lint.set_arg("multiple", multiple).span_suggestion(
+                    span,
+                    fluent::lint::suggestion,
+                    "",
+                    Applicability::MaybeIncorrect,
+                )
+            },
+        );
     }
 }
index df1587c5948f58d4cf984e48e852f2cb65f3bc22..078465bdce675548f132ce4aa32cd162fba03f02 100644 (file)
@@ -100,15 +100,18 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
                 if trait_predicate.trait_ref.self_ty().is_impl_trait() {
                     continue;
                 }
-                cx.struct_span_lint(DROP_BOUNDS, span, |lint| {
-                    let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
-                        return
-                    };
-                    lint.build(fluent::lint::drop_trait_constraints)
-                        .set_arg("predicate", predicate)
-                        .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
-                        .emit();
-                });
+                let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
+                    continue;
+                };
+                cx.struct_span_lint(
+                    DROP_BOUNDS,
+                    span,
+                    fluent::lint::drop_trait_constraints,
+                    |lint| {
+                        lint.set_arg("predicate", predicate)
+                            .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
+                    },
+                );
             }
         }
     }
@@ -119,14 +122,11 @@ fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx>) {
         };
         for bound in &bounds[..] {
             let def_id = bound.trait_ref.trait_def_id();
-            if cx.tcx.lang_items().drop_trait() == def_id {
-                cx.struct_span_lint(DYN_DROP, bound.span, |lint| {
-                    let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop) else {
-                        return
-                    };
-                    lint.build(fluent::lint::drop_glue)
-                        .set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
-                        .emit();
+            if cx.tcx.lang_items().drop_trait() == def_id
+                && let Some(needs_drop) = cx.tcx.get_diagnostic_item(sym::needs_drop)
+            {
+                cx.struct_span_lint(DYN_DROP, bound.span, fluent::lint::drop_glue, |lint| {
+                    lint.set_arg("needs_drop", cx.tcx.def_path_str(needs_drop))
                 });
             }
         }
index 4fb6d65a6e98f4f86db64f3975bc73a5809fe042..b6009bd800a5f1b66d05b7f748b835cff5cccd7e 100644 (file)
@@ -144,12 +144,18 @@ fn lint_overflowing_range_endpoint<'tcx>(
     // We can suggest using an inclusive range
     // (`..=`) instead only if it is the `end` that is
     // overflowing and only by 1.
-    if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max {
-        cx.struct_span_lint(OVERFLOWING_LITERALS, struct_expr.span, |lint| {
-            let mut err = lint.build(fluent::lint::range_endpoint_out_of_range);
-            err.set_arg("ty", ty);
-            if let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span) {
+    if eps[1].expr.hir_id == expr.hir_id && lit_val - 1 == max
+        && let Ok(start) = cx.sess().source_map().span_to_snippet(eps[0].span)
+    {
+        cx.struct_span_lint(
+            OVERFLOWING_LITERALS,
+            struct_expr.span,
+            fluent::lint::range_endpoint_out_of_range,
+            |lint| {
                 use ast::{LitIntType, LitKind};
+
+                lint.set_arg("ty", ty);
+
                 // We need to preserve the literal's suffix,
                 // as it may determine typing information.
                 let suffix = match lit.node {
@@ -159,16 +165,17 @@ fn lint_overflowing_range_endpoint<'tcx>(
                     _ => bug!(),
                 };
                 let suggestion = format!("{}..={}{}", start, lit_val - 1, suffix);
-                err.span_suggestion(
+                lint.span_suggestion(
                     struct_expr.span,
                     fluent::lint::suggestion,
                     suggestion,
                     Applicability::MachineApplicable,
                 );
-                err.emit();
                 overwritten = true;
-            }
-        });
+
+                lint
+            },
+        );
     }
     overwritten
 }
@@ -221,52 +228,58 @@ fn report_bin_hex_error(
     negative: bool,
 ) {
     let size = Integer::from_attr(&cx.tcx, ty).size();
-    cx.struct_span_lint(OVERFLOWING_LITERALS, expr.span, |lint| {
-        let (t, actually) = match ty {
-            attr::IntType::SignedInt(t) => {
-                let actually = if negative {
-                    -(size.sign_extend(val) as i128)
-                } else {
-                    size.sign_extend(val) as i128
-                };
-                (t.name_str(), actually.to_string())
-            }
-            attr::IntType::UnsignedInt(t) => {
-                let actually = size.truncate(val);
-                (t.name_str(), actually.to_string())
-            }
-        };
-        let mut err = lint.build(fluent::lint::overflowing_bin_hex);
-        if negative {
-            // If the value is negative,
-            // emits a note about the value itself, apart from the literal.
-            err.note(fluent::lint::negative_note);
-            err.note(fluent::lint::negative_becomes_note);
-        } else {
-            err.note(fluent::lint::positive_note);
-        }
-        if let Some(sugg_ty) =
-            get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
-        {
-            err.set_arg("suggestion_ty", sugg_ty);
-            if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
-                let (sans_suffix, _) = repr_str.split_at(pos);
-                err.span_suggestion(
-                    expr.span,
-                    fluent::lint::suggestion,
-                    format!("{}{}", sans_suffix, sugg_ty),
-                    Applicability::MachineApplicable,
-                );
+    cx.struct_span_lint(
+        OVERFLOWING_LITERALS,
+        expr.span,
+        fluent::lint::overflowing_bin_hex,
+        |lint| {
+            let (t, actually) = match ty {
+                attr::IntType::SignedInt(t) => {
+                    let actually = if negative {
+                        -(size.sign_extend(val) as i128)
+                    } else {
+                        size.sign_extend(val) as i128
+                    };
+                    (t.name_str(), actually.to_string())
+                }
+                attr::IntType::UnsignedInt(t) => {
+                    let actually = size.truncate(val);
+                    (t.name_str(), actually.to_string())
+                }
+            };
+
+            if negative {
+                // If the value is negative,
+                // emits a note about the value itself, apart from the literal.
+                lint.note(fluent::lint::negative_note);
+                lint.note(fluent::lint::negative_becomes_note);
             } else {
-                err.help(fluent::lint::help);
+                lint.note(fluent::lint::positive_note);
             }
-        }
-        err.set_arg("ty", t);
-        err.set_arg("lit", repr_str);
-        err.set_arg("dec", val);
-        err.set_arg("actually", actually);
-        err.emit();
-    });
+            if let Some(sugg_ty) =
+                get_type_suggestion(cx.typeck_results().node_type(expr.hir_id), val, negative)
+            {
+                lint.set_arg("suggestion_ty", sugg_ty);
+                if let Some(pos) = repr_str.chars().position(|c| c == 'i' || c == 'u') {
+                    let (sans_suffix, _) = repr_str.split_at(pos);
+                    lint.span_suggestion(
+                        expr.span,
+                        fluent::lint::suggestion,
+                        format!("{}{}", sans_suffix, sugg_ty),
+                        Applicability::MachineApplicable,
+                    );
+                } else {
+                    lint.help(fluent::lint::help);
+                }
+            }
+            lint.set_arg("ty", t)
+                .set_arg("lit", repr_str)
+                .set_arg("dec", val)
+                .set_arg("actually", actually);
+
+            lint
+        },
+    );
 }
 
 // This function finds the next fitting type and generates a suggestion string.
@@ -349,26 +362,27 @@ fn lint_int_literal<'tcx>(
             return;
         }
 
-        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
-            let mut err = lint.build(fluent::lint::overflowing_int);
-            err.set_arg("ty", t.name_str());
-            err.set_arg(
-                "lit",
-                cx.sess()
-                    .source_map()
-                    .span_to_snippet(lit.span)
-                    .expect("must get snippet from literal"),
-            );
-            err.set_arg("min", min);
-            err.set_arg("max", max);
-            err.note(fluent::lint::note);
+        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint::overflowing_int, |lint| {
+            lint.set_arg("ty", t.name_str())
+                .set_arg(
+                    "lit",
+                    cx.sess()
+                        .source_map()
+                        .span_to_snippet(lit.span)
+                        .expect("must get snippet from literal"),
+                )
+                .set_arg("min", min)
+                .set_arg("max", max)
+                .note(fluent::lint::note);
+
             if let Some(sugg_ty) =
                 get_type_suggestion(cx.typeck_results().node_type(e.hir_id), v, negative)
             {
-                err.set_arg("suggestion_ty", sugg_ty);
-                err.help(fluent::lint::help);
+                lint.set_arg("suggestion_ty", sugg_ty);
+                lint.help(fluent::lint::help);
             }
-            err.emit();
+
+            lint
         });
     }
 }
@@ -393,16 +407,19 @@ fn lint_uint_literal<'tcx>(
             match par_e.kind {
                 hir::ExprKind::Cast(..) => {
                     if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
-                        cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| {
-                            lint.build(fluent::lint::only_cast_u8_to_char)
-                                .span_suggestion(
+                        cx.struct_span_lint(
+                            OVERFLOWING_LITERALS,
+                            par_e.span,
+                            fluent::lint::only_cast_u8_to_char,
+                            |lint| {
+                                lint.span_suggestion(
                                     par_e.span,
                                     fluent::lint::suggestion,
                                     format!("'\\u{{{:X}}}'", lit_val),
                                     Applicability::MachineApplicable,
                                 )
-                                .emit();
-                        });
+                            },
+                        );
                         return;
                     }
                 }
@@ -424,9 +441,8 @@ fn lint_uint_literal<'tcx>(
             );
             return;
         }
-        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
-            lint.build(fluent::lint::overflowing_uint)
-                .set_arg("ty", t.name_str())
+        cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, fluent::lint::overflowing_uint, |lint| {
+            lint.set_arg("ty", t.name_str())
                 .set_arg(
                     "lit",
                     cx.sess()
@@ -437,7 +453,6 @@ fn lint_uint_literal<'tcx>(
                 .set_arg("min", min)
                 .set_arg("max", max)
                 .note(fluent::lint::note)
-                .emit();
         });
     }
 }
@@ -467,19 +482,22 @@ fn lint_literal<'tcx>(
                 _ => bug!(),
             };
             if is_infinite == Ok(true) {
-                cx.struct_span_lint(OVERFLOWING_LITERALS, e.span, |lint| {
-                    lint.build(fluent::lint::overflowing_literal)
-                        .set_arg("ty", t.name_str())
-                        .set_arg(
-                            "lit",
-                            cx.sess()
-                                .source_map()
-                                .span_to_snippet(lit.span)
-                                .expect("must get snippet from literal"),
-                        )
-                        .note(fluent::lint::note)
-                        .emit();
-                });
+                cx.struct_span_lint(
+                    OVERFLOWING_LITERALS,
+                    e.span,
+                    fluent::lint::overflowing_literal,
+                    |lint| {
+                        lint.set_arg("ty", t.name_str())
+                            .set_arg(
+                                "lit",
+                                cx.sess()
+                                    .source_map()
+                                    .span_to_snippet(lit.span)
+                                    .expect("must get snippet from literal"),
+                            )
+                            .note(fluent::lint::note)
+                    },
+                );
             }
         }
         _ => {}
@@ -497,9 +515,12 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx hir::Expr<'tcx>) {
             }
             hir::ExprKind::Binary(binop, ref l, ref r) => {
                 if is_comparison(binop) && !check_limits(cx, binop, &l, &r) {
-                    cx.struct_span_lint(UNUSED_COMPARISONS, e.span, |lint| {
-                        lint.build(fluent::lint::unused_comparisons).emit();
-                    });
+                    cx.struct_span_lint(
+                        UNUSED_COMPARISONS,
+                        e.span,
+                        fluent::lint::unused_comparisons,
+                        |lint| lint,
+                    );
                 }
             }
             hir::ExprKind::Lit(ref lit) => lint_literal(cx, self, e, lit),
@@ -1150,25 +1171,24 @@ fn emit_ffi_unsafe_type_lint(
             CItemKind::Definition => IMPROPER_CTYPES_DEFINITIONS,
         };
 
-        self.cx.struct_span_lint(lint, sp, |lint| {
+        self.cx.struct_span_lint(lint, sp, fluent::lint::improper_ctypes, |lint| {
             let item_description = match self.mode {
                 CItemKind::Declaration => "block",
                 CItemKind::Definition => "fn",
             };
-            let mut diag = lint.build(fluent::lint::improper_ctypes);
-            diag.set_arg("ty", ty);
-            diag.set_arg("desc", item_description);
-            diag.span_label(sp, fluent::lint::label);
+            lint.set_arg("ty", ty);
+            lint.set_arg("desc", item_description);
+            lint.span_label(sp, fluent::lint::label);
             if let Some(help) = help {
-                diag.help(help);
+                lint.help(help);
             }
-            diag.note(note);
+            lint.note(note);
             if let ty::Adt(def, _) = ty.kind() {
                 if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did()) {
-                    diag.span_note(sp, fluent::lint::note);
+                    lint.span_note(sp, fluent::lint::note);
                 }
             }
-            diag.emit();
+            lint
         });
     }
 
@@ -1381,11 +1401,8 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
                 cx.struct_span_lint(
                     VARIANT_SIZE_DIFFERENCES,
                     enum_definition.variants[largest_index].span,
-                    |lint| {
-                        lint.build(fluent::lint::variant_size_differences)
-                            .set_arg("largest", largest)
-                            .emit();
-                    },
+                    fluent::lint::variant_size_differences,
+                    |lint| lint.set_arg("largest", largest),
                 );
             }
         }
@@ -1493,25 +1510,16 @@ fn match_ordering(cx: &LateContext<'_>, ord_arg: &Expr<'_>) -> Option<Symbol> {
 
     fn check_atomic_load_store(cx: &LateContext<'_>, expr: &Expr<'_>) {
         if let Some((method, args)) = Self::inherent_atomic_method_call(cx, expr, &[sym::load, sym::store])
-            && let Some((ordering_arg, invalid_ordering)) = match method {
-                sym::load => Some((&args[0], sym::Release)),
-                sym::store => Some((&args[1], sym::Acquire)),
+            && let Some((ordering_arg, invalid_ordering, msg)) = match method {
+                sym::load => Some((&args[0], sym::Release, fluent::lint::atomic_ordering_load)),
+                sym::store => Some((&args[1], sym::Acquire, fluent::lint::atomic_ordering_store)),
                 _ => None,
             }
             && let Some(ordering) = Self::match_ordering(cx, ordering_arg)
             && (ordering == invalid_ordering || ordering == sym::AcqRel)
         {
-            cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, |diag| {
-                if method == sym::load {
-                    diag.build(fluent::lint::atomic_ordering_load)
-                        .help(fluent::lint::help)
-                        .emit()
-                } else {
-                    debug_assert_eq!(method, sym::store);
-                    diag.build(fluent::lint::atomic_ordering_store)
-                        .help(fluent::lint::help)
-                        .emit();
-                }
+            cx.struct_span_lint(INVALID_ATOMIC_ORDERING, ordering_arg.span, msg, |lint| {
+                lint.help(fluent::lint::help)
             });
         }
     }
@@ -1523,10 +1531,9 @@ fn check_memory_fence(cx: &LateContext<'_>, expr: &Expr<'_>) {
             && matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::fence | sym::compiler_fence))
             && Self::match_ordering(cx, &args[0]) == Some(sym::Relaxed)
         {
-            cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, |diag| {
-                diag.build(fluent::lint::atomic_ordering_fence)
+            cx.struct_span_lint(INVALID_ATOMIC_ORDERING, args[0].span, fluent::lint::atomic_ordering_fence, |lint| {
+                lint
                     .help(fluent::lint::help)
-                    .emit();
             });
         }
     }
index 3d426ecbfcb0538a663491077f40e578a80758ee..787c9518b50893165ddd1091ce53b8b230dbf0a3 100644 (file)
@@ -154,9 +154,8 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
         };
 
         if let Some(must_use_op) = must_use_op {
-            cx.struct_span_lint(UNUSED_MUST_USE, expr.span, |lint| {
-                lint.build(fluent::lint::unused_op)
-                    .set_arg("op", must_use_op)
+            cx.struct_span_lint(UNUSED_MUST_USE, expr.span, fluent::lint::unused_op, |lint| {
+                lint.set_arg("op", must_use_op)
                     .span_label(expr.span, fluent::lint::label)
                     .span_suggestion_verbose(
                         expr.span.shrink_to_lo(),
@@ -164,14 +163,13 @@ fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
                         "let _ = ",
                         Applicability::MachineApplicable,
                     )
-                    .emit();
             });
             op_warned = true;
         }
 
         if !(type_permits_lack_of_use || fn_warned || op_warned) {
-            cx.struct_span_lint(UNUSED_RESULTS, s.span, |lint| {
-                lint.build(fluent::lint::unused_result).set_arg("ty", ty).emit();
+            cx.struct_span_lint(UNUSED_RESULTS, s.span, fluent::lint::unused_result, |lint| {
+                lint.set_arg("ty", ty)
             });
         }
 
@@ -267,29 +265,35 @@ fn check_must_use_ty<'tcx>(
                     }
                 },
                 ty::Closure(..) => {
-                    cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
-                        // FIXME(davidtwco): this isn't properly translatable because of the
-                        // pre/post strings
-                        lint.build(fluent::lint::unused_closure)
-                            .set_arg("count", plural_len)
-                            .set_arg("pre", descr_pre)
-                            .set_arg("post", descr_post)
-                            .note(fluent::lint::note)
-                            .emit();
-                    });
+                    cx.struct_span_lint(
+                        UNUSED_MUST_USE,
+                        span,
+                        fluent::lint::unused_closure,
+                        |lint| {
+                            // FIXME(davidtwco): this isn't properly translatable because of the
+                            // pre/post strings
+                            lint.set_arg("count", plural_len)
+                                .set_arg("pre", descr_pre)
+                                .set_arg("post", descr_post)
+                                .note(fluent::lint::note)
+                        },
+                    );
                     true
                 }
                 ty::Generator(..) => {
-                    cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
-                        // FIXME(davidtwco): this isn't properly translatable because of the
-                        // pre/post strings
-                        lint.build(fluent::lint::unused_generator)
-                            .set_arg("count", plural_len)
-                            .set_arg("pre", descr_pre)
-                            .set_arg("post", descr_post)
-                            .note(fluent::lint::note)
-                            .emit();
-                    });
+                    cx.struct_span_lint(
+                        UNUSED_MUST_USE,
+                        span,
+                        fluent::lint::unused_generator,
+                        |lint| {
+                            // FIXME(davidtwco): this isn't properly translatable because of the
+                            // pre/post strings
+                            lint.set_arg("count", plural_len)
+                                .set_arg("pre", descr_pre)
+                                .set_arg("post", descr_post)
+                                .note(fluent::lint::note)
+                        },
+                    );
                     true
                 }
                 _ => false,
@@ -309,18 +313,17 @@ fn check_must_use_def(
             descr_post_path: &str,
         ) -> bool {
             if let Some(attr) = cx.tcx.get_attr(def_id, sym::must_use) {
-                cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
+                cx.struct_span_lint(UNUSED_MUST_USE, span, fluent::lint::unused_def, |lint| {
                     // FIXME(davidtwco): this isn't properly translatable because of the pre/post
                     // strings
-                    let mut err = lint.build(fluent::lint::unused_def);
-                    err.set_arg("pre", descr_pre_path);
-                    err.set_arg("post", descr_post_path);
-                    err.set_arg("def", cx.tcx.def_path_str(def_id));
+                    lint.set_arg("pre", descr_pre_path);
+                    lint.set_arg("post", descr_post_path);
+                    lint.set_arg("def", cx.tcx.def_path_str(def_id));
                     // check for #[must_use = "..."]
                     if let Some(note) = attr.value_str() {
-                        err.note(note.as_str());
+                        lint.note(note.as_str());
                     }
-                    err.emit();
+                    lint
                 });
                 true
             } else {
@@ -357,25 +360,34 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
     fn check_stmt(&mut self, cx: &LateContext<'_>, s: &hir::Stmt<'_>) {
         if let hir::StmtKind::Semi(expr) = s.kind {
             if let hir::ExprKind::Path(_) = expr.kind {
-                cx.struct_span_lint(PATH_STATEMENTS, s.span, |lint| {
-                    let ty = cx.typeck_results().expr_ty(expr);
-                    if ty.needs_drop(cx.tcx, cx.param_env) {
-                        let mut lint = lint.build(fluent::lint::path_statement_drop);
-                        if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
-                            lint.span_suggestion(
-                                s.span,
-                                fluent::lint::suggestion,
-                                format!("drop({});", snippet),
-                                Applicability::MachineApplicable,
-                            );
-                        } else {
-                            lint.span_help(s.span, fluent::lint::suggestion);
-                        }
-                        lint.emit();
-                    } else {
-                        lint.build(fluent::lint::path_statement_no_effect).emit();
-                    }
-                });
+                let ty = cx.typeck_results().expr_ty(expr);
+                if ty.needs_drop(cx.tcx, cx.param_env) {
+                    cx.struct_span_lint(
+                        PATH_STATEMENTS,
+                        s.span,
+                        fluent::lint::path_statement_drop,
+                        |lint| {
+                            if let Ok(snippet) = cx.sess().source_map().span_to_snippet(expr.span) {
+                                lint.span_suggestion(
+                                    s.span,
+                                    fluent::lint::suggestion,
+                                    format!("drop({});", snippet),
+                                    Applicability::MachineApplicable,
+                                );
+                            } else {
+                                lint.span_help(s.span, fluent::lint::suggestion);
+                            }
+                            lint
+                        },
+                    );
+                } else {
+                    cx.struct_span_lint(
+                        PATH_STATEMENTS,
+                        s.span,
+                        fluent::lint::path_statement_no_effect,
+                        |lint| lint,
+                    );
+                }
             }
         }
     }
@@ -545,22 +557,21 @@ fn emit_unused_delims(
         } else {
             MultiSpan::from(value_span)
         };
-        cx.struct_span_lint(self.lint(), primary_span, |lint| {
-            let mut db = lint.build(fluent::lint::unused_delim);
-            db.set_arg("delim", Self::DELIM_STR);
-            db.set_arg("item", msg);
+        cx.struct_span_lint(self.lint(), primary_span, fluent::lint::unused_delim, |lint| {
+            lint.set_arg("delim", Self::DELIM_STR);
+            lint.set_arg("item", msg);
             if let Some((lo, hi)) = spans {
                 let replacement = vec![
                     (lo, if keep_space.0 { " ".into() } else { "".into() }),
                     (hi, if keep_space.1 { " ".into() } else { "".into() }),
                 ];
-                db.multipart_suggestion(
+                lint.multipart_suggestion(
                     fluent::lint::suggestion,
                     replacement,
                     Applicability::MachineApplicable,
                 );
             }
-            db.emit();
+            lint
         });
     }
 
@@ -1128,9 +1139,12 @@ fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &
                 ast::UseTreeKind::Nested(_) => return,
             };
 
-            cx.struct_span_lint(UNUSED_IMPORT_BRACES, item.span, |lint| {
-                lint.build(fluent::lint::unused_import_braces).set_arg("node", node_name).emit();
-            });
+            cx.struct_span_lint(
+                UNUSED_IMPORT_BRACES,
+                item.span,
+                fluent::lint::unused_import_braces,
+                |lint| lint.set_arg("node", node_name),
+            );
         }
     }
 }
@@ -1179,15 +1193,17 @@ fn check_expr(&mut self, cx: &LateContext<'_>, e: &hir::Expr<'_>) {
 
         for adj in cx.typeck_results().expr_adjustments(e) {
             if let adjustment::Adjust::Borrow(adjustment::AutoBorrow::Ref(_, m)) = adj.kind {
-                cx.struct_span_lint(UNUSED_ALLOCATION, e.span, |lint| {
-                    lint.build(match m {
+                cx.struct_span_lint(
+                    UNUSED_ALLOCATION,
+                    e.span,
+                    match m {
                         adjustment::AutoBorrowMutability::Not => fluent::lint::unused_allocation,
                         adjustment::AutoBorrowMutability::Mut { .. } => {
                             fluent::lint::unused_allocation_mut
                         }
-                    })
-                    .emit();
-                });
+                    },
+                    |lint| lint,
+                );
             }
         }
     }
index b9a283552f75f75f526aab5777e17ae1069c0fc2..3a0bd1ba50d3ba4b27f21d1e38558ebee8d8a851 100644 (file)
@@ -96,38 +96,43 @@ pub(crate) fn into_tokens(self) -> TokenStream {
             let body = builder.body(&variant);
 
             let diag = &builder.parent.diag;
-            let init = match builder.slug.value_ref() {
+
+            quote! {
+                #preamble
+                #body
+                #diag
+            }
+        });
+
+        let msg = builder.each_variant(&mut structure, |mut builder, variant| {
+            // HACK(wafflelapkin): initialize slug (???)
+            let _preamble = builder.preamble(&variant);
+
+            match builder.slug.value_ref() {
                 None => {
                     span_err(builder.span, "diagnostic slug not specified")
                         .help(&format!(
                             "specify the slug as the first argument to the attribute, such as \
-                             `#[diag(typeck::example_error)]`",
+                            `#[diag(typeck::example_error)]`",
                         ))
                         .emit();
                     return DiagnosticDeriveError::ErrorHandled.to_compile_error();
                 }
-                Some(slug) => {
-                    quote! {
-                        let mut #diag = #diag.build(rustc_errors::fluent::#slug);
-                    }
-                }
-            };
-
-            quote! {
-                #init
-                #preamble
-                #body
-                #diag.emit();
+                Some(slug) => quote! { rustc_errors::fluent::#slug.into() },
             }
         });
 
         let diag = &builder.diag;
         structure.gen_impl(quote! {
             gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self {
-                fn decorate_lint(self, #diag: rustc_errors::LintDiagnosticBuilder<'__a, ()>) {
+                fn decorate_lint<'__b>(self, #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()>) -> &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> {
                     use rustc_errors::IntoDiagnosticArg;
                     #implementation
                 }
+
+                fn msg(&self) -> rustc_errors::DiagnosticMessage {
+                    #msg
+                }
             }
         })
     }
index 2f45222de47280c6d2b4cea1753cefc53c988a6e..b4fbf3b668ddfd420297743a5e2adc6cff28e0e9 100644 (file)
@@ -2,7 +2,7 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_errors::{Diagnostic, DiagnosticId, LintDiagnosticBuilder, MultiSpan};
+use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, MultiSpan};
 use rustc_hir::HirId;
 use rustc_index::vec::IndexVec;
 use rustc_query_system::ich::StableHashingContext;
@@ -283,7 +283,11 @@ pub fn struct_lint_level<'s, 'd>(
     level: Level,
     src: LintLevelSource,
     span: Option<MultiSpan>,
-    decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>) + 'd,
+    msg: impl Into<DiagnosticMessage>,
+    decorate: impl 'd
+    + for<'a, 'b> FnOnce(
+        &'b mut DiagnosticBuilder<'a, ()>,
+    ) -> &'b mut DiagnosticBuilder<'a, ()>,
 ) {
     // Avoid codegen bloat from monomorphization by immediately doing dyn dispatch of `decorate` to
     // the "real" work.
@@ -293,7 +297,13 @@ fn struct_lint_level_impl<'s, 'd>(
         level: Level,
         src: LintLevelSource,
         span: Option<MultiSpan>,
-        decorate: Box<dyn for<'b> FnOnce(LintDiagnosticBuilder<'b, ()>) + 'd>,
+        msg: impl Into<DiagnosticMessage>,
+        decorate: Box<
+            dyn 'd
+                + for<'a, 'b> FnOnce(
+                    &'b mut DiagnosticBuilder<'a, ()>,
+                ) -> &'b mut DiagnosticBuilder<'a, ()>,
+        >,
     ) {
         // Check for future incompatibility lints and issue a stronger warning.
         let future_incompatible = lint.future_incompatible;
@@ -344,6 +354,9 @@ fn struct_lint_level_impl<'s, 'd>(
             (Level::Deny | Level::Forbid, None) => sess.diagnostic().struct_err_lint(""),
         };
 
+        err.set_primary_message(msg);
+        err.set_is_lint();
+
         // If this code originates in a foreign macro, aka something that this crate
         // did not itself author, then it's likely that there's nothing this crate
         // can do about it. We probably want to skip the lint entirely.
@@ -373,11 +386,13 @@ fn struct_lint_level_impl<'s, 'd>(
         if let Level::Expect(_) = level {
             let name = lint.name_lower();
             err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn: false });
-            decorate(LintDiagnosticBuilder::new(err));
+
+            decorate(&mut err);
+            err.emit();
             return;
         }
 
-        explain_lint_level_source(lint, level, src, &mut err);
+        explain_lint_level_source(lint, level, src, &mut *err);
 
         let name = lint.name_lower();
         let is_force_warn = matches!(level, Level::ForceWarn(_));
@@ -417,10 +432,11 @@ fn struct_lint_level_impl<'s, 'd>(
             }
         }
 
-        // Finally, run `decorate`. This function is also responsible for emitting the diagnostic.
-        decorate(LintDiagnosticBuilder::new(err));
+        // Finally, run `decorate`.
+        decorate(&mut err);
+        err.emit()
     }
-    struct_lint_level_impl(sess, lint, level, src, span, Box::new(decorate))
+    struct_lint_level_impl(sess, lint, level, src, span, msg, Box::new(decorate))
 }
 
 /// Returns whether `span` originates in a foreign crate's external macro.
index d182929c40066c3691176ee529487e48de05437d..61bc089e431bb4e407d38337bc364629ab20d3aa 100644 (file)
@@ -253,13 +253,12 @@ fn late_report_deprecation(
         return;
     }
     let method_span = method_span.unwrap_or(span);
-    tcx.struct_span_lint_hir(lint, hir_id, method_span, |lint| {
-        let mut diag = lint.build(message);
+    tcx.struct_span_lint_hir(lint, hir_id, method_span, message, |diag| {
         if let hir::Node::Expr(_) = tcx.hir().get(hir_id) {
             let kind = tcx.def_kind(def_id).descr(def_id);
-            deprecation_suggestion(&mut diag, kind, suggestion, method_span);
+            deprecation_suggestion(diag, kind, suggestion, method_span);
         }
-        diag.emit();
+        diag
     });
 }
 
@@ -621,9 +620,7 @@ pub fn check_optional_stability(
         unmarked: impl FnOnce(Span, DefId),
     ) -> bool {
         let soft_handler = |lint, span, msg: &_| {
-            self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| {
-                lint.build(msg).emit();
-            })
+            self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, msg, |lint| lint)
         };
         let eval_result =
             self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable);
index 4781585b82c3897ba0dffad02795a61f2edd599c..a3489226f62b00d0198007b3ef944c990d16f8a7 100644 (file)
@@ -35,7 +35,9 @@
 use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{self, Lock, Lrc, ReadGuard, RwLock, WorkerLocal};
 use rustc_data_structures::vec_map::VecMap;
-use rustc_errors::{DecorateLint, ErrorGuaranteed, LintDiagnosticBuilder, MultiSpan};
+use rustc_errors::{
+    DecorateLint, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
+};
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
@@ -2857,7 +2859,9 @@ pub fn emit_spanned_lint(
         span: impl Into<MultiSpan>,
         decorator: impl for<'a> DecorateLint<'a, ()>,
     ) {
-        self.struct_span_lint_hir(lint, hir_id, span, |diag| decorator.decorate_lint(diag))
+        self.struct_span_lint_hir(lint, hir_id, span, decorator.msg(), |diag| {
+            decorator.decorate_lint(diag)
+        })
     }
 
     pub fn struct_span_lint_hir(
@@ -2865,10 +2869,13 @@ pub fn struct_span_lint_hir(
         lint: &'static Lint,
         hir_id: HirId,
         span: impl Into<MultiSpan>,
-        decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+        msg: impl Into<DiagnosticMessage>,
+        decorate: impl for<'a, 'b> FnOnce(
+            &'b mut DiagnosticBuilder<'a, ()>,
+        ) -> &'b mut DiagnosticBuilder<'a, ()>,
     ) {
         let (level, src) = self.lint_level_at_node(lint, hir_id);
-        struct_lint_level(self.sess, lint, level, src, Some(span.into()), decorate);
+        struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg, decorate);
     }
 
     /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically
@@ -2879,17 +2886,20 @@ pub fn emit_lint(
         id: HirId,
         decorator: impl for<'a> DecorateLint<'a, ()>,
     ) {
-        self.struct_lint_node(lint, id, |diag| decorator.decorate_lint(diag))
+        self.struct_lint_node(lint, id, decorator.msg(), |diag| decorator.decorate_lint(diag))
     }
 
     pub fn struct_lint_node(
         self,
         lint: &'static Lint,
         id: HirId,
-        decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>),
+        msg: impl Into<DiagnosticMessage>,
+        decorate: impl for<'a, 'b> FnOnce(
+            &'b mut DiagnosticBuilder<'a, ()>,
+        ) -> &'b mut DiagnosticBuilder<'a, ()>,
     ) {
         let (level, src) = self.lint_level_at_node(lint, id);
-        struct_lint_level(self.sess, lint, level, src, None, decorate);
+        struct_lint_level(self.sess, lint, level, src, None, msg, decorate);
     }
 
     pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> {
index 988ebccb633e40698094ca9312ca90734ea59432..5e8ce65daf0fc451ae750d10923c5bdbe7fdb17c 100644 (file)
@@ -89,15 +89,8 @@ fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
                     UNSAFE_OP_IN_UNSAFE_FN,
                     self.hir_context,
                     span,
-                    |lint| {
-                        lint.build(&format!(
-                            "{} is unsafe and requires unsafe block (error E0133)",
-                            description,
-                        ))
-                        .span_label(span, kind.simple_description())
-                        .note(note)
-                        .emit();
-                    },
+                    format!("{} is unsafe and requires unsafe block (error E0133)", description,),
+                    |lint| lint.span_label(span, kind.simple_description()).note(note),
                 )
             }
             SafetyContext::Safe => {
@@ -125,14 +118,13 @@ fn warn_unused_unsafe(
         enclosing_unsafe: Option<(Span, &'static str)>,
     ) {
         let block_span = self.tcx.sess.source_map().guess_head_span(block_span);
-        self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, |lint| {
-            let msg = "unnecessary `unsafe` block";
-            let mut db = lint.build(msg);
-            db.span_label(block_span, msg);
+        let msg = "unnecessary `unsafe` block";
+        self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, msg, |lint| {
+            lint.span_label(block_span, msg);
             if let Some((span, kind)) = enclosing_unsafe {
-                db.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
+                lint.span_label(span, format!("because it's nested under this `unsafe` {}", kind));
             }
-            db.emit();
+            lint
         });
     }
 
index 54d549fd66c95b2ce39cf40c8be61858cda61825..b21f30efce8076dcd993c481dd5f78cbe517e515 100644 (file)
@@ -36,16 +36,20 @@ pub(crate) fn check<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) {
 
         let sp = tcx.def_span(def_id);
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-        tcx.struct_span_lint_hir(UNCONDITIONAL_RECURSION, hir_id, sp, |lint| {
-            let mut db = lint.build("function cannot return without recursing");
-            db.span_label(sp, "cannot return without recursing");
-            // offer some help to the programmer.
-            for call_span in vis.reachable_recursive_calls {
-                db.span_label(call_span, "recursive call site");
-            }
-            db.help("a `loop` may express intention better if this is on purpose");
-            db.emit();
-        });
+        tcx.struct_span_lint_hir(
+            UNCONDITIONAL_RECURSION,
+            hir_id,
+            sp,
+            "function cannot return without recursing",
+            |lint| {
+                lint.span_label(sp, "cannot return without recursing");
+                // offer some help to the programmer.
+                for call_span in vis.reachable_recursive_calls {
+                    lint.span_label(call_span, "recursive call site");
+                }
+                lint.help("a `loop` may express intention better if this is on purpose")
+            },
+        );
     }
 }
 
index d45b886903bbf757464894a79d4fb58504bc14fa..8fca94119c2114b16cb56241ac7b4654a6bb4b6a 100644 (file)
@@ -7,7 +7,7 @@
 use rustc_arena::TypedArena;
 use rustc_ast::Mutability;
 use rustc_errors::{
-    error_code, pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder,
+    error_code, pluralize, struct_span_err, Applicability, DelayDm, Diagnostic, DiagnosticBuilder,
     ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir as hir;
@@ -347,19 +347,23 @@ fn check_let_chain(&mut self, cx: &mut MatchCheckCtxt<'p, 'tcx>, pat_id: HirId)
             let span_end = affix.last().unwrap().unwrap().0;
             let span = span_start.to(span_end);
             let cnt = affix.len();
-            cx.tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, top, span, |lint| {
-                let s = pluralize!(cnt);
-                let mut diag = lint.build(&format!("{kind} irrefutable pattern{s} in let chain"));
-                diag.note(&format!(
-                    "{these} pattern{s} will always match",
-                    these = pluralize!("this", cnt),
-                ));
-                diag.help(&format!(
-                    "consider moving {} {suggestion}",
-                    if cnt > 1 { "them" } else { "it" }
-                ));
-                diag.emit()
-            });
+            let s = pluralize!(cnt);
+            cx.tcx.struct_span_lint_hir(
+                IRREFUTABLE_LET_PATTERNS,
+                top,
+                span,
+                format!("{kind} irrefutable pattern{s} in let chain"),
+                |lint| {
+                    lint.note(format!(
+                        "{these} pattern{s} will always match",
+                        these = pluralize!("this", cnt),
+                    ))
+                    .help(format!(
+                        "consider moving {} {suggestion}",
+                        if cnt > 1 { "them" } else { "it" }
+                    ))
+                },
+            );
         };
         if let Some(until) = chain_refutabilities.iter().position(|r| !matches!(*r, Some((_, false)))) && until > 0 {
             // The chain has a non-zero prefix of irrefutable `let` statements.
@@ -561,26 +565,28 @@ fn check_for_bindings_named_same_as_variants(
                 BINDINGS_WITH_VARIANT_NAME,
                 p.hir_id,
                 p.span,
+                DelayDm(|| format!(
+                    "pattern binding `{}` is named the same as one \
+                        of the variants of the type `{}`",
+                    ident, cx.tcx.def_path_str(edef.did())
+                )),
                 |lint| {
                     let ty_path = cx.tcx.def_path_str(edef.did());
-                    let mut err = lint.build(&format!(
-                        "pattern binding `{}` is named the same as one \
-                         of the variants of the type `{}`",
-                        ident, ty_path
-                    ));
-                    err.code(error_code!(E0170));
+                    lint.code(error_code!(E0170));
+
                     // If this is an irrefutable pattern, and there's > 1 variant,
                     // then we can't actually match on this. Applying the below
                     // suggestion would produce code that breaks on `check_irrefutable`.
                     if rf == Refutable || variant_count == 1 {
-                        err.span_suggestion(
+                        lint.span_suggestion(
                             p.span,
                             "to match on the variant, qualify the path",
                             format!("{}::{}", ty_path, ident),
                             Applicability::MachineApplicable,
                         );
                     }
-                    err.emit();
+
+                    lint
                 },
             )
         }
@@ -598,14 +604,13 @@ fn pat_is_catchall(pat: &DeconstructedPat<'_, '_>) -> bool {
 }
 
 fn unreachable_pattern(tcx: TyCtxt<'_>, span: Span, id: HirId, catchall: Option<Span>) {
-    tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, |lint| {
-        let mut err = lint.build("unreachable pattern");
+    tcx.struct_span_lint_hir(UNREACHABLE_PATTERNS, id, span, "unreachable pattern", |lint| {
         if let Some(catchall) = catchall {
             // We had a catchall pattern, hint at that.
-            err.span_label(span, "unreachable pattern");
-            err.span_label(catchall, "matches any value");
+            lint.span_label(span, "unreachable pattern");
+            lint.span_label(catchall, "matches any value");
         }
-        err.emit();
+        lint
     });
 }
 
@@ -621,6 +626,11 @@ fn irrefutable_let_patterns(
     count: usize,
     span: Span,
 ) {
+    let span = match source {
+        LetSource::LetElse(span) => span,
+        _ => span,
+    };
+
     macro_rules! emit_diag {
         (
             $lint:expr,
@@ -630,18 +640,23 @@ macro_rules! emit_diag {
         ) => {{
             let s = pluralize!(count);
             let these = pluralize!("this", count);
-            let mut diag = $lint.build(&format!("irrefutable {} pattern{s}", $source_name));
-            diag.note(&format!("{these} pattern{s} will always match, so the {}", $note_sufix));
-            diag.help(concat!("consider ", $help_sufix));
-            diag.emit()
+            tcx.struct_span_lint_hir(
+                IRREFUTABLE_LET_PATTERNS,
+                id,
+                span,
+                format!("irrefutable {} pattern{s}", $source_name),
+                |lint| {
+                    lint.note(&format!(
+                        "{these} pattern{s} will always match, so the {}",
+                        $note_sufix
+                    ))
+                    .help(concat!("consider ", $help_sufix))
+                },
+            )
         }};
     }
 
-    let span = match source {
-        LetSource::LetElse(span) => span,
-        _ => span,
-    };
-    tcx.struct_span_lint_hir(IRREFUTABLE_LET_PATTERNS, id, span, |lint| match source {
+    match source {
         LetSource::GenericLet => {
             emit_diag!(lint, "`let`", "`let` is useless", "removing `let`");
         }
@@ -677,7 +692,7 @@ macro_rules! emit_diag {
                 "instead using a `loop { ... }` with a `let` inside it"
             );
         }
-    });
+    };
 }
 
 fn is_let_irrefutable<'p, 'tcx>(
index b58685e895809b266d76df47122f3add615fad3a..f2935ca0e3aecc1caed1dd45f528fb3f6c245625 100644 (file)
@@ -1,3 +1,4 @@
+use rustc_errors::DelayDm;
 use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -205,9 +206,8 @@ fn to_pat(
                         lint::builtin::INDIRECT_STRUCTURAL_MATCH,
                         self.id,
                         self.span,
-                        |lint| {
-                            lint.build(&msg).emit();
-                        },
+                        msg,
+                        |lint| lint,
                     );
                 } else {
                     debug!(
@@ -286,9 +286,8 @@ fn recur(
                         lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
                         id,
                         span,
-                        |lint| {
-                            lint.build("floating-point types cannot be used in patterns").emit();
-                        },
+                        "floating-point types cannot be used in patterns",
+                        |lint| lint,
                     );
                 }
                 PatKind::Constant { value: cv }
@@ -340,15 +339,15 @@ fn recur(
                         lint::builtin::INDIRECT_STRUCTURAL_MATCH,
                         id,
                         span,
-                        |lint| {
-                            let msg = format!(
+                        DelayDm(|| {
+                            format!(
                                 "to use a constant of type `{}` in a pattern, \
                                  `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
                                 cv.ty(),
                                 cv.ty(),
-                            );
-                            lint.build(&msg).emit();
-                        },
+                            )
+                        }),
+                        |lint| lint,
                     );
                 }
                 // Since we are behind a reference, we can just bubble the error up so we get a
@@ -488,7 +487,8 @@ fn recur(
                                 lint::builtin::INDIRECT_STRUCTURAL_MATCH,
                                 self.id,
                                 self.span,
-                                |lint| {lint.build(&msg).emit();},
+                                msg,
+                                |lint| lint,
                             );
                         }
                         PatKind::Constant { value: cv }
@@ -556,9 +556,8 @@ fn recur(
                         lint::builtin::POINTER_STRUCTURAL_MATCH,
                         id,
                         span,
-                        |lint| {
-                            lint.build(msg).emit();
-                        },
+                        msg,
+                        |lint| lint,
                     );
                 }
                 PatKind::Constant { value: cv }
@@ -594,9 +593,8 @@ fn recur(
                 lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
                 id,
                 span,
-                |lint| {
-                    lint.build(&msg).emit();
-                },
+                msg,
+                |lint| lint,
             );
         }
 
index 5105f059f9b64797317ac251dc630389a8a1ceb8..91ecfccdb5f746f481ce2a2de514fa86842ec8da 100644 (file)
@@ -299,10 +299,10 @@ pub(super) fn lint_overlapping_range_endpoints<'a, 'p: 'a, 'tcx: 'a>(
                 lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
                 hir_id,
                 pcx.span,
+                "multiple patterns overlap on their endpoints",
                 |lint| {
-                    let mut err = lint.build("multiple patterns overlap on their endpoints");
                     for (int_range, span) in overlaps {
-                        err.span_label(
+                        lint.span_label(
                             span,
                             &format!(
                                 "this range overlaps on `{}`...",
@@ -310,9 +310,9 @@ pub(super) fn lint_overlapping_range_endpoints<'a, 'p: 'a, 'tcx: 'a>(
                             ),
                         );
                     }
-                    err.span_label(pcx.span, "... with this range");
-                    err.note("you likely meant to write mutually exclusive ranges");
-                    err.emit();
+                    lint.span_label(pcx.span, "... with this range");
+                    lint.note("you likely meant to write mutually exclusive ranges");
+                    lint
                 },
             );
         }
index 22b58837148981c669b6eef88e8157165c2a921d..f127907284425e1e885c8642ddee85265fae6d04 100644 (file)
@@ -754,9 +754,8 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
     hir_id: HirId,
     witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
 ) {
-    cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, |build| {
+    cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, "some variants are not matched explicitly", |lint| {
         let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
-        let mut lint = build.build("some variants are not matched explicitly");
         lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
         lint.help(
             "ensure that all variants are matched explicitly by adding the suggested match arms",
@@ -765,7 +764,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
             "the matched value is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
             scrut_ty,
         ));
-        lint.emit();
+        lint
     });
 }
 
index 8838b14c53a589898278d121d398a475dcba4320..fa5f392fa74f6cc03bf351690741aeb4bf642035 100644 (file)
@@ -1,4 +1,4 @@
-use rustc_errors::{DiagnosticBuilder, LintDiagnosticBuilder};
+use rustc_errors::{DiagnosticBuilder, DiagnosticMessage};
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -63,7 +63,10 @@ fn lint_const_item_usage(
         place: &Place<'tcx>,
         const_item: DefId,
         location: Location,
-        decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b, ()>) -> DiagnosticBuilder<'b, ()>,
+        msg: impl Into<DiagnosticMessage>,
+        decorate: impl for<'a, 'b> FnOnce(
+            &'a mut DiagnosticBuilder<'b, ()>,
+        ) -> &'a mut DiagnosticBuilder<'b, ()>,
     ) {
         // Don't lint on borrowing/assigning when a dereference is involved.
         // If we 'leave' the temporary via a dereference, we must
@@ -84,10 +87,10 @@ fn lint_const_item_usage(
                 CONST_ITEM_MUTATION,
                 lint_root,
                 source_info.span,
+                msg,
                 |lint| {
                     decorate(lint)
                         .span_note(self.tcx.def_span(const_item), "`const` item defined here")
-                        .emit();
                 },
             );
         }
@@ -102,10 +105,8 @@ fn visit_statement(&mut self, stmt: &Statement<'tcx>, loc: Location) {
             // so emitting a lint would be redundant.
             if !lhs.projection.is_empty() {
                 if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
-                    self.lint_const_item_usage(&lhs, def_id, loc, |lint| {
-                        let mut lint = lint.build("attempting to modify a `const` item");
-                        lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified");
-                        lint
+                    self.lint_const_item_usage(&lhs, def_id, loc, "attempting to modify a `const` item",|lint| {
+                        lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified")
                     })
                 }
             }
@@ -137,8 +138,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) {
                 });
                 let lint_loc =
                     if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
-                self.lint_const_item_usage(place, def_id, lint_loc, |lint| {
-                    let mut lint = lint.build("taking a mutable reference to a `const` item");
+                self.lint_const_item_usage(place, def_id, lint_loc, "taking a mutable reference to a `const` item", |lint| {
                     lint
                         .note("each usage of a `const` item creates a new temporary")
                         .note("the mutable reference will refer to this temporary, not the original `const` item");
index 3b7ba3f9a67ac97096d1dd166aff9992babc1aee..51abcf51189f62b92984d8db0838fa1741f5d6fb 100644 (file)
@@ -33,21 +33,27 @@ struct PackedRefChecker<'a, 'tcx> {
 fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
 
-    tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| {
-        // FIXME: when we make this a hard error, this should have its
-        // own error code.
-        let extra = if tcx.generics_of(def_id).own_requires_monomorphization() {
-            "with type or const parameters"
-        } else {
-            "that does not derive `Copy`"
-        };
-        let message = format!(
-            "`{}` can't be derived on this `#[repr(packed)]` struct {}",
-            tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")),
-            extra
-        );
-        lint.build(message).emit();
-    });
+    // FIXME: when we make this a hard error, this should have its
+    // own error code.
+
+    let extra = if tcx.generics_of(def_id).own_requires_monomorphization() {
+        "with type or const parameters"
+    } else {
+        "that does not derive `Copy`"
+    };
+    let message = format!(
+        "`{}` can't be derived on this `#[repr(packed)]` struct {}",
+        tcx.item_name(tcx.trait_id_of_impl(def_id.to_def_id()).expect("derived trait name")),
+        extra
+    );
+
+    tcx.struct_span_lint_hir(
+        UNALIGNED_REFERENCES,
+        lint_hir_id,
+        tcx.def_span(def_id),
+        message,
+        |lint| lint,
+    );
 }
 
 impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
@@ -86,8 +92,9 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
                         UNALIGNED_REFERENCES,
                         lint_root,
                         source_info.span,
+                        "reference to packed field is unaligned",
                         |lint| {
-                            lint.build("reference to packed field is unaligned")
+                            lint
                                 .note(
                                     "fields of packed structs are not properly aligned, and creating \
                                     a misaligned reference is undefined behavior (even if that \
@@ -98,7 +105,6 @@ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location:
                                     reference with a raw pointer and use `read_unaligned`/`write_unaligned` \
                                     (loads and stores via `*p` must be properly aligned even when using raw pointers)"
                                 )
-                                .emit();
                         },
                     );
                 }
index beff19a3ab2e1d908f8a09a4848c8ddeb5065c33..4730be1244bdaeb9320f190b91811727da477b3d 100644 (file)
@@ -489,21 +489,20 @@ fn unsafety_check_result<'tcx>(
 
 fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
     let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
-    tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, |lint| {
-        let msg = "unnecessary `unsafe` block";
-        let mut db = lint.build(msg);
-        db.span_label(span, msg);
+    let msg = "unnecessary `unsafe` block";
+    tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, msg, |lint| {
+        lint.span_label(span, msg);
         match kind {
             UnusedUnsafe::Unused => {}
             UnusedUnsafe::InUnsafeBlock(id) => {
-                db.span_label(
+                lint.span_label(
                     tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
                     "because it's nested under this `unsafe` block",
                 );
             }
         }
 
-        db.emit();
+        lint
     });
 }
 
@@ -543,15 +542,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
                 UNSAFE_OP_IN_UNSAFE_FN,
                 lint_root,
                 source_info.span,
-                |lint| {
-                    lint.build(&format!(
-                        "{} is unsafe and requires unsafe block (error E0133)",
-                        description,
-                    ))
-                    .span_label(source_info.span, description)
-                    .note(note)
-                    .emit();
-                },
+                format!("{} is unsafe and requires unsafe block (error E0133)", description,),
+                |lint| lint.span_label(source_info.span, description).note(note),
             ),
         }
     }
index 973f55437eeb336e84c40c33ead26a570218f0ae..cda3702c83d1c262b7210af3ffef82236950c870 100644 (file)
@@ -347,10 +347,8 @@ fn report_assert_as_lint(
         panic: AssertKind<impl std::fmt::Debug>,
     ) {
         if let Some(lint_root) = self.lint_root(source_info) {
-            self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
-                let mut err = lint.build(message);
-                err.span_label(source_info.span, format!("{:?}", panic));
-                err.emit();
+            self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, message, |lint| {
+                lint.span_label(source_info.span, format!("{:?}", panic))
             });
         }
     }
index 7522a50a8c6436ebf94fee1af0bf79f80cf1b41f..1244c18020ddd3985a002dbe97600c9fca83afc1 100644 (file)
@@ -106,14 +106,12 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
                 .lint_root;
             let span = terminator.source_info.span;
 
-            tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, |lint| {
-                let msg = match fn_def_id {
-                    Some(_) => "call to foreign function with FFI-unwind ABI",
-                    None => "call to function pointer with FFI-unwind ABI",
-                };
-                let mut db = lint.build(msg);
-                db.span_label(span, msg);
-                db.emit();
+            let msg = match fn_def_id {
+                Some(_) => "call to foreign function with FFI-unwind ABI",
+                None => "call to function pointer with FFI-unwind ABI",
+            };
+            tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, msg, |lint| {
+                lint.span_label(span, msg)
             });
 
             tainted = true;
index 0568eb2ffa607e38152103f8088cd5bcaff50ea1..469566694a3ef6b366d807056f5ceca8192705ce 100644 (file)
@@ -179,11 +179,15 @@ fn emit_lint(
         let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
         let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
         let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
-        self.tcx.struct_span_lint_hir(FUNCTION_ITEM_REFERENCES, lint_root, span, |lint| {
-            lint.build("taking a reference to a function item does not give a function pointer")
-                .span_suggestion(
+        self.tcx.struct_span_lint_hir(
+            FUNCTION_ITEM_REFERENCES,
+            lint_root,
+            span,
+            "taking a reference to a function item does not give a function pointer",
+            |lint| {
+                lint.span_suggestion(
                     span,
-                    &format!("cast `{}` to obtain a function pointer", ident),
+                    format!("cast `{}` to obtain a function pointer", ident),
                     format!(
                         "{} as {}{}fn({}{}){}",
                         if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) },
@@ -195,7 +199,7 @@ fn emit_lint(
                     ),
                     Applicability::Unspecified,
                 )
-                .emit();
-        });
+            },
+        );
     }
 }
index 897a0db930c79d9677a97adcae09bbf0fc1a4627..87433538512b9dd974ebf7d2d99393a70ac951a4 100644 (file)
@@ -370,10 +370,13 @@ fn check_generic_attr(
                 b.push_str(&(allowed_target.to_string() + "s"));
                 b
             });
-            self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
-                lint.build(&format!("`#[{name}]` only has an effect on {}", supported_names))
-                    .emit();
-            });
+            self.tcx.struct_span_lint_hir(
+                UNUSED_ATTRIBUTES,
+                hir_id,
+                attr.span,
+                &format!("`#[{name}]` only has an effect on {}", supported_names),
+                |lint| lint,
+            );
         }
     }
 
@@ -877,25 +880,31 @@ fn check_attr_crate_level(
         hir_id: HirId,
     ) -> bool {
         if hir_id != CRATE_HIR_ID {
-            self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| {
-                let mut err = lint.build(fluent::passes::attr_crate_level);
-                if attr.style == AttrStyle::Outer
-                    && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID
-                {
-                    if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) {
-                        src.insert(1, '!');
-                        err.span_suggestion_verbose(
-                            attr.span,
-                            fluent::passes::suggestion,
-                            src,
-                            Applicability::MaybeIncorrect,
-                        );
-                    } else {
-                        err.span_help(attr.span, fluent::passes::help);
+            self.tcx.struct_span_lint_hir(
+                INVALID_DOC_ATTRIBUTES,
+                hir_id,
+                meta.span(),
+                fluent::passes::attr_crate_level,
+                |err| {
+                    if attr.style == AttrStyle::Outer
+                        && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID
+                    {
+                        if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) {
+                            src.insert(1, '!');
+                            err.span_suggestion_verbose(
+                                attr.span,
+                                fluent::passes::suggestion,
+                                src,
+                                Applicability::MaybeIncorrect,
+                            );
+                        } else {
+                            err.span_help(attr.span, fluent::passes::help);
+                        }
                     }
-                }
-                err.note(fluent::passes::note).emit();
-            });
+                    err.note(fluent::passes::note);
+                    err
+                },
+            );
             return false;
         }
         true
index e9d71bc93ac109f096ead1d2a9da66d4ce1d1288..5e28a900e55e785cc621bcc091894c9df20ef6bf 100644 (file)
@@ -4,7 +4,7 @@
 
 use itertools::Itertools;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, Applicability, MultiSpan};
+use rustc_errors::{pluralize, Applicability, DelayDm, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -190,13 +190,14 @@ fn check_for_self_assign_helper<'tcx>(
                     lint::builtin::DEAD_CODE,
                     assign.hir_id,
                     assign.span,
-                    |lint| {
-                        lint.build(&format!(
+                    DelayDm(|| format!(
                             "useless assignment of {} of type `{}` to itself",
                             if is_field_assign { "field" } else { "variable" },
                             self.typeck_results().expr_ty(lhs),
-                        ))
-                        .emit();
+                        )),
+                    |lint| {
+                        lint
+
                     },
                 )
         }
@@ -723,6 +724,26 @@ fn warn_multiple_dead_codes(
                 })
                 .collect();
 
+            let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
+            let span_len = dead_codes.len();
+            let names = match &names[..] {
+                _ if span_len > 6 => String::new(),
+                [name] => format!("`{name}` "),
+                [names @ .., last] => {
+                    format!(
+                        "{} and `{last}` ",
+                        names.iter().map(|name| format!("`{name}`")).join(", ")
+                    )
+                }
+                [] => unreachable!(),
+            };
+            let msg = format!(
+                "{these}{descr}{s} {names}{are} never {participle}",
+                these = if span_len > 6 { "multiple " } else { "" },
+                s = pluralize!(span_len),
+                are = pluralize!("is", span_len),
+            );
+
             tcx.struct_span_lint_hir(
                 if is_positional {
                     lint::builtin::UNUSED_TUPLE_STRUCT_FIELDS
@@ -731,27 +752,8 @@ fn warn_multiple_dead_codes(
                 },
                 tcx.hir().local_def_id_to_hir_id(first_id),
                 MultiSpan::from_spans(spans.clone()),
-                |lint| {
-                    let descr = tcx.def_kind(first_id).descr(first_id.to_def_id());
-                    let span_len = dead_codes.len();
-                    let names = match &names[..] {
-                        _ if span_len > 6 => String::new(),
-                        [name] => format!("`{name}` "),
-                        [names @ .., last] => {
-                            format!(
-                                "{} and `{last}` ",
-                                names.iter().map(|name| format!("`{name}`")).join(", ")
-                            )
-                        }
-                        [] => unreachable!(),
-                    };
-                    let mut err = lint.build(&format!(
-                        "{these}{descr}{s} {names}{are} never {participle}",
-                        these = if span_len > 6 { "multiple " } else { "" },
-                        s = pluralize!(span_len),
-                        are = pluralize!("is", span_len),
-                    ));
-
+                msg,
+                |err| {
                     if is_positional {
                         err.multipart_suggestion(
                             &format!(
@@ -797,7 +799,7 @@ fn warn_multiple_dead_codes(
                         );
                         err.note(&msg);
                     }
-                    err.emit();
+                    err
                 },
             );
         }
index 6a4cd79cde7128080ac4ce97922e65562aff3783..c6fe40f72fc634c4994661be8952e24018b7e4eb 100644 (file)
@@ -1319,14 +1319,14 @@ fn warn_about_unreachable(
             // that we do not emit the same warning twice if the uninhabited type
             // is indeed `!`.
 
+            let msg = format!("unreachable {}", descr);
             self.ir.tcx.struct_span_lint_hir(
                 lint::builtin::UNREACHABLE_CODE,
                 expr_id,
                 expr_span,
-                |lint| {
-                    let msg = format!("unreachable {}", descr);
-                    lint.build(&msg)
-                        .span_label(expr_span, &msg)
+                &msg,
+                |diag| {
+                    diag.span_label(expr_span, &msg)
                         .span_label(orig_span, "any code following this expression is unreachable")
                         .span_note(
                             orig_span,
@@ -1335,7 +1335,6 @@ fn warn_about_unreachable(
                                 orig_ty
                             ),
                         )
-                        .emit();
                 },
             );
         }
@@ -1491,14 +1490,8 @@ fn warn_about_unused_upvars(&self, entry_ln: LiveNode) {
                                 lint::builtin::UNUSED_ASSIGNMENTS,
                                 var_hir_id,
                                 vec![span],
-                                |lint| {
-                                    lint.build(&format!(
-                                        "value captured by `{}` is never read",
-                                        name
-                                    ))
-                                    .help("did you mean to capture by reference instead?")
-                                    .emit();
-                                },
+                                format!("value captured by `{}` is never read", name),
+                                |lint| lint.help("did you mean to capture by reference instead?"),
                             );
                         }
                     }
@@ -1508,11 +1501,8 @@ fn warn_about_unused_upvars(&self, entry_ln: LiveNode) {
                             lint::builtin::UNUSED_VARIABLES,
                             var_hir_id,
                             vec![span],
-                            |lint| {
-                                lint.build(&format!("unused variable: `{}`", name))
-                                    .help("did you mean to capture by reference instead?")
-                                    .emit();
-                            },
+                            format!("unused variable: `{}`", name),
+                            |lint| lint.help("did you mean to capture by reference instead?"),
                         );
                     }
                 }
@@ -1601,20 +1591,17 @@ fn report_unused(
                         .into_iter()
                         .map(|(_, _, ident_span)| ident_span)
                         .collect::<Vec<_>>(),
-                    |lint| {
-                        lint.build(&format!("variable `{}` is assigned to, but never used", name))
-                            .note(&format!("consider using `_{}` instead", name))
-                            .emit();
-                    },
+                    format!("variable `{}` is assigned to, but never used", name),
+                    |lint| lint.note(&format!("consider using `_{}` instead", name)),
                 )
             } else if can_remove {
                 self.ir.tcx.struct_span_lint_hir(
                     lint::builtin::UNUSED_VARIABLES,
                     first_hir_id,
                     hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::<Vec<_>>(),
+                    format!("unused variable: `{}`", name),
                     |lint| {
-                        let mut err = lint.build(&format!("unused variable: `{}`", name));
-                        err.multipart_suggestion(
+                        lint.multipart_suggestion(
                             "try removing the field",
                             hir_ids_and_spans
                                 .iter()
@@ -1629,8 +1616,7 @@ fn report_unused(
                                 })
                                 .collect(),
                             Applicability::MachineApplicable,
-                        );
-                        err.emit();
+                        )
                     },
                 );
             } else {
@@ -1661,14 +1647,13 @@ fn report_unused(
                             .iter()
                             .map(|(_, pat_span, _)| *pat_span)
                             .collect::<Vec<_>>(),
+                        format!("unused variable: `{}`", name),
                         |lint| {
-                            let mut err = lint.build(&format!("unused variable: `{}`", name));
-                            err.multipart_suggestion(
+                            lint.multipart_suggestion(
                                 "try ignoring the field",
                                 shorthands,
                                 Applicability::MachineApplicable,
-                            );
-                            err.emit();
+                            )
                         },
                     );
                 } else {
@@ -1684,17 +1669,16 @@ fn report_unused(
                             .iter()
                             .map(|(_, _, ident_span)| *ident_span)
                             .collect::<Vec<_>>(),
+                        format!("unused variable: `{}`", name),
                         |lint| {
-                            let mut err = lint.build(&format!("unused variable: `{}`", name));
-                            if self.has_added_lit_match_name_span(&name, opt_body, &mut err) {
-                                err.span_label(pat.span, "unused variable");
+                            if self.has_added_lit_match_name_span(&name, opt_body, lint) {
+                                lint.span_label(pat.span, "unused variable");
                             }
-                            err.multipart_suggestion(
+                            lint.multipart_suggestion(
                                 "if this is intentional, prefix it with an underscore",
                                 non_shorthands,
                                 Applicability::MachineApplicable,
-                            );
-                            err.emit();
+                            )
                         },
                     );
                 }
@@ -1758,11 +1742,8 @@ fn report_unused_assign(
                 lint::builtin::UNUSED_ASSIGNMENTS,
                 hir_id,
                 spans,
-                |lint| {
-                    lint.build(&message(&name))
-                        .help("maybe it is overwritten before being read?")
-                        .emit();
-                },
+                message(&name),
+                |lint| lint.help("maybe it is overwritten before being read?"),
             )
         }
     }
index 607973446fc1e32c3818f682c746013b5e0e250a..2690be66c21e5ae8456dfad9330dfda967c574d7 100644 (file)
@@ -65,9 +65,13 @@ fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) {
     if abi == Abi::Rust {
         let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
         let span = tcx.def_span(def_id);
-        tcx.struct_span_lint_hir(UNDEFINED_NAKED_FUNCTION_ABI, hir_id, span, |lint| {
-            lint.build("Rust ABI is unsupported in naked functions").emit();
-        });
+        tcx.struct_span_lint_hir(
+            UNDEFINED_NAKED_FUNCTION_ABI,
+            hir_id,
+            span,
+            "Rust ABI is unsupported in naked functions",
+            |lint| lint,
+        );
     }
 }
 
index e50beb27d2a8802829ec2a0f446b74daf318167b..34fa80228df89d883b5e7f3b8ee18d4afcd7052d 100644 (file)
@@ -752,10 +752,8 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
                                 INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
                                 item.hir_id(),
                                 span,
-                                |lint| {lint
-                                    .build("an `#[unstable]` annotation here has no effect")
-                                    .note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
-                                    .emit();}
+                                "an `#[unstable]` annotation here has no effect",
+                                |lint| lint.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
                             );
                         }
                     }
@@ -1081,11 +1079,16 @@ fn unnecessary_partially_stable_feature_lint(
     implies: Symbol,
     since: Symbol,
 ) {
-    tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
-        lint.build(&format!(
+    tcx.struct_span_lint_hir(
+        lint::builtin::STABLE_FEATURES,
+        hir::CRATE_HIR_ID,
+        span,
+        format!(
             "the feature `{feature}` has been partially stabilized since {since} and is succeeded \
              by the feature `{implies}`"
-        ))
+        ),
+        |lint| {
+            lint
         .span_suggestion(
             span,
             &format!(
@@ -1100,8 +1103,8 @@ fn unnecessary_partially_stable_feature_lint(
             "",
             Applicability::MaybeIncorrect,
         )
-        .emit();
-    });
+        },
+    );
 }
 
 fn unnecessary_stable_feature_lint(
@@ -1113,12 +1116,8 @@ fn unnecessary_stable_feature_lint(
     if since.as_str() == VERSION_PLACEHOLDER {
         since = rust_version_symbol();
     }
-    tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, |lint| {
-        lint.build(&format!(
-            "the feature `{feature}` has been stable since {since} and no longer requires an \
-             attribute to enable",
-        ))
-        .emit();
+    tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, format!("the feature `{feature}` has been stable since {since} and no longer requires an attribute to enable"), |lint| {
+        lint
     });
 }
 
index dc585fca34f8c7817b1f16bea5e11d04ff8773d4..3f98db6b2a924adfb9de5ee661a5d683cc58fd53 100644 (file)
@@ -235,14 +235,18 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
                   .emit()
             }
 
-            Err(ErrorHandled::TooGeneric) => Err(if uv.has_infer_types_or_consts() {
-                NotConstEvaluatable::MentionsInfer
+            Err(ErrorHandled::TooGeneric) => {
+                let err = if uv.has_infer_types_or_consts() {
+                    NotConstEvaluatable::MentionsInfer
                 } else if uv.has_param_types_or_consts() {
-                NotConstEvaluatable::MentionsParam
-            } else {
-                let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?"));
-                NotConstEvaluatable::Error(guar)
-            }),
+                    NotConstEvaluatable::MentionsParam
+                } else {
+                    let guar = infcx.tcx.sess.delay_span_bug(span, format!("Missing value for constant, but no error reported?"));
+                    NotConstEvaluatable::Error(guar)
+                };
+
+                Err(err)
+            },
             Err(ErrorHandled::Linted) => {
                 let reported =
                     infcx.tcx.sess.delay_span_bug(span, "constant in type had error reported as lint");
@@ -250,23 +254,23 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
             }
             Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
             Ok(_) => {
-              if uv.substs.has_param_types_or_consts() {
-                  assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
-                  let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
+                if uv.substs.has_param_types_or_consts() {
+                    assert!(matches!(infcx.tcx.def_kind(uv.def.did), DefKind::AnonConst));
+                    let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(uv.def);
 
-                  if mir_body.is_polymorphic {
-                      let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
-                      tcx.struct_span_lint_hir(
-                          lint::builtin::CONST_EVALUATABLE_UNCHECKED,
-                          tcx.hir().local_def_id_to_hir_id(local_def_id),
-                          span,
-                          |err| {
-                              err.build("cannot use constants which depend on generic parameters in types").emit();
-                        })
-                  }
-              }
+                    if mir_body.is_polymorphic {
+                        let Some(local_def_id) = uv.def.did.as_local() else { return Ok(()) };
+                        tcx.struct_span_lint_hir(
+                            lint::builtin::CONST_EVALUATABLE_UNCHECKED,
+                            tcx.hir().local_def_id_to_hir_id(local_def_id),
+                            span,
+                            "cannot use constants which depend on generic parameters in types",
+                            |err| err
+                        )
+                    }
+                }
 
-              Ok(())
+                Ok(())
             },
         }
     }
index 2773b61e9ba620ad129afebe0a1b54513599f11a..8f87a7fdeba5eaf7ac69a83eeb9e6ba29fee22b2 100644 (file)
@@ -14,7 +14,7 @@
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::{self, Obligation, ObligationCause};
 use hir::def::DefKind;
-use rustc_errors::{FatalError, MultiSpan};
+use rustc_errors::{DelayDm, FatalError, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::abstract_const::{walk_abstract_const, AbstractConst};
@@ -164,37 +164,42 @@ fn lint_object_unsafe_trait(
 ) {
     // Using `CRATE_NODE_ID` is wrong, but it's hard to get a more precise id.
     // It's also hard to get a use site span, so we use the method definition span.
-    tcx.struct_span_lint_hir(WHERE_CLAUSES_OBJECT_SAFETY, hir::CRATE_HIR_ID, span, |lint| {
-        let mut err = lint.build(&format!(
-            "the trait `{}` cannot be made into an object",
-            tcx.def_path_str(trait_def_id)
-        ));
-        let node = tcx.hir().get_if_local(trait_def_id);
-        let mut spans = MultiSpan::from_span(span);
-        if let Some(hir::Node::Item(item)) = node {
-            spans.push_span_label(item.ident.span, "this trait cannot be made into an object...");
-            spans.push_span_label(span, format!("...because {}", violation.error_msg()));
-        } else {
-            spans.push_span_label(
-                span,
-                format!(
-                    "the trait cannot be made into an object because {}",
-                    violation.error_msg()
-                ),
+    tcx.struct_span_lint_hir(
+        WHERE_CLAUSES_OBJECT_SAFETY,
+        hir::CRATE_HIR_ID,
+        span,
+        DelayDm(|| format!("the trait `{}` cannot be made into an object", tcx.def_path_str(trait_def_id))),
+        |err| {
+            let node = tcx.hir().get_if_local(trait_def_id);
+            let mut spans = MultiSpan::from_span(span);
+            if let Some(hir::Node::Item(item)) = node {
+                spans.push_span_label(
+                    item.ident.span,
+                    "this trait cannot be made into an object...",
+                );
+                spans.push_span_label(span, format!("...because {}", violation.error_msg()));
+            } else {
+                spans.push_span_label(
+                    span,
+                    format!(
+                        "the trait cannot be made into an object because {}",
+                        violation.error_msg()
+                    ),
+                );
+            };
+            err.span_note(
+                spans,
+                "for a trait to be \"object safe\" it needs to allow building a vtable to allow the \
+                call to be resolvable dynamically; for more information visit \
+                <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
             );
-        };
-        err.span_note(
-            spans,
-            "for a trait to be \"object safe\" it needs to allow building a vtable to allow the \
-             call to be resolvable dynamically; for more information visit \
-             <https://doc.rust-lang.org/reference/items/traits.html#object-safety>",
-        );
-        if node.is_some() {
-            // Only provide the help if its a local trait, otherwise it's not
-            violation.solution(&mut err);
-        }
-        err.emit();
-    });
+            if node.is_some() {
+                // Only provide the help if its a local trait, otherwise it's not
+                violation.solution(err);
+            }
+            err
+        },
+    );
 }
 
 fn sized_trait_bound_spans<'tcx>(
index 451427a69807d7ba4134f66c2c04584290df7974..6d856435355ed47fdaa94ed40040a7db69f98e4c 100644 (file)
@@ -6,6 +6,7 @@
 //!
 //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly
 use hir::LangItem;
+use rustc_errors::DelayDm;
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_infer::traits::ObligationCause;
@@ -825,13 +826,11 @@ fn assemble_candidates_for_unsizing(
                                     DEREF_INTO_DYN_SUPERTRAIT,
                                     obligation.cause.body_id,
                                     obligation.cause.span,
-                                    |lint| {
-                                        lint.build(&format!(
-                                            "`{}` implements `Deref` with supertrait `{}` as output",
-                                            source,
-                                            deref_output_ty
-                                        )).emit();
-                                    },
+                                    DelayDm(|| format!(
+                                        "`{}` implements `Deref` with supertrait `{}` as output",
+                                        source, deref_output_ty
+                                    )),
+                                    |lint| lint,
                                 );
                                 return;
                             }
index 56a88749c46adf842b67cfc67a539f508df4da25..eac3f0f30e8b553e5dea47f44801a213e55c0fcf 100644 (file)
@@ -17,7 +17,7 @@
 use crate::traits::select::IntercrateAmbiguityCause;
 use crate::traits::{self, coherence, FutureCompatOverlapErrorKind, ObligationCause};
 use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_errors::{struct_span_err, EmissionGuarantee, LintDiagnosticBuilder};
+use rustc_errors::{struct_span_err, DiagnosticBuilder, EmissionGuarantee};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::ty::{self, ImplSubject, TyCtxt};
 use rustc_middle::ty::{InternalSubsts, SubstsRef};
@@ -350,26 +350,12 @@ fn report_conflicting_impls(
     // Work to be done after we've built the DiagnosticBuilder. We have to define it
     // now because the struct_lint methods don't return back the DiagnosticBuilder
     // that's passed in.
-    fn decorate<G: EmissionGuarantee>(
+    fn decorate<'a, 'b, G: EmissionGuarantee>(
         tcx: TyCtxt<'_>,
         overlap: OverlapError,
-        used_to_be_allowed: Option<FutureCompatOverlapErrorKind>,
         impl_span: Span,
-        err: LintDiagnosticBuilder<'_, G>,
-    ) -> G {
-        let msg = format!(
-            "conflicting implementations of trait `{}`{}{}",
-            overlap.trait_desc,
-            overlap
-                .self_desc
-                .clone()
-                .map_or_else(String::new, |ty| { format!(" for type `{}`", ty) }),
-            match used_to_be_allowed {
-                Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
-                _ => "",
-            }
-        );
-        let mut err = err.build(&msg);
+        err: &'b mut DiagnosticBuilder<'a, G>,
+    ) -> &'b mut DiagnosticBuilder<'a, G> {
         match tcx.span_of_impl(overlap.with_impl) {
             Ok(span) => {
                 err.span_label(span, "first implementation here");
@@ -384,7 +370,9 @@ fn decorate<G: EmissionGuarantee>(
             }
             Err(cname) => {
                 let msg = match to_pretty_impl_header(tcx, overlap.with_impl) {
-                    Some(s) => format!("conflicting implementation in crate `{}`:\n- {}", cname, s),
+                    Some(s) => {
+                        format!("conflicting implementation in crate `{}`:\n- {}", cname, s)
+                    }
                     None => format!("conflicting implementation in crate `{}`", cname),
                 };
                 err.note(&msg);
@@ -392,28 +380,33 @@ fn decorate<G: EmissionGuarantee>(
         }
 
         for cause in &overlap.intercrate_ambiguity_causes {
-            cause.add_intercrate_ambiguity_hint(&mut err);
+            cause.add_intercrate_ambiguity_hint(err);
         }
 
         if overlap.involves_placeholder {
-            coherence::add_placeholder_note(&mut err);
+            coherence::add_placeholder_note(err);
         }
-        err.emit()
+        err
     }
 
+    let msg = format!(
+        "conflicting implementations of trait `{}`{}{}",
+        overlap.trait_desc,
+        overlap.self_desc.as_deref().map_or_else(String::new, |ty| format!(" for type `{ty}`")),
+        match used_to_be_allowed {
+            Some(FutureCompatOverlapErrorKind::Issue33140) => ": (E0119)",
+            _ => "",
+        }
+    );
+
     match used_to_be_allowed {
         None => {
             let reported = if overlap.with_impl.is_local()
                 || tcx.orphan_check_impl(impl_def_id).is_ok()
             {
-                let err = struct_span_err!(tcx.sess, impl_span, E0119, "");
-                Some(decorate(
-                    tcx,
-                    overlap,
-                    used_to_be_allowed,
-                    impl_span,
-                    LintDiagnosticBuilder::new(err),
-                ))
+                let mut err = struct_span_err!(tcx.sess, impl_span, E0119, "{msg}",);
+                decorate(tcx, overlap, impl_span, &mut err);
+                Some(err.emit())
             } else {
                 Some(tcx.sess.delay_span_bug(impl_span, "impl should have failed the orphan check"))
             };
@@ -428,9 +421,8 @@ fn decorate<G: EmissionGuarantee>(
                 lint,
                 tcx.hir().local_def_id_to_hir_id(impl_def_id),
                 impl_span,
-                |ldb| {
-                    decorate(tcx, overlap, used_to_be_allowed, impl_span, ldb);
-                },
+                msg,
+                |err| decorate(tcx, overlap, impl_span, err),
             );
         }
     };