diff options
| author | bors <bors@rust-lang.org> | 2022-10-01 10:44:25 +0000 | 
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-10-01 10:44:25 +0000 | 
| commit | 744e397d8855f7da87d70aa8d0bd9e0f5f0b51a1 (patch) | |
| tree | 1721987352b5f0a8548fc46984821d974b661934 /compiler | |
| parent | 277bb6653b55475b5fbce6309e9852fa2100dabe (diff) | |
| parent | b5b3ffe3fc9cfb524a6432ec60a0fc95c514d2e1 (diff) | |
| download | rust-744e397d8855f7da87d70aa8d0bd9e0f5f0b51a1.tar.gz rust-744e397d8855f7da87d70aa8d0bd9e0f5f0b51a1.zip | |
Auto merge of #101986 - WaffleLapkin:move_lint_note_to_the_bottom, r=estebank
Move lint level source explanation to the bottom So, uhhhhh r? `@estebank` ## User-facing change "note: `#[warn(...)]` on by default" and such are moved to the bottom of the diagnostic: ```diff - = note: `#[warn(unsupported_calling_conventions)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678> + = note: `#[warn(unsupported_calling_conventions)]` on by default ``` Why warning is enabled is the least important thing, so it shouldn't be the first note the user reads, IMO. ## Developer-facing change `struct_span_lint` and similar methods have a different signature. Before: `..., impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>)` After: `..., impl Into<DiagnosticMessage>, impl for<'a, 'b> FnOnce(&'b mut DiagnosticBuilder<'a, ()>) -> &'b mut DiagnosticBuilder<'a, ()>` The reason for this is that `struct_span_lint` needs to edit the diagnostic _after_ `decorate` closure is called. This also makes lint code a little bit nicer in my opinion. Another option is to use `impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>) -> DiagnosticBuilder<'a, ()>` altough I don't _really_ see reasons to do `let lint = lint.build(message)` everywhere. ## Subtle problem By moving the message outside of the closure (that may not be called if the lint is disabled) `format!(...)` is executed earlier, possibly formatting `Ty` which may call a query that trims paths that crashes the compiler if there were no warnings... I don't think it's that big of a deal, considering that we move from `format!(...)` to `fluent` (which is lazy by-default) anyway, however this required adding a workaround which is unfortunate. ## P.S. I'm sorry, I do not how to make this PR smaller/easier to review. Changes to the lint API affect SO MUCH 😢
Diffstat (limited to 'compiler')
65 files changed, 1762 insertions, 1582 deletions
| diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 09d53331b5b..09c92ae0361 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -233,10 +233,10 @@ impl<'tcx> ConstEvalErr<'tcx> { 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 diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index abf98a9621e..bf9248f99b6 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -358,6 +358,17 @@ impl<S: Into<String>> From<S> for DiagnosticMessage { } } +/// 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 diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 5520e22e476..49dcc2ba021 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -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] diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 092a77f944c..bbe6435be59 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -642,27 +642,3 @@ macro_rules! struct_span_err { macro_rules! error_code { ($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }}; } - -/// Wrapper around a `DiagnosticBuilder` for creating lints. -pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>); - -impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> { - #[rustc_lint_diagnostics] - /// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`. - pub fn build(mut self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'a, G> { - self.0.set_primary_message(msg); - self.0.set_is_lint(); - self.0 - } - - /// Create a `LintDiagnosticBuilder` from some existing `DiagnosticBuilder`. - pub fn new(err: DiagnosticBuilder<'a, G>) -> LintDiagnosticBuilder<'a, G> { - LintDiagnosticBuilder(err) - } -} - -impl<'a> LintDiagnosticBuilder<'a, ErrorGuaranteed> { - pub fn forget_guarantee(self) -> LintDiagnosticBuilder<'a, ()> { - LintDiagnosticBuilder(self.0.forget_guarantee()) - } -} diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index c6ede209e65..c8711ec6e25 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -30,7 +30,7 @@ use rustc_data_structures::stable_hasher::StableHasher; 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, }; @@ -374,7 +374,7 @@ pub use diagnostic::{ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; -pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder}; +pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee}; use std::backtrace::Backtrace; /// A handler deals with errors and other compiler output. diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index fbb0c8918d2..b66e59d8ac6 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -649,9 +649,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { LATE_BOUND_LIFETIME_ARGUMENTS, args.args[0].hir_id(), multispan, - |lint| { - lint.build(msg).emit(); - }, + msg, + |lint| lint, ); } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index ea6da299b8f..6e373e41b4c 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2010,30 +2010,35 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { tcx.check_stability(item.def_id, Some(hir_ref_id), span, None); if let Some(variant_def_id) = variant_resolution { - tcx.struct_span_lint_hir(AMBIGUOUS_ASSOCIATED_ITEMS, hir_ref_id, span, |lint| { - let mut err = lint.build("ambiguous associated item"); - let mut could_refer_to = |kind: DefKind, def_id, also| { - let note_msg = format!( - "`{}` could{} refer to the {} defined here", - assoc_ident, - also, - kind.descr(def_id) - ); - err.span_note(tcx.def_span(def_id), ¬e_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), ¬e_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)) } @@ -3079,15 +3084,15 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { BARE_TRAIT_OBJECTS, self_ty.hir_id, self_ty.span, + msg, |lint| { - let mut diag = lint.build(msg); - diag.multipart_suggestion_verbose( + lint.multipart_suggestion_verbose( "use `dyn`", sugg, Applicability::MachineApplicable, ); - self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag); - diag.emit(); + self.maybe_lint_blanket_trait_impl(&self_ty, lint); + lint }, ); } diff --git a/compiler/rustc_hir_analysis/src/check/cast.rs b/compiler/rustc_hir_analysis/src/check/cast.rs index 81a979865ac..01badc133c9 100644 --- a/compiler/rustc_hir_analysis/src/check/cast.rs +++ b/compiler/rustc_hir_analysis/src/check/cast.rs @@ -33,7 +33,7 @@ use super::FnCtxt; use crate::hir::def_id::DefId; use crate::type_error_struct; use hir::def_id::LOCAL_CRATE; -use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{struct_span_err, Applicability, DelayDm, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode}; use rustc_middle::mir::Mutability; @@ -754,19 +754,25 @@ impl<'a, 'tcx> CastCheck<'tcx> { } else { ("", lint::builtin::TRIVIAL_CASTS) }; - fcx.tcx.struct_span_lint_hir(lint, self.expr.hir_id, self.span, |err| { - err.build(&format!( - "trivial {}cast: `{}` as `{}`", - adjective, - fcx.ty_to_string(t_expr), - fcx.ty_to_string(t_cast) - )) - .help(&format!( - "cast can be replaced by coercion; this might \ - require {type_asc_or}a temporary variable" - )) - .emit(); - }); + fcx.tcx.struct_span_lint_hir( + lint, + self.expr.hir_id, + self.span, + DelayDm(|| { + format!( + "trivial {}cast: `{}` as `{}`", + adjective, + fcx.ty_to_string(t_expr), + fcx.ty_to_string(t_cast) + ) + }), + |lint| { + lint.help(format!( + "cast can be replaced by coercion; this might \ + require {type_asc_or}a temporary variable" + )) + }, + ); } #[instrument(skip(fcx), level = "debug")] @@ -1074,12 +1080,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { lint::builtin::CENUM_IMPL_DROP_CAST, self.expr.hir_id, self.span, - |err| { - err.build(&format!( - "cannot cast enum `{}` into integer `{}` because it implements `Drop`", - self.expr_ty, self.cast_ty - )) - .emit(); + DelayDm(|| format!( + "cannot cast enum `{}` into integer `{}` because it implements `Drop`", + self.expr_ty, self.cast_ty + )), + |lint| { + lint }, ); } @@ -1090,12 +1096,11 @@ impl<'a, 'tcx> CastCheck<'tcx> { lint::builtin::LOSSY_PROVENANCE_CASTS, self.expr.hir_id, self.span, - |err| { - let mut err = err.build(&format!( + DelayDm(|| format!( "under strict provenance it is considered bad style to cast pointer `{}` to integer `{}`", self.expr_ty, self.cast_ty - )); - + )), + |lint| { let msg = "use `.addr()` to obtain the address of a pointer"; let expr_prec = self.expr.precedence().order(); @@ -1114,9 +1119,9 @@ impl<'a, 'tcx> CastCheck<'tcx> { (cast_span, format!(").addr(){scalar_cast}")), ]; - err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); + lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); } else { - err.span_suggestion( + lint.span_suggestion( cast_span, msg, format!(".addr(){scalar_cast}"), @@ -1124,12 +1129,12 @@ impl<'a, 'tcx> CastCheck<'tcx> { ); } - err.help( + lint.help( "if you can't comply with strict provenance and need to expose the pointer \ provenance you can use `.expose_addr()` instead" ); - err.emit(); + lint }, ); } @@ -1139,24 +1144,24 @@ impl<'a, 'tcx> CastCheck<'tcx> { lint::builtin::FUZZY_PROVENANCE_CASTS, self.expr.hir_id, self.span, - |err| { - let mut err = err.build(&format!( - "strict provenance disallows casting integer `{}` to pointer `{}`", - self.expr_ty, self.cast_ty - )); + DelayDm(|| format!( + "strict provenance disallows casting integer `{}` to pointer `{}`", + self.expr_ty, self.cast_ty + )), + |lint| { let msg = "use `.with_addr()` to adjust a valid pointer in the same allocation, to this address"; let suggestions = vec![ (self.expr_span.shrink_to_lo(), String::from("(...).with_addr(")), (self.expr_span.shrink_to_hi().to(self.cast_span), String::from(")")), ]; - err.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); - err.help( + lint.multipart_suggestion(msg, suggestions, Applicability::MaybeIncorrect); + lint.help( "if you can't comply with strict provenance and don't have a pointer with \ the correct provenance you can use `std::ptr::from_exposed_addr()` instead" ); - err.emit(); + lint }, ); } diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 4bbe9abaf98..824144aeac0 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -48,9 +48,13 @@ pub(super) fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ab .emit(); } None => { - tcx.struct_span_lint_hir(UNSUPPORTED_CALLING_CONVENTIONS, hir_id, span, |lint| { - lint.build("use of calling convention not supported on this target").emit(); - }); + tcx.struct_span_lint_hir( + UNSUPPORTED_CALLING_CONVENTIONS, + hir_id, + span, + "use of calling convention not supported on this target", + |lint| lint, + ); } } @@ -510,10 +514,10 @@ fn check_static_inhabited<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { UNINHABITED_STATIC, tcx.hir().local_def_id_to_hir_id(def_id), span, + "static of uninhabited type", |lint| { - lint.build("static of uninhabited type") + lint .note("uninhabited statics cannot be initialized, and any access would be an immediate error") - .emit(); }, ); } @@ -1437,6 +1441,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()), span, + "zero-sized fields in `repr(transparent)` cannot contain external non-exhaustive types", |lint| { let note = if non_exhaustive { "is marked with `#[non_exhaustive]`" @@ -1444,10 +1449,9 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD "contains private fields" }; let field_ty = tcx.def_path_str_with_substs(def_id, substs); - lint.build("zero-sized fields in repr(transparent) cannot contain external non-exhaustive types") + lint .note(format!("this {descr} contains `{field_ty}`, which {note}, \ and makes it not a breaking change to become non-zero-sized in the future.")) - .emit(); }, ) } diff --git a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs b/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs index 4522678802b..4bd5e9f6ab5 100644 --- a/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_analysis/src/check/fn_ctxt/_impl.rs @@ -58,17 +58,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); - self.tcx().struct_span_lint_hir(lint::builtin::UNREACHABLE_CODE, id, span, |lint| { - let msg = format!("unreachable {}", kind); - lint.build(&msg) - .span_label(span, &msg) - .span_label( + let msg = format!("unreachable {}", kind); + self.tcx().struct_span_lint_hir( + lint::builtin::UNREACHABLE_CODE, + id, + span, + &msg, + |lint| { + lint.span_label(span, &msg).span_label( orig_span, custom_note .unwrap_or("any code following this expression is unreachable"), ) - .emit(); - }) + }, + ) } } } diff --git a/compiler/rustc_hir_analysis/src/check/generator_interior.rs b/compiler/rustc_hir_analysis/src/check/generator_interior.rs index 254a19368bf..898419b5b23 100644 --- a/compiler/rustc_hir_analysis/src/check/generator_interior.rs +++ b/compiler/rustc_hir_analysis/src/check/generator_interior.rs @@ -6,7 +6,7 @@ use self::drop_ranges::DropRanges; use super::FnCtxt; use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; -use rustc_errors::pluralize; +use rustc_errors::{pluralize, DelayDm}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -610,33 +610,33 @@ fn check_must_not_suspend_def( rustc_session::lint::builtin::MUST_NOT_SUSPEND, hir_id, data.source_span, - |lint| { - let msg = format!( + DelayDm(|| { + format!( "{}`{}`{} held across a suspend point, but should not be", data.descr_pre, tcx.def_path_str(def_id), data.descr_post, - ); - let mut err = lint.build(&msg); - + ) + }), + |lint| { // add span pointing to the offending yield/await - err.span_label(data.yield_span, "the value is held across this suspend point"); + lint.span_label(data.yield_span, "the value is held across this suspend point"); // Add optional reason note if let Some(note) = attr.value_str() { // FIXME(guswynn): consider formatting this better - err.span_note(data.source_span, note.as_str()); + lint.span_note(data.source_span, note.as_str()); } // Add some quick suggestions on what to do // FIXME: can `drop` work as a suggestion here as well? - err.span_help( + lint.span_help( data.source_span, "consider using a block (`{ ... }`) \ to shrink the value's scope, ending before the suspend point", ); - err.emit(); + lint }, ); diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs index d8fe63dbf08..c604c8af8d2 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs @@ -328,17 +328,16 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> { lint::builtin::ASM_SUB_REGISTER, expr.hir_id, spans, + "formatting may not be suitable for sub-register argument", |lint| { - let msg = "formatting may not be suitable for sub-register argument"; - let mut err = lint.build(msg); - err.span_label(expr.span, "for this argument"); - err.help(&format!( + lint.span_label(expr.span, "for this argument"); + lint.help(&format!( "use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`", )); - err.help(&format!( + lint.help(&format!( "or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`", )); - err.emit(); + lint }, ); } diff --git a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs b/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs index 392695cca68..ca4cdf5a0d0 100644 --- a/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs +++ b/compiler/rustc_hir_analysis/src/check/method/prelude2021.rs @@ -82,14 +82,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prelude_or_array_lint, self_expr.hir_id, self_expr.span, + format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name), |lint| { let sp = self_expr.span; - let mut lint = lint.build(&format!( - "trait method `{}` will become ambiguous in Rust 2021", - segment.ident.name - )); - let derefs = "*".repeat(pick.autoderefs); let autoref = match pick.autoref_or_ptr_adjustment { @@ -133,7 +129,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - lint.emit(); + lint }, ); } else { @@ -143,6 +139,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prelude_or_array_lint, call_expr.hir_id, call_expr.span, + format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name), |lint| { let sp = call_expr.span; let trait_name = self.trait_path_or_bare_name( @@ -151,11 +148,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pick.item.container_id(self.tcx), ); - let mut lint = lint.build(&format!( - "trait method `{}` will become ambiguous in Rust 2021", - segment.ident.name - )); - let (self_adjusted, precise) = self.adjust_expr(pick, self_expr, sp); if precise { let args = args @@ -202,7 +194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - lint.emit(); + lint }, ); } @@ -257,15 +249,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return; } - self.tcx.struct_span_lint_hir(RUST_2021_PRELUDE_COLLISIONS, expr_id, span, |lint| { - // "type" refers to either a type or, more likely, a trait from which - // the associated function or method is from. - let container_id = pick.item.container_id(self.tcx); - let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id); - let trait_generics = self.tcx.generics_of(container_id); - - let trait_name = - if trait_generics.params.len() <= trait_generics.has_self as usize { + self.tcx.struct_span_lint_hir( + RUST_2021_PRELUDE_COLLISIONS, + expr_id, + span, + format!( + "trait-associated function `{}` will become ambiguous in Rust 2021", + method_name.name + ), + |lint| { + // "type" refers to either a type or, more likely, a trait from which + // the associated function or method is from. + let container_id = pick.item.container_id(self.tcx); + let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id); + let trait_generics = self.tcx.generics_of(container_id); + + let trait_name = if trait_generics.params.len() <= trait_generics.has_self as usize + { trait_path } else { let counts = trait_generics.own_counts(); @@ -282,44 +282,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }; - let mut lint = lint.build(&format!( - "trait-associated function `{}` will become ambiguous in Rust 2021", - method_name.name - )); - - let mut self_ty_name = self_ty_span - .find_ancestor_inside(span) - .and_then(|span| self.sess().source_map().span_to_snippet(span).ok()) - .unwrap_or_else(|| self_ty.to_string()); - - // Get the number of generics the self type has (if an Adt) unless we can determine that - // the user has written the self type with generics already which we (naively) do by looking - // for a "<" in `self_ty_name`. - if !self_ty_name.contains('<') { - if let Adt(def, _) = self_ty.kind() { - let generics = self.tcx.generics_of(def.did()); - if !generics.params.is_empty() { - let counts = generics.own_counts(); - self_ty_name += &format!( - "<{}>", - std::iter::repeat("'_") - .take(counts.lifetimes) - .chain(std::iter::repeat("_").take(counts.types + counts.consts)) - .collect::<Vec<_>>() - .join(", ") - ); + let mut self_ty_name = self_ty_span + .find_ancestor_inside(span) + .and_then(|span| self.sess().source_map().span_to_snippet(span).ok()) + .unwrap_or_else(|| self_ty.to_string()); + + // Get the number of generics the self type has (if an Adt) unless we can determine that + // the user has written the self type with generics already which we (naively) do by looking + // for a "<" in `self_ty_name`. + if !self_ty_name.contains('<') { + if let Adt(def, _) = self_ty.kind() { + let generics = self.tcx.generics_of(def.did()); + if !generics.params.is_empty() { + let counts = generics.own_counts(); + self_ty_name += &format!( + "<{}>", + std::iter::repeat("'_") + .take(counts.lifetimes) + .chain( + std::iter::repeat("_").take(counts.types + counts.consts) + ) + .collect::<Vec<_>>() + .join(", ") + ); + } } } - } - lint.span_suggestion( - span, - "disambiguate the associated function", - format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,), - Applicability::MachineApplicable, - ); - - lint.emit(); - }); + lint.span_suggestion( + span, + "disambiguate the associated function", + format!("<{} as {}>::{}", self_ty_name, trait_name, method_name.name,), + Applicability::MachineApplicable, + ); + + lint + }, + ); } fn trait_path_or_bare_name( diff --git a/compiler/rustc_hir_analysis/src/check/method/probe.rs b/compiler/rustc_hir_analysis/src/check/method/probe.rs index 6cd7ced01a3..a761a93dea4 100644 --- a/compiler/rustc_hir_analysis/src/check/method/probe.rs +++ b/compiler/rustc_hir_analysis/src/check/method/probe.rs @@ -409,9 +409,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lint::builtin::TYVAR_BEHIND_RAW_POINTER, scope_expr_id, span, - |lint| { - lint.build("type annotations needed").emit(); - }, + "type annotations needed", + |lint| lint, ); } } else { @@ -1358,24 +1357,24 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { stable_pick: &Pick<'_>, unstable_candidates: &[(Candidate<'tcx>, Symbol)], ) { + let def_kind = stable_pick.item.kind.as_def_kind(); self.tcx.struct_span_lint_hir( lint::builtin::UNSTABLE_NAME_COLLISIONS, self.scope_expr_id, self.span, + format!( + "{} {} with this name may be added to the standard library in the future", + def_kind.article(), + def_kind.descr(stable_pick.item.def_id), + ), |lint| { - let def_kind = stable_pick.item.kind.as_def_kind(); - let mut diag = lint.build(&format!( - "{} {} with this name may be added to the standard library in the future", - def_kind.article(), - def_kind.descr(stable_pick.item.def_id), - )); match (stable_pick.item.kind, stable_pick.item.container) { (ty::AssocKind::Fn, _) => { // FIXME: This should be a `span_suggestion` instead of `help` // However `self.span` only // highlights the method name, so we can't use it. Also consider reusing // the code from `report_method_error()`. - diag.help(&format!( + lint.help(&format!( "call with fully qualified syntax `{}(...)` to keep using the current \ method", self.tcx.def_path_str(stable_pick.item.def_id), @@ -1383,7 +1382,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } (ty::AssocKind::Const, ty::AssocItemContainer::TraitContainer) => { let def_id = stable_pick.item.container_id(self.tcx); - diag.span_suggestion( + lint.span_suggestion( self.span, "use the fully qualified path to the associated const", format!( @@ -1399,7 +1398,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } if self.tcx.sess.is_nightly_build() { for (candidate, feature) in unstable_candidates { - diag.help(&format!( + lint.help(&format!( "add `#![feature({})]` to the crate attributes to enable `{}`", feature, self.tcx.def_path_str(candidate.item.def_id), @@ -1407,7 +1406,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - diag.emit(); + lint }, ); } diff --git a/compiler/rustc_hir_analysis/src/check/pat.rs b/compiler/rustc_hir_analysis/src/check/pat.rs index 8906b622b68..178326cfdc4 100644 --- a/compiler/rustc_hir_analysis/src/check/pat.rs +++ b/compiler/rustc_hir_analysis/src/check/pat.rs @@ -1790,10 +1790,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &unmentioned_fields.iter().map(|(_, i)| i).collect::<Vec<_>>(), ); - self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, |build| { - let mut lint = build.build("some fields are not explicitly listed"); + self.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, pat.hir_id, pat.span, "some fields are not explicitly listed", |lint| { lint.span_label(pat.span, format!("field{} {} not listed", rustc_errors::pluralize!(unmentioned_fields.len()), joined_patterns)); - lint.help( "ensure that all fields are mentioned explicitly by adding the suggested fields", ); @@ -1801,7 +1799,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found", ty, )); - lint.emit(); + + lint }); } diff --git a/compiler/rustc_hir_analysis/src/check/upvar.rs b/compiler/rustc_hir_analysis/src/check/upvar.rs index 0b207a6c0be..4f495641691 100644 --- a/compiler/rustc_hir_analysis/src/check/upvar.rs +++ b/compiler/rustc_hir_analysis/src/check/upvar.rs @@ -749,10 +749,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, closure_hir_id, closure_head_span, + reasons.migration_message(), |lint| { - let mut diagnostics_builder = lint.build( - &reasons.migration_message(), - ); for NeededMigration { var_hir_id, diagnostics_info } in &need_migrations { // Labels all the usage of the captured variable and why they are responsible // for migration being needed @@ -760,13 +758,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &lint_note.captures_info { UpvarMigrationInfo::CapturingPrecise { source_expr: Some(capture_expr_id), var_name: captured_name } => { let cause_span = self.tcx.hir().span(*capture_expr_id); - diagnostics_builder.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", + lint.span_label(cause_span, format!("in Rust 2018, this closure captures all of `{}`, but in Rust 2021, it will only capture `{}`", self.tcx.hir().name(*var_hir_id), captured_name, )); } UpvarMigrationInfo::CapturingNothing { use_span } => { - diagnostics_builder.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect", + lint.span_label(*use_span, format!("in Rust 2018, this causes the closure to capture `{}`, but in Rust 2021, it has no effect", self.tcx.hir().name(*var_hir_id), )); } @@ -781,13 +779,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &lint_note.captures_info { UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { - diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", + lint.span_label(drop_location_span, format!("in Rust 2018, `{}` is dropped here, but in Rust 2021, only `{}` will be dropped here as part of the closure", self.tcx.hir().name(*var_hir_id), captured_name, )); } UpvarMigrationInfo::CapturingNothing { use_span: _ } => { - diagnostics_builder.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", + lint.span_label(drop_location_span, format!("in Rust 2018, `{v}` is dropped here along with the closure, but in Rust 2021 `{v}` is not part of the closure", v = self.tcx.hir().name(*var_hir_id), )); } @@ -800,7 +798,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match &lint_note.captures_info { UpvarMigrationInfo::CapturingPrecise { var_name: captured_name, .. } => { let var_name = self.tcx.hir().name(*var_hir_id); - diagnostics_builder.span_label(closure_head_span, format!("\ + lint.span_label(closure_head_span, format!("\ in Rust 2018, this closure implements {missing_trait} \ as `{var_name}` implements {missing_trait}, but in Rust 2021, \ this closure will no longer implement {missing_trait} \ @@ -814,7 +812,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - diagnostics_builder.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>"); + lint.note("for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>"); let diagnostic_msg = format!( "add a dummy let to cause {} to be fully captured", @@ -857,7 +855,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We take the indentation from the next non-empty line. let line2 = lines.find(|line| !line.is_empty()).unwrap_or_default(); let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0; - diagnostics_builder.span_suggestion( + lint.span_suggestion( closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(), &diagnostic_msg, format!("\n{indent}{migration_string};"), @@ -868,7 +866,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // braces, but with more than just the opening // brace on the first line. We put the `let` // directly after the `{`. - diagnostics_builder.span_suggestion( + lint.span_suggestion( closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(), &diagnostic_msg, format!(" {migration_string};"), @@ -877,7 +875,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { // This is a closure without braces around the body. // We add braces to add the `let` before the body. - diagnostics_builder.multipart_suggestion( + lint.multipart_suggestion( &diagnostic_msg, vec![ (closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")), @@ -887,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } else { - diagnostics_builder.span_suggestion( + lint.span_suggestion( closure_span, &diagnostic_msg, migration_string, @@ -895,7 +893,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - diagnostics_builder.emit(); + lint }, ); } diff --git a/compiler/rustc_hir_analysis/src/check_unused.rs b/compiler/rustc_hir_analysis/src/check_unused.rs index 1d23ed92921..922833f8580 100644 --- a/compiler/rustc_hir_analysis/src/check_unused.rs +++ b/compiler/rustc_hir_analysis/src/check_unused.rs @@ -29,14 +29,18 @@ pub fn check_crate(tcx: TyCtxt<'_>) { continue; } let hir::ItemKind::Use(path, _) = item.kind else { unreachable!() }; - tcx.struct_span_lint_hir(lint::builtin::UNUSED_IMPORTS, item.hir_id(), path.span, |lint| { - let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { - format!("unused import: `{}`", snippet) - } else { - "unused import".to_owned() - }; - lint.build(&msg).emit(); - }); + let msg = if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(path.span) { + format!("unused import: `{}`", snippet) + } else { + "unused import".to_owned() + }; + tcx.struct_span_lint_hir( + lint::builtin::UNUSED_IMPORTS, + item.hir_id(), + path.span, + msg, + |lint| lint, + ); } unused_crates_lint(tcx); diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 7d15e5a7f3c..1307f74f210 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -2,7 +2,7 @@ //! crate or pertains to a type defined in this crate. use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; +use rustc_errors::{struct_span_err, DelayDm}; use rustc_errors::{Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; use rustc_middle::ty::subst::GenericArgKind; @@ -412,30 +412,31 @@ fn lint_auto_trait_impl<'tcx>( lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS, tcx.hir().local_def_id_to_hir_id(impl_def_id), tcx.def_span(impl_def_id), - |err| { - let item_span = tcx.def_span(self_type_did); - let self_descr = tcx.def_kind(self_type_did).descr(self_type_did); - let mut err = err.build(&format!( + DelayDm(|| { + format!( "cross-crate traits with a default impl, like `{}`, \ should not be specialized", tcx.def_path_str(trait_ref.def_id), - )); + ) + }), + |lint| { + let item_span = tcx.def_span(self_type_did); + let self_descr = tcx.def_kind(self_type_did).descr(self_type_did); match arg { ty::util::NotUniqueParam::DuplicateParam(arg) => { - err.note(&format!("`{}` is mentioned multiple times", arg)); + lint.note(&format!("`{}` is mentioned multiple times", arg)); } ty::util::NotUniqueParam::NotParam(arg) => { - err.note(&format!("`{}` is not a generic parameter", arg)); + lint.note(&format!("`{}` is not a generic parameter", arg)); } } - err.span_note( + lint.span_note( item_span, &format!( "try using the same sequence of generic parameters as the {} definition", self_descr, ), - ); - err.emit(); + ) }, ); } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 8cd0a84274e..ab4b861b6cb 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -2067,11 +2067,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: DefId) -> CodegenFnAttrs { lint::builtin::INLINE_NO_SANITIZE, hir_id, no_sanitize_span, - |lint| { - lint.build("`no_sanitize` will have no effect after inlining") - .span_note(inline_span, "inlining requested here") - .emit(); - }, + "`no_sanitize` will have no effect after inlining", + |lint| lint.span_note(inline_span, "inlining requested here"), ) } } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 1deff17e840..7ffacbecf5f 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -266,9 +266,8 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { lint::builtin::INVALID_TYPE_PARAM_DEFAULT, param.hir_id, param.span, - |lint| { - lint.build(TYPE_DEFAULT_NOT_ALLOWED).emit(); - }, + TYPE_DEFAULT_NOT_ALLOWED, + |lint| lint, ); } Defaults::Deny => { diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs index b97f8acb37f..bd6b637f76f 100644 --- a/compiler/rustc_lint/src/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -118,37 +118,41 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { // 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 + }, + ) } } } diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 5d69c35ebfc..f28cfbd8b4c 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -33,8 +33,8 @@ use rustc_ast_pretty::pprust::{self, expr_to_string}; 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 @@ impl EarlyLintPass for WhileTrue { && !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 @@ impl EarlyLintPass for WhileTrue { ), Applicability::MachineApplicable, ) - .emit(); - }) + }, + ) } } } @@ -154,9 +157,12 @@ impl BoxPointers { 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 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { 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 @@ impl UnsafeCode { &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 @@ impl UnsafeCode { 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 @@ impl UnsafeCode { 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 @@ impl UnsafeCode { 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 @@ impl EarlyLintPass for UnsafeCode { 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 @@ impl EarlyLintPass for UnsafeCode { 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 @@ impl MissingDoc { 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 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { ) .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 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { } 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 @@ impl EarlyLintPass for AnonymousParameters { 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 @@ impl EarlyLintPass for DeprecatedAttr { _, ) = 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 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { 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 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { // fix may be to monomorphize source by hand Applicability::MaybeIncorrect, ) - .emit(); - }); + }, + ); break; } } @@ -1170,27 +1194,29 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { 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 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { 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 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { 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 @@ impl UnreachablePub { 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 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds { 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 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { 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 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { 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 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { 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 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { 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 @@ impl KeywordIdents { 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 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { } 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 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { .collect::<Vec<_>>(), Applicability::MachineApplicable, ) - .emit(); - }); + }, + ); } } } @@ -2302,18 +2341,24 @@ impl EarlyLintPass for IncompleteFeatures { .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 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { 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 @@ impl<'tcx> LateLintPass<'tcx> for ClashingExternDeclarations { 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 @@ impl<'tcx> LateLintPass<'tcx> for DerefNullPtr { 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 @@ impl<'tcx> LateLintPass<'tcx> for NamedAsmLabels { 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 @@ impl EarlyLintPass for SpecialModuleName { } 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 @@ impl EarlyLintPass for UnexpectedCfgs { 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) + }, + ); } } } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index cbab56f2066..87007728e9d 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -25,10 +25,8 @@ use crate::passes::{EarlyLintPassObject, LateLintPassObject}; 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 @@ pub trait LintContext: Sized { &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 @@ pub trait LintContext: Sized { ) => { add_elided_lifetime_in_path_suggestion( sess.source_map(), - &mut db, + db, n, path_span, incl_angl_brckt, @@ -696,7 +695,7 @@ pub trait LintContext: Sized { } } 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 @@ pub trait LintContext: Sized { } } // Rewrap `db`, and pass control to the user. - decorate(LintDiagnosticBuilder::new(db)); + decorate(db) }); } @@ -877,7 +876,10 @@ pub trait LintContext: Sized { &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 @@ pub trait LintContext: Sized { 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: impl Into<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 @@ impl<'tcx> LintContext for LateContext<'tcx> { &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 @@ impl LintContext for EarlyContext<'_> { &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 { diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 96ecd79a69c..18d30e1435b 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -43,9 +43,8 @@ impl<'a, T: EarlyLintPass> EarlyContextAndPass<'a, T> { self.context.lookup_with_diagnostics( lint_id.lint, Some(span), - |lint| { - lint.build(msg).emit(); - }, + msg, + |lint| lint, diagnostic, ); } diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs index f41ee640499..e8d307814b9 100644 --- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs +++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs @@ -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), + ); } } diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index 699e8154318..af13f453a50 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -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 }, ); } diff --git a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs index 8f22221324a..42557068bd3 100644 --- a/compiler/rustc_lint/src/hidden_unicode_codepoints.rs +++ b/compiler/rustc_lint/src/hidden_unicode_codepoints.rs @@ -60,52 +60,56 @@ impl HiddenUnicodeCodepoints { }) .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 { diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 9c4f9efde5a..8f5e38fdbcc 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -34,13 +34,16 @@ impl LateLintPass<'_> for DefaultHashTypes { 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 @@ impl LateLintPass<'_> for QueryStability { 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 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { 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 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { 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 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { // The import probably needs to be changed Applicability::MaybeIncorrect, ) - .emit(); }) } } @@ -308,11 +310,8 @@ impl EarlyLintPass for LintPassImpl { 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 @@ impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword { 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 @@ impl LateLintPass<'_> for Diagnostics { } 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 @@ impl LateLintPass<'_> for Diagnostics { } 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 @@ impl LateLintPass<'_> for BadOptAccess { 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 ); } } diff --git a/compiler/rustc_lint/src/let_underscore.rs b/compiler/rustc_lint/src/let_underscore.rs index 7e885e6c51a..78f355ec3d0 100644 --- a/compiler/rustc_lint/src/let_underscore.rs +++ b/compiler/rustc_lint/src/let_underscore.rs @@ -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 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { 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, + ) } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 1e16ac51e9e..82382350823 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -3,7 +3,7 @@ use crate::late::unerased_lint_store; 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 @@ impl<'s> LintLevelsBuilder<'s> { 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 @@ impl<'s> LintLevelsBuilder<'s> { 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 @@ impl<'s> LintLevelsBuilder<'s> { 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 @@ impl<'s> LintLevelsBuilder<'s> { 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 @@ impl<'s> LintLevelsBuilder<'s> { 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 @@ impl<'s> LintLevelsBuilder<'s> { 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 @@ impl<'s> LintLevelsBuilder<'s> { &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 diff --git a/compiler/rustc_lint/src/methods.rs b/compiler/rustc_lint/src/methods.rs index 5f7f03480c0..313119637bc 100644 --- a/compiler/rustc_lint/src/methods.rs +++ b/compiler/rustc_lint/src/methods.rs @@ -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) + }, + ); } } } diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs index 764003e61a6..b2626efb6d7 100644 --- a/compiler/rustc_lint/src/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -180,15 +180,21 @@ impl EarlyLintPass for NonAsciiIdents { 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 @@ impl EarlyLintPass for NonAsciiIdents { .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 @@ impl EarlyLintPass for NonAsciiIdents { } 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) + }, + ); } } } diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index cdad2d2e8f9..9d2a23f2b5f 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -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 + }, + ); } } diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 768ad84838b..9f800e9c8c9 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -136,26 +136,30 @@ impl NonCamelCaseTypes { 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 @@ impl NonSnakeCase { 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 @@ impl NonSnakeCase { 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 + }, + ) } } } diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs index d1449496d33..19188d5c376 100644 --- a/compiler/rustc_lint/src/noop_method_call.rs +++ b/compiler/rustc_lint/src/noop_method_call.rs @@ -90,13 +90,11 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall { } 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(); }); } } diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index efaa268647d..349399b5964 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -29,18 +29,20 @@ impl<'tcx> LateLintPass<'tcx> for PassByValue { } } 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(); - }) + }, + ) } } _ => {} diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs index 26f41345383..46c84550e9f 100644 --- a/compiler/rustc_lint/src/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -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, + ) + }, + ); } } diff --git a/compiler/rustc_lint/src/traits.rs b/compiler/rustc_lint/src/traits.rs index df1587c5948..078465bdce6 100644 --- a/compiler/rustc_lint/src/traits.rs +++ b/compiler/rustc_lint/src/traits.rs @@ -100,15 +100,18 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { 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 @@ impl<'tcx> LateLintPass<'tcx> for DropTraitConstraints { }; 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)) }); } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 4fb6d65a6e9..b6009bd800a 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -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 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { } 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 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { 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 @@ impl<'tcx> LateLintPass<'tcx> for VariantSizeDifferences { 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 @@ impl InvalidAtomicOrdering { 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 @@ impl InvalidAtomicOrdering { && 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(); }); } } diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 3d426ecbfcb..787c9518b50 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -154,9 +154,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { }; 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 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { "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 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } }, 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 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { 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 @@ trait UnusedDelimLint { } 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 @@ impl UnusedImportBraces { 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 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAllocation { 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, + ); } } } diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index b9a283552f7..3a0bd1ba50d 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -96,38 +96,43 @@ impl<'a> LintDiagnosticDerive<'a> { 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 + } } }) } diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 2f45222de47..328b7ad6a49 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -2,7 +2,7 @@ use std::cmp; 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 @@ pub fn struct_lint_level<'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 @@ pub fn struct_lint_level<'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,12 +386,12 @@ pub fn struct_lint_level<'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); - let name = lint.name_lower(); let is_force_warn = matches!(level, Level::ForceWarn(_)); err.code(DiagnosticId::Lint { name, has_future_breakage, is_force_warn }); @@ -417,10 +430,12 @@ pub fn struct_lint_level<'s, 'd>( } } - // Finally, run `decorate`. This function is also responsible for emitting the diagnostic. - decorate(LintDiagnosticBuilder::new(err)); + // Finally, run `decorate`. + decorate(&mut err); + explain_lint_level_source(lint, level, src, &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. diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index d182929c400..61bc089e431 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -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 @@ impl<'tcx> TyCtxt<'tcx> { 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); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 4781585b82c..a3489226f62 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -35,7 +35,9 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; 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 @@ impl<'tcx> TyCtxt<'tcx> { 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 @@ impl<'tcx> TyCtxt<'tcx> { 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 @@ impl<'tcx> TyCtxt<'tcx> { 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]> { diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 988ebccb633..5e8ce65daf0 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -89,15 +89,8 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { 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 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { 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 }); } diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index 54d549fd66c..b21f30efce8 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -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") + }, + ); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index d45b886903b..8fca94119c2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -7,7 +7,7 @@ use super::{PatCtxt, PatternError}; 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 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> { 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 @@ fn irrefutable_let_patterns( ) => {{ 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 @@ fn irrefutable_let_patterns( "instead using a `loop { ... }` with a `let` inside it" ); } - }); + }; } fn is_let_irrefutable<'p, 'tcx>( diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index b58685e8958..f2935ca0e3a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -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 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { lint::builtin::INDIRECT_STRUCTURAL_MATCH, self.id, self.span, - |lint| { - lint.build(&msg).emit(); - }, + msg, + |lint| lint, ); } else { debug!( @@ -286,9 +286,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { 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 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { 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 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { 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 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { lint::builtin::POINTER_STRUCTURAL_MATCH, id, span, - |lint| { - lint.build(msg).emit(); - }, + msg, + |lint| lint, ); } PatKind::Constant { value: cv } @@ -594,9 +593,8 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH, id, span, - |lint| { - lint.build(&msg).emit(); - }, + msg, + |lint| lint, ); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 5105f059f9b..91ecfccdb5f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -299,10 +299,10 @@ impl IntRange { 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 @@ impl IntRange { ), ); } - 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 }, ); } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 22b58837148..f1279072844 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -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 }); } diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 8838b14c53a..fa5f392fa74 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -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 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> { 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 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> { 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 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { // 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 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { }); 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"); diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs index 3b7ba3f9a67..51abcf51189 100644 --- a/compiler/rustc_mir_transform/src/check_packed_ref.rs +++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs @@ -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 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { 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 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> { 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(); }, ); } diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index beff19a3ab2..4730be1244b 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -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), ), } } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 973f55437ee..cda3702c83d 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -347,10 +347,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { 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)) }); } } diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 7522a50a8c6..1244c18020d 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -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; diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 0568eb2ffa6..469566694a3 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -179,11 +179,15 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { 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 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> { ), Applicability::Unspecified, ) - .emit(); - }); + }, + ); } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 897a0db930c..87433538512 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -370,10 +370,13 @@ impl CheckAttrVisitor<'_> { 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 @@ impl CheckAttrVisitor<'_> { 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 diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 3b1c1cd657f..08f704da62c 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -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}; @@ -184,13 +184,14 @@ impl<'tcx> MarkSymbolVisitor<'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 + }, ) } @@ -717,6 +718,26 @@ impl<'tcx> DeadVisitor<'tcx> { }) .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 @@ -725,27 +746,8 @@ impl<'tcx> DeadVisitor<'tcx> { }, 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!( @@ -791,7 +793,7 @@ impl<'tcx> DeadVisitor<'tcx> { ); err.note(&msg); } - err.emit(); + err }, ); } diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 6a4cd79cde7..c6fe40f72fc 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -1319,14 +1319,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // 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 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { orig_ty ), ) - .emit(); }, ); } @@ -1491,14 +1490,8 @@ impl<'tcx> Liveness<'_, 'tcx> { 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 @@ impl<'tcx> Liveness<'_, 'tcx> { 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 @@ impl<'tcx> Liveness<'_, 'tcx> { .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 @@ impl<'tcx> Liveness<'_, 'tcx> { }) .collect(), Applicability::MachineApplicable, - ); - err.emit(); + ) }, ); } else { @@ -1661,14 +1647,13 @@ impl<'tcx> Liveness<'_, 'tcx> { .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 @@ impl<'tcx> Liveness<'_, 'tcx> { .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 @@ impl<'tcx> Liveness<'_, 'tcx> { 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?"), ) } } diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 607973446fc..2690be66c21 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -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, + ); } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index e50beb27d2a..34fa80228df 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -752,10 +752,8 @@ impl<'tcx> Visitor<'tcx> for Checker<'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 }); } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index dc585fca34f..3f98db6b2a9 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -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(()) }, } } diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 2773b61e9ba..8f87a7fdeba 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -14,7 +14,7 @@ use crate::infer::TyCtxtInferExt; 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>( diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 451427a6980..6d856435355 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { 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; } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 56a88749c46..eac3f0f30e8 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -17,7 +17,7 @@ use crate::infer::{InferCtxt, InferOk, TyCtxtInferExt}; 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 report_conflicting_impls( } 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 report_conflicting_impls( } 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 report_conflicting_impls( 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), ); } }; | 
