From 74674820aaabbb68035a87f6cdf213e21d88ae27 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 26 Feb 2026 16:56:45 +0100 Subject: [PATCH 1/8] Remove unused `LintContext::emit_lint` method --- compiler/rustc_lint/src/context.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 971170aaba304..2b26caaed8741 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -535,8 +535,8 @@ pub trait LintContext { decorate: impl for<'a> Diagnostic<'a, ()>, ); - /// Emit a lint at `span` from a lint struct (some type that implements `LintDiagnostic`, - /// typically generated by `#[derive(LintDiagnostic)]`). + /// Emit a lint at `span` from a lint struct (some type that implements `Diagnostic`, + /// typically generated by `#[derive(Diagnostic)]`). fn emit_span_lint>( &self, lint: &'static Lint, @@ -573,16 +573,8 @@ pub trait LintContext { self.opt_span_lint(lint, Some(span), decorate); } - /// Emit a lint from a lint struct (some type that implements `LintDiagnostic`, typically - /// generated by `#[derive(LintDiagnostic)]`). - fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> LintDiagnostic<'a, ()>) { - self.opt_span_lint(lint, None as Option, |lint| { - decorator.decorate_lint(lint); - }); - } - - /// Emit a lint from a lint struct (some type that implements `LintDiagnostic`, typically - /// generated by `#[derive(LintDiagnostic)]`). + /// Emit a lint from a lint struct (some type that implements `Diagnostic`, typically + /// generated by `#[derive(Diagnostic)]`). fn emit_diag_lint(&self, lint: &'static Lint, decorator: impl for<'a> Diagnostic<'a, ()>) { self.opt_span_diag_lint(lint, None as Option, decorator); } From 6dc23a591ee983f289770577bb9813ccaac1b66b Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 26 Feb 2026 17:29:12 +0100 Subject: [PATCH 2/8] Remove `LintContext::emit_span_lint_lazy` --- compiler/rustc_lint/src/context.rs | 16 +------------ compiler/rustc_lint/src/lints.rs | 2 +- compiler/rustc_lint/src/nonstandard_style.rs | 24 +++++++++++++++++--- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 2b26caaed8741..5cd5c95f1ec14 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -11,7 +11,7 @@ use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync; use rustc_data_structures::unord::UnordMap; -use rustc_errors::{Diag, Diagnostic, LintBuffer, LintDiagnostic, MultiSpan}; +use rustc_errors::{Diag, Diagnostic, LintBuffer, MultiSpan}; use rustc_feature::Features; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; @@ -546,20 +546,6 @@ pub trait LintContext { self.opt_span_diag_lint(lint, Some(span), decorator); } - /// Emit a lint at `span` from a lazily-constructed lint struct (some type that implements - /// `LintDiagnostic`, typically generated by `#[derive(LintDiagnostic)]`). - fn emit_span_lint_lazy, L: for<'a> LintDiagnostic<'a, ()>>( - &self, - lint: &'static Lint, - span: S, - decorator: impl FnOnce() -> L, - ) { - self.opt_span_lint(lint, Some(span), |lint| { - let decorator = decorator(); - decorator.decorate_lint(lint); - }); - } - /// Emit a lint at the appropriate level, with an associated span. /// /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index bd7ce30e2ccad..1b983c55bae3c 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -1600,7 +1600,7 @@ impl Subdiagnostic for NonSnakeCaseDiagSub { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("{$sort} `{$name}` should have an upper case name")] pub(crate) struct NonUpperCaseGlobal<'a> { pub sort: &'a str, diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index d7db55b58d00f..b42966ce8ec8e 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -1,6 +1,6 @@ use rustc_abi::ExternAbi; use rustc_attr_parsing::AttributeParser; -use rustc_errors::Applicability; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir::attrs::{AttributeKind, ReprAttr}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -461,6 +461,19 @@ declare_lint! { declare_lint_pass!(NonUpperCaseGlobals => [NON_UPPER_CASE_GLOBALS]); +struct NonUpperCaseGlobalGenerator<'a, F: FnOnce() -> NonUpperCaseGlobal<'a>> { + callback: F, +} + +impl<'a, 'b, F: FnOnce() -> NonUpperCaseGlobal<'b>> Diagnostic<'a, ()> + for NonUpperCaseGlobalGenerator<'b, F> +{ + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { callback } = self; + callback().into_diag(dcx, level) + } +} + impl NonUpperCaseGlobals { fn check_upper_case(cx: &LateContext<'_>, sort: &str, did: Option, ident: &Ident) { let name = ident.name.as_str(); @@ -517,7 +530,7 @@ impl NonUpperCaseGlobals { } } - cx.emit_span_lint_lazy(NON_UPPER_CASE_GLOBALS, ident.span, || { + let callback = || { // Compute usages lazily as it can expansive and useless when the lint is allowed. // cf. https://github.com/rust-lang/rust/pull/142645#issuecomment-2993024625 let usages = if can_change_usages @@ -537,7 +550,12 @@ impl NonUpperCaseGlobals { }; NonUpperCaseGlobal { sort, name, sub, usages } - }); + }; + cx.emit_span_lint( + NON_UPPER_CASE_GLOBALS, + ident.span, + NonUpperCaseGlobalGenerator { callback }, + ); } } } From c1037ce357d01189723636cedb34bfe30547bc5c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 26 Feb 2026 17:46:32 +0100 Subject: [PATCH 3/8] Migrate most `rustc_lint` lint to `Diagnostic` --- compiler/rustc_lint/src/early.rs | 2 +- compiler/rustc_lint/src/early/diagnostics.rs | 213 +++++++++---------- compiler/rustc_lint/src/lints.rs | 122 +++++------ 3 files changed, 157 insertions(+), 180 deletions(-) diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 0295df2feca56..1c205035934b5 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -36,7 +36,7 @@ impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> { fn check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint; - self.context.opt_span_lint(lint_id.lint, span, |diag| match diagnostic { + self.context.opt_span_diag_lint(lint_id.lint, span, |diag| match diagnostic { DecorateDiagCompat::Builtin(b) => { diagnostics::decorate_builtin_lint(self.context.sess(), self.tcx, b, diag); } diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 31a6351c6e70b..7f13a7559b493 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -16,11 +16,11 @@ use crate::lints; mod check_cfg; -pub fn decorate_builtin_lint( +pub fn decorate_builtin_lint)>( sess: &Session, tcx: Option>, diagnostic: BuiltinLintDiag, - diag: &mut Diag<'_, ()>, + callback: F, ) { match diagnostic { BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => { @@ -41,13 +41,12 @@ pub fn decorate_builtin_lint( spans: spans.iter().map(|(_c, span)| *span).collect(), }); - lints::UnicodeTextFlow { + callback(lints::UnicodeTextFlow { comment_span, characters, suggestions, num_codepoints: spans.len(), - } - .decorate_lint(diag); + }); } BuiltinLintDiag::AbsPathWithModule(mod_span) => { let (replacement, applicability) = match sess.source_map().span_to_snippet(mod_span) { @@ -60,13 +59,12 @@ pub fn decorate_builtin_lint( } Err(_) => ("crate::".to_string(), Applicability::HasPlaceholders), }; - lints::AbsPathWithModule { + callback(lints::AbsPathWithModule { sugg: lints::AbsPathWithModuleSugg { span: mod_span, applicability, replacement }, - } - .decorate_lint(diag); + }); } BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => { - lints::ElidedLifetimesInPaths { + callback(lints::ElidedLifetimesInPaths { subdiag: elided_lifetime_in_path_suggestion( sess.source_map(), n, @@ -74,8 +72,7 @@ pub fn decorate_builtin_lint( incl_angl_brckt, insertion_span, ), - } - .decorate_lint(diag); + }); } BuiltinLintDiag::UnusedImports { remove_whole_use, @@ -92,15 +89,14 @@ pub fn decorate_builtin_lint( let test_module_span = test_module_span.map(|span| sess.source_map().guess_head_span(span)); - lints::UnusedImports { + callback(lints::UnusedImports { sugg, test_module_span, num_snippets: span_snippets.len(), span_snippets: DiagArgValue::StrListSepByAnd( span_snippets.into_iter().map(Cow::Owned).collect(), ), - } - .decorate_lint(diag); + }); } BuiltinLintDiag::RedundantImport(spans, ident) => { let subs = spans @@ -112,7 +108,7 @@ pub fn decorate_builtin_lint( (true, false) => lints::RedundantImportSub::DefinedPrelude { span, ident }, }) .collect(); - lints::RedundantImport { subs, ident }.decorate_lint(diag); + callback(lints::RedundantImport { subs, ident }); } BuiltinLintDiag::DeprecatedMacro { suggestion, @@ -127,45 +123,46 @@ pub fn decorate_builtin_lint( suggestion, }); - stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind } - .decorate_lint(diag); + callback(stability::Deprecated { + sub, + kind: "macro".to_owned(), + path, + note, + since_kind, + }); } BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => { let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span }; - if is_foreign { + callback(if is_foreign { lints::PatternsInFnsWithoutBody::Foreign { sub } } else { lints::PatternsInFnsWithoutBody::Bodiless { sub } - } - .decorate_lint(diag); + }); } BuiltinLintDiag::ReservedPrefix(label_span, prefix) => { - lints::ReservedPrefix { + callback(lints::ReservedPrefix { label: label_span, suggestion: label_span.shrink_to_hi(), prefix, - } - .decorate_lint(diag); + }); } BuiltinLintDiag::RawPrefix(label_span) => { - lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() } - .decorate_lint(diag); + callback(lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }); } BuiltinLintDiag::ReservedString { is_string, suggestion } => { if is_string { - lints::ReservedString { suggestion }.decorate_lint(diag); + callback(lints::ReservedString { suggestion }); } else { - lints::ReservedMultihash { suggestion }.decorate_lint(diag); + callback(lints::ReservedMultihash { suggestion }); } } BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => { - lints::BreakWithLabelAndLoop { + callback(lints::BreakWithLabelAndLoop { sub: lints::BreakWithLabelAndLoopSub { left: sugg_span.shrink_to_lo(), right: sugg_span.shrink_to_hi(), }, - } - .decorate_lint(diag); + }); } BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { let suggestion = match sugg { @@ -176,7 +173,7 @@ pub fn decorate_builtin_lint( }, None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp }, }; - lints::DeprecatedWhereClauseLocation { suggestion }.decorate_lint(diag); + callback(lints::DeprecatedWhereClauseLocation { suggestion }); } BuiltinLintDiag::SingleUseLifetime { param_span, @@ -203,11 +200,10 @@ pub fn decorate_builtin_lint( None }; - lints::SingleUseLifetime { suggestion, param_span, use_span, ident } - .decorate_lint(diag); + callback(lints::SingleUseLifetime { suggestion, param_span, use_span, ident }); } BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => { - lints::UnusedLifetime { deletion_span, ident }.decorate_lint(diag); + callback(lints::UnusedLifetime { deletion_span, ident }); } BuiltinLintDiag::NamedArgumentUsedPositionally { position_sp_to_replace, @@ -235,14 +231,13 @@ pub fn decorate_builtin_lint( (None, String::new()) }; - lints::NamedArgumentUsedPositionally { + callback(lints::NamedArgumentUsedPositionally { named_arg_sp, position_label_sp: position_sp_for_msg, suggestion, name, named_arg_name, - } - .decorate_lint(diag); + }); } BuiltinLintDiag::AmbiguousGlobReexports { name, @@ -250,13 +245,12 @@ pub fn decorate_builtin_lint( first_reexport_span, duplicate_reexport_span, } => { - lints::AmbiguousGlobReexports { + callback(lints::AmbiguousGlobReexports { first_reexport: first_reexport_span, duplicate_reexport: duplicate_reexport_span, name, namespace, - } - .decorate_lint(diag); + }); } BuiltinLintDiag::HiddenGlobReexports { name, @@ -264,17 +258,16 @@ pub fn decorate_builtin_lint( glob_reexport_span, private_item_span, } => { - lints::HiddenGlobReexports { + callback(lints::HiddenGlobReexports { glob_reexport: glob_reexport_span, private_item: private_item_span, name, namespace, - } - .decorate_lint(diag); + }); } BuiltinLintDiag::UnusedQualifications { removal_span } => { - lints::UnusedQualifications { removal_span }.decorate_lint(diag); + callback(lints::UnusedQualifications { removal_span }); } BuiltinLintDiag::AssociatedConstElidedLifetime { elided, @@ -283,63 +276,57 @@ pub fn decorate_builtin_lint( } => { let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span }; let code = if elided { "'static " } else { "'static" }; - lints::AssociatedConstElidedLifetime { + callback(lints::AssociatedConstElidedLifetime { span: lt_span, code, elided, lifetimes_in_scope, - } - .decorate_lint(diag); + }); } BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => match wildcard_span { Some(wildcard_span) => { - lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span } - .decorate_lint(diag) + callback(lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span }) } - None => lints::UnreachableCfgSelectPredicate { span }.decorate_lint(diag), + None => callback(lints::UnreachableCfgSelectPredicate { span }), }, BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { - lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag) - } - BuiltinLintDiag::UnusedVisibility(span) => { - lints::UnusedVisibility { span }.decorate_lint(diag) + callback(lints::UnusedCrateDependency { extern_crate, local_crate }) } - BuiltinLintDiag::AttributeLint(kind) => decorate_attribute_lint(sess, tcx, &kind, diag), + BuiltinLintDiag::UnusedVisibility(span) => callback(lints::UnusedVisibility { span }), + BuiltinLintDiag::AttributeLint(kind) => decorate_attribute_lint(sess, tcx, &kind, callback), } } -pub fn decorate_attribute_lint( +pub fn decorate_attribute_lint)>( sess: &Session, tcx: Option>, kind: &AttributeLintKind, - diag: &mut Diag<'_, ()>, + callback: F, ) { match kind { &AttributeLintKind::UnusedDuplicate { this, other, warning } => { - lints::UnusedDuplicate { this, other, warning }.decorate_lint(diag) + callback(lints::UnusedDuplicate { this, other, warning }) } AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => { - lints::IllFormedAttributeInput { + callback(lints::IllFormedAttributeInput { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), ), has_docs: docs.is_some(), docs: docs.unwrap_or(""), - } - .decorate_lint(diag) + }) } AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { - lints::EmptyAttributeList { + callback(lints::EmptyAttributeList { attr_span: *first_span, attr_path: attr_path.clone(), valid_without_list: *valid_without_list, - } - .decorate_lint(diag) + }) } AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => { - lints::InvalidTargetLint { + callback(lints::InvalidTargetLint { name: name.clone(), target, applied: DiagArgValue::StrListSepByAnd( @@ -347,129 +334,119 @@ pub fn decorate_attribute_lint( ), only, attr_span: *attr_span, - } - .decorate_lint(diag) + }) } &AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, target, target_span } => { - lints::InvalidAttrStyle { + callback(lints::InvalidAttrStyle { name: name.clone(), is_used_as_inner, target_span: (!is_used_as_inner).then_some(target_span), target, - } - .decorate_lint(diag) + }) } &AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span, sugg_spans } => { - lints::UnsafeAttrOutsideUnsafeLint { + callback(lints::UnsafeAttrOutsideUnsafeLint { span: attribute_name_span, suggestion: sugg_spans .map(|(left, right)| lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }), - } - .decorate_lint(diag) + }) } &AttributeLintKind::UnexpectedCfgName(name, value) => { - check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag) + callback(check_cfg::unexpected_cfg_name(sess, tcx, name, value)) } &AttributeLintKind::UnexpectedCfgValue(name, value) => { - check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag) + callback(check_cfg::unexpected_cfg_value(sess, tcx, name, value)) } &AttributeLintKind::DuplicateDocAlias { first_definition } => { - lints::DocAliasDuplicated { first_defn: first_definition }.decorate_lint(diag) + callback(lints::DocAliasDuplicated { first_defn: first_definition }) } &AttributeLintKind::DocAutoCfgExpectsHideOrShow => { - lints::DocAutoCfgExpectsHideOrShow.decorate_lint(diag) + callback(lints::DocAutoCfgExpectsHideOrShow) } - &AttributeLintKind::AmbiguousDeriveHelpers => { - lints::AmbiguousDeriveHelpers.decorate_lint(diag) - } + &AttributeLintKind::AmbiguousDeriveHelpers => callback(lints::AmbiguousDeriveHelpers), &AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name } => { - lints::DocAutoCfgHideShowUnexpectedItem { attr_name }.decorate_lint(diag) + callback(lints::DocAutoCfgHideShowUnexpectedItem { attr_name }) } &AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name } => { - lints::DocAutoCfgHideShowExpectsList { attr_name }.decorate_lint(diag) + callback(lints::DocAutoCfgHideShowExpectsList { attr_name }) } - &AttributeLintKind::DocInvalid => { lints::DocInvalid }.decorate_lint(diag), + &AttributeLintKind::DocInvalid => callback(lints::DocInvalid), &AttributeLintKind::DocUnknownInclude { span, inner, value } => { - lints::DocUnknownInclude { inner, value, sugg: (span, Applicability::MaybeIncorrect) } + callback(lints::DocUnknownInclude { + inner, + value, + sugg: (span, Applicability::MaybeIncorrect), + }) } - .decorate_lint(diag), &AttributeLintKind::DocUnknownSpotlight { span } => { - lints::DocUnknownSpotlight { sugg_span: span }.decorate_lint(diag) + callback(lints::DocUnknownSpotlight { sugg_span: span }) } &AttributeLintKind::DocUnknownPasses { name, span } => { - lints::DocUnknownPasses { name, note_span: span }.decorate_lint(diag) + callback(lints::DocUnknownPasses { name, note_span: span }) } &AttributeLintKind::DocUnknownPlugins { span } => { - lints::DocUnknownPlugins { label_span: span }.decorate_lint(diag) + callback(lints::DocUnknownPlugins { label_span: span }) } - &AttributeLintKind::DocUnknownAny { name } => { - lints::DocUnknownAny { name }.decorate_lint(diag) - } + &AttributeLintKind::DocUnknownAny { name } => callback(lints::DocUnknownAny { name }), - &AttributeLintKind::DocAutoCfgWrongLiteral => { - lints::DocAutoCfgWrongLiteral.decorate_lint(diag) - } + &AttributeLintKind::DocAutoCfgWrongLiteral => callback(lints::DocAutoCfgWrongLiteral), - &AttributeLintKind::DocTestTakesList => lints::DocTestTakesList.decorate_lint(diag), + &AttributeLintKind::DocTestTakesList => callback(lints::DocTestTakesList), - &AttributeLintKind::DocTestUnknown { name } => { - lints::DocTestUnknown { name }.decorate_lint(diag) - } + &AttributeLintKind::DocTestUnknown { name } => callback(lints::DocTestUnknown { name }), - &AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.decorate_lint(diag), + &AttributeLintKind::DocTestLiteral => callback(lints::DocTestLiteral), - &AttributeLintKind::AttrCrateLevelOnly => lints::AttrCrateLevelOnly.decorate_lint(diag), + &AttributeLintKind::AttrCrateLevelOnly => callback(lints::AttrCrateLevelOnly), &AttributeLintKind::DoNotRecommendDoesNotExpectArgs => { - lints::DoNotRecommendDoesNotExpectArgs.decorate_lint(diag) + callback(lints::DoNotRecommendDoesNotExpectArgs) } - &AttributeLintKind::CrateTypeUnknown { span, suggested } => lints::UnknownCrateTypes { - sugg: suggested.map(|s| lints::UnknownCrateTypesSuggestion { span, snippet: s }), + &AttributeLintKind::CrateTypeUnknown { span, suggested } => { + callback(lints::UnknownCrateTypes { + sugg: suggested.map(|s| lints::UnknownCrateTypesSuggestion { span, snippet: s }), + }) } - .decorate_lint(diag), - &AttributeLintKind::MalformedDoc => lints::MalformedDoc.decorate_lint(diag), + &AttributeLintKind::MalformedDoc => callback(lints::MalformedDoc), - &AttributeLintKind::ExpectedNoArgs => lints::ExpectedNoArgs.decorate_lint(diag), + &AttributeLintKind::ExpectedNoArgs => callback(lints::ExpectedNoArgs), - &AttributeLintKind::ExpectedNameValue => lints::ExpectedNameValue.decorate_lint(diag), + &AttributeLintKind::ExpectedNameValue => callback(lints::ExpectedNameValue), &AttributeLintKind::MalformedOnUnimplementedAttr { span } => { - lints::MalformedOnUnimplementedAttrLint { span }.decorate_lint(diag) + callback(lints::MalformedOnUnimplementedAttrLint { span }) } &AttributeLintKind::MalformedOnConstAttr { span } => { - lints::MalformedOnConstAttrLint { span }.decorate_lint(diag) + callback(lints::MalformedOnConstAttrLint { span }) } AttributeLintKind::MalformedDiagnosticFormat { warning } => match warning { FormatWarning::PositionalArgument { .. } => { - lints::DisallowedPositionalArgument.decorate_lint(diag) - } - FormatWarning::InvalidSpecifier { .. } => { - lints::InvalidFormatSpecifier.decorate_lint(diag) + callback(lints::DisallowedPositionalArgument) } + FormatWarning::InvalidSpecifier { .. } => callback(lints::InvalidFormatSpecifier), }, AttributeLintKind::DiagnosticWrappedParserError { description, label, span } => { - lints::WrappedParserError { description, label, span: *span }.decorate_lint(diag) + callback(lints::WrappedParserError { description, label, span: *span }) } &AttributeLintKind::IgnoredDiagnosticOption { option_name, first_span, later_span } => { - lints::IgnoredDiagnosticOption { option_name, first_span, later_span } - .decorate_lint(diag) + callback(lints::IgnoredDiagnosticOption { option_name, first_span, later_span }) } &AttributeLintKind::MissingOptionsForOnUnimplemented => { - lints::MissingOptionsForOnUnimplementedAttr.decorate_lint(diag) + callback(lints::MissingOptionsForOnUnimplementedAttr) } &AttributeLintKind::MissingOptionsForOnConst => { - lints::MissingOptionsForOnConstAttr.decorate_lint(diag) + callback(lints::MissingOptionsForOnConstAttr) } } } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 1b983c55bae3c..40021debca0b4 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -11,7 +11,7 @@ use rustc_errors::{ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::VisitorExt; -use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_middle::ty::inhabitedness::InhabitedPredicate; use rustc_middle::ty::{Clause, PolyExistentialTraitRef, Ty, TyCtxt}; use rustc_session::Session; @@ -2712,7 +2712,7 @@ pub(crate) struct UnexpectedCfgCargoMacroHelp { pub crate_name: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unexpected `cfg` condition name: `{$name}`")] pub(crate) struct UnexpectedCfgName { #[subdiagnostic] @@ -2859,7 +2859,7 @@ pub(crate) mod unexpected_cfg_name { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "unexpected `cfg` condition value: {$has_value -> [true] `{$value}` @@ -2994,7 +2994,7 @@ pub(crate) mod unexpected_cfg_value { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("extern crate `{$extern_crate}` is unused in crate `{$local_crate}`")] #[help("remove the dependency or add `use {$extern_crate} as _;` to the crate root")] pub(crate) struct UnusedCrateDependency { @@ -3003,7 +3003,7 @@ pub(crate) struct UnusedCrateDependency { } // FIXME(jdonszelmann): duplicated in rustc_attr_parsing, should be moved there completely. -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "{$num_suggestions -> [1] attribute must be of the form {$suggestions} @@ -3018,7 +3018,7 @@ pub(crate) struct IllFormedAttributeInput { pub docs: &'static str, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unicode codepoint changing visible direction of text present in comment")] #[note( "these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen" @@ -3058,7 +3058,7 @@ pub(crate) struct UnicodeTextFlowSuggestion { pub spans: Vec, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition" )] @@ -3077,14 +3077,14 @@ pub(crate) struct AbsPathWithModuleSugg { pub replacement: String, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("hidden lifetime parameters in types are deprecated")] pub(crate) struct ElidedLifetimesInPaths { #[subdiagnostic] pub subdiag: ElidedLifetimeInPathSubdiag, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "{$num_snippets -> [one] unused import: {$span_snippets} @@ -3128,7 +3128,7 @@ pub(crate) enum UnusedImportsSugg { }, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("the item `{$ident}` is imported redundantly")] pub(crate) struct RedundantImport { #[subdiagnostic] @@ -3164,7 +3164,7 @@ pub(crate) enum RedundantImportSub { }, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] pub(crate) enum PatternsInFnsWithoutBody { #[diag("patterns aren't allowed in foreign function declarations")] Foreign { @@ -3191,7 +3191,7 @@ pub(crate) struct PatternsInFnsWithoutBodySub { pub ident: Ident, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("prefix `{$prefix}` is unknown")] pub(crate) struct ReservedPrefix { #[label("unknown prefix")] @@ -3206,7 +3206,7 @@ pub(crate) struct ReservedPrefix { pub prefix: String, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("prefix `'r` is reserved")] pub(crate) struct RawPrefix { #[label("reserved prefix")] @@ -3219,7 +3219,7 @@ pub(crate) struct RawPrefix { pub suggestion: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression" )] @@ -3237,7 +3237,7 @@ pub(crate) struct BreakWithLabelAndLoopSub { pub right: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("where clause not allowed here")] #[note("see issue #89122 for more information")] pub(crate) struct DeprecatedWhereClauseLocation { @@ -3266,7 +3266,7 @@ pub(crate) enum DeprecatedWhereClauseLocationSugg { }, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("lifetime parameter `{$ident}` only used once")] pub(crate) struct SingleUseLifetime { #[label("this lifetime...")] @@ -3290,7 +3290,7 @@ pub(crate) struct SingleUseLifetimeSugg { pub replace_lt: String, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("lifetime parameter `{$ident}` never used")] pub(crate) struct UnusedLifetime { #[suggestion("elide the unused lifetime", code = "", applicability = "machine-applicable")] @@ -3299,7 +3299,7 @@ pub(crate) struct UnusedLifetime { pub ident: Ident, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("named argument `{$named_arg_name}` is not used by name")] pub(crate) struct NamedArgumentUsedPositionally { #[label("this named argument is referred to by position in formatting string")] @@ -3318,7 +3318,7 @@ pub(crate) struct NamedArgumentUsedPositionally { pub named_arg_name: String, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("ambiguous glob re-exports")] pub(crate) struct AmbiguousGlobReexports { #[label("the name `{$name}` in the {$namespace} namespace is first re-exported here")] @@ -3330,7 +3330,7 @@ pub(crate) struct AmbiguousGlobReexports { pub namespace: String, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("private item shadows public glob re-export")] pub(crate) struct HiddenGlobReexports { #[note( @@ -3344,7 +3344,7 @@ pub(crate) struct HiddenGlobReexports { pub namespace: String, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unnecessary qualification")] pub(crate) struct UnusedQualifications { #[suggestion( @@ -3356,7 +3356,7 @@ pub(crate) struct UnusedQualifications { pub removal_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "{$elided -> [true] `&` without an explicit lifetime name cannot be used here @@ -3422,7 +3422,7 @@ pub(crate) enum MutRefSugg { #[diag("`use` of a local item without leading `self::`, `super::`, or `crate::`")] pub(crate) struct UnqualifiedLocalImportsDiag; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("will be parsed as a guarded string in Rust 2024")] pub(crate) struct ReservedString { #[suggestion( @@ -3433,7 +3433,7 @@ pub(crate) struct ReservedString { pub suggestion: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("reserved token in Rust 2024")] pub(crate) struct ReservedMultihash { #[suggestion( @@ -3642,7 +3642,7 @@ impl Subdiagnostic for MismatchedLifetimeSyntaxesSuggestion { } } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unused attribute")] #[note( "{$valid_without_list -> @@ -3664,7 +3664,7 @@ pub(crate) struct EmptyAttributeList { pub valid_without_list: bool, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`#[{$name}]` attribute cannot be used on {$target}")] #[warning( "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" @@ -3684,7 +3684,7 @@ pub(crate) struct InvalidTargetLint { pub attr_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag( "{$is_used_as_inner -> [false] crate-level attribute should be an inner attribute: add an exclamation mark: `#![{$name}]` @@ -3699,7 +3699,7 @@ pub(crate) struct InvalidAttrStyle { pub target: &'static str, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unused attribute")] pub(crate) struct UnusedDuplicate { #[suggestion("remove this attribute", code = "", applicability = "machine-applicable")] @@ -3712,28 +3712,28 @@ pub(crate) struct UnusedDuplicate { pub warning: bool, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("malformed `doc` attribute input")] #[warning( "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" )] pub(crate) struct MalformedDoc; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("didn't expect any arguments here")] #[warning( "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" )] pub(crate) struct ExpectedNoArgs; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("expected this to be of the form `... = \"...\"`")] #[warning( "this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!" )] pub(crate) struct ExpectedNameValue; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unsafe attribute used without unsafe")] pub(crate) struct UnsafeAttrOutsideUnsafeLint { #[label("usage of unsafe attribute")] @@ -3751,7 +3751,7 @@ pub(crate) struct UnsafeAttrOutsideUnsafeSuggestion { pub right: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("visibility qualifiers have no effect on `const _` declarations")] #[note("`const _` does not declare a name, so there is nothing for the qualifier to apply to")] pub(crate) struct UnusedVisibility { @@ -3764,38 +3764,38 @@ pub(crate) struct UnusedVisibility { pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("doc alias is duplicated")] pub(crate) struct DocAliasDuplicated { #[label("first defined here")] pub first_defn: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("only `hide` or `show` are allowed in `#[doc(auto_cfg(...))]`")] pub(crate) struct DocAutoCfgExpectsHideOrShow; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("there exists a built-in attribute with the same name")] pub(crate) struct AmbiguousDeriveHelpers; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`#![doc(auto_cfg({$attr_name}(...)))]` only accepts identifiers or key/value items")] pub(crate) struct DocAutoCfgHideShowUnexpectedItem { pub attr_name: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`#![doc(auto_cfg({$attr_name}(...)))]` expects a list of items")] pub(crate) struct DocAutoCfgHideShowExpectsList { pub attr_name: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("invalid `doc` attribute")] pub(crate) struct DocInvalid; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unknown `doc` attribute `include`")] pub(crate) struct DocUnknownInclude { pub inner: &'static str, @@ -3807,7 +3807,7 @@ pub(crate) struct DocUnknownInclude { pub sugg: (Span, Applicability), } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unknown `doc` attribute `spotlight`")] #[note("`doc(spotlight)` was renamed to `doc(notable_trait)`")] #[note("`doc(spotlight)` is now a no-op")] @@ -3821,7 +3821,7 @@ pub(crate) struct DocUnknownSpotlight { pub sugg_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unknown `doc` attribute `{$name}`")] #[note( "`doc` attribute `{$name}` no longer functions; see issue #44136 " @@ -3833,7 +3833,7 @@ pub(crate) struct DocUnknownPasses { pub note_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unknown `doc` attribute `plugins`")] #[note( "`doc` attribute `plugins` no longer functions; see issue #44136 and CVE-2018-1000622 " @@ -3844,42 +3844,42 @@ pub(crate) struct DocUnknownPlugins { pub label_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unknown `doc` attribute `{$name}`")] pub(crate) struct DocUnknownAny { pub name: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("expected boolean for `#[doc(auto_cfg = ...)]`")] pub(crate) struct DocAutoCfgWrongLiteral; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`#[doc(test(...)]` takes a list of attributes")] pub(crate) struct DocTestTakesList; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unknown `doc(test)` attribute `{$name}`")] pub(crate) struct DocTestUnknown { pub name: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`#![doc(test(...)]` does not take a literal")] pub(crate) struct DocTestLiteral; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("this attribute can only be applied at the crate level")] #[note( "read for more information" )] pub(crate) struct AttrCrateLevelOnly; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`#[diagnostic::do_not_recommend]` does not expect any arguments")] pub(crate) struct DoNotRecommendDoesNotExpectArgs; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("invalid `crate_type` value")] pub(crate) struct UnknownCrateTypes { #[subdiagnostic] @@ -3894,14 +3894,14 @@ pub(crate) struct UnknownCrateTypesSuggestion { pub snippet: Symbol, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unreachable configuration predicate")] pub(crate) struct UnreachableCfgSelectPredicate { #[label("this configuration predicate is never reached")] pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("unreachable configuration predicate")] pub(crate) struct UnreachableCfgSelectPredicateWildcard { #[label("this configuration predicate is never reached")] @@ -3911,19 +3911,19 @@ pub(crate) struct UnreachableCfgSelectPredicateWildcard { pub wildcard_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("positional format arguments are not allowed here")] #[help( "only named format arguments with the name of one of the generic types are allowed in this context" )] pub(crate) struct DisallowedPositionalArgument; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("invalid format specifier")] #[help("no format specifier are supported in this position")] pub(crate) struct InvalidFormatSpecifier; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("{$description}")] pub(crate) struct WrappedParserError<'a> { pub description: &'a str, @@ -3932,7 +3932,7 @@ pub(crate) struct WrappedParserError<'a> { pub label: &'a str, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("`{$option_name}` is ignored due to previous definition of `{$option_name}`")] pub(crate) struct IgnoredDiagnosticOption { pub option_name: Symbol, @@ -3942,17 +3942,17 @@ pub(crate) struct IgnoredDiagnosticOption { pub later_span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("missing options for `on_unimplemented` attribute")] #[help("at least one of the `message`, `note` and `label` options are expected")] pub(crate) struct MissingOptionsForOnUnimplementedAttr; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("missing options for `on_const` attribute")] #[help("at least one of the `message`, `note` and `label` options are expected")] pub(crate) struct MissingOptionsForOnConstAttr; -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("malformed `on_unimplemented` attribute")] #[help("only `message`, `note` and `label` are allowed as options")] pub(crate) struct MalformedOnUnimplementedAttrLint { @@ -3960,7 +3960,7 @@ pub(crate) struct MalformedOnUnimplementedAttrLint { pub span: Span, } -#[derive(LintDiagnostic)] +#[derive(Diagnostic)] #[diag("malformed `on_const` attribute")] #[help("only `message`, `note` and `label` are allowed as options")] pub(crate) struct MalformedOnConstAttrLint { From 22b4a8cb86b4210da38cdec82b0c1382f09a7b39 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 26 Feb 2026 21:37:48 +0100 Subject: [PATCH 4/8] Update `decorate_builtin_lint` to use `Diagnostic` instead of `LintDiagnostic` --- compiler/rustc_hir_analysis/src/lib.rs | 32 +- compiler/rustc_lint/src/early.rs | 35 +- compiler/rustc_lint/src/early/diagnostics.rs | 380 ++++++++++-------- compiler/rustc_lint/src/lib.rs | 2 +- src/librustdoc/lib.rs | 36 +- .../consts/assoc-const-elided-lifetime.stderr | 8 +- .../elided-lifetime.stderr | 8 +- .../generic-associated-const.stderr | 4 +- .../static-trait-impl.stderr | 4 +- 9 files changed, 303 insertions(+), 206 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index a1c8b8421e7c1..4c3abe5cd3a09 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -149,20 +149,30 @@ pub fn provide(providers: &mut Providers) { } fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { + struct DiagEmitter<'tcx> { + hir_id: rustc_hir::HirId, + tcx: TyCtxt<'tcx>, + span: Span, + } + + impl rustc_lint::EmitDiag for DiagEmitter<'_> { + fn emit( + &self, + lint: &'static rustc_lint::Lint, + diag: impl for<'a> rustc_errors::Diagnostic<'a, ()>, + ) { + self.tcx.emit_node_span_lint(lint, self.hir_id, self.span, diag); + } + } + match lint { DelayedLint::AttributeParsing(attribute_lint) => { - tcx.node_span_lint( + rustc_lint::decorate_attribute_lint( + &DiagEmitter { hir_id: attribute_lint.id, tcx, span: attribute_lint.span }, + tcx.sess, + Some(tcx), + &attribute_lint.kind, attribute_lint.lint_id.lint, - attribute_lint.id, - attribute_lint.span, - |diag| { - rustc_lint::decorate_attribute_lint( - tcx.sess, - Some(tcx), - &attribute_lint.kind, - diag, - ); - }, ); } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 1c205035934b5..6d87a488373d5 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -7,7 +7,7 @@ use rustc_ast::visit::{self as ast_visit, Visitor, walk_list}; use rustc_ast::{self as ast, AttrVec, HasAttrs}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer}; +use rustc_errors::{BufferedEarlyLint, DecorateDiagCompat, Diagnostic, LintBuffer, MultiSpan}; use rustc_feature::Features; use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::Session; @@ -15,6 +15,7 @@ use rustc_session::lint::LintPass; use rustc_span::{Ident, Span}; use tracing::debug; +use crate::Lint; use crate::context::{EarlyContext, LintContext, LintStore}; use crate::passes::{EarlyLintPass, EarlyLintPassObject}; @@ -32,16 +33,40 @@ pub struct EarlyContextAndPass<'ecx, 'tcx, T: EarlyLintPass> { pass: T, } +pub trait EmitDiag { + fn emit(&self, lint: &'static Lint, diag: impl for<'a> Diagnostic<'a, ()>); +} + +struct DiagEmitter<'a, 'b> { + ctx: &'a EarlyContext<'b>, + span: Option, +} + +impl EmitDiag for DiagEmitter<'_, '_> { + fn emit(&self, lint: &'static Lint, diag: impl for<'a> Diagnostic<'a, ()>) { + self.ctx.opt_span_diag_lint(lint, self.span.clone(), diag); + } +} + impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> { fn check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint; - self.context.opt_span_diag_lint(lint_id.lint, span, |diag| match diagnostic { + match diagnostic { DecorateDiagCompat::Builtin(b) => { - diagnostics::decorate_builtin_lint(self.context.sess(), self.tcx, b, diag); + diagnostics::decorate_builtin_lint( + &DiagEmitter { ctx: &self.context, span }, + self.context.sess(), + self.tcx, + b, + lint_id.lint, + ); } - DecorateDiagCompat::Dynamic(d) => d.decorate_lint_box(diag), - }); + DecorateDiagCompat::Dynamic(d) => { + self.context + .opt_span_lint(lint_id.lint, span, |diag| d.decorate_lint_box(diag)); + } + } } } diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 7f13a7559b493..bc1f51f2b65a9 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -1,9 +1,7 @@ use std::borrow::Cow; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; -use rustc_errors::{ - Applicability, Diag, DiagArgValue, LintDiagnostic, elided_lifetime_in_path_suggestion, -}; +use rustc_errors::{Applicability, DiagArgValue, elided_lifetime_in_path_suggestion}; use rustc_hir::lints::{AttributeLintKind, FormatWarning}; use rustc_middle::middle::stability; use rustc_middle::ty::TyCtxt; @@ -12,15 +10,16 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_span::BytePos; use tracing::debug; -use crate::lints; +use crate::{EmitDiag, Lint, lints}; mod check_cfg; -pub fn decorate_builtin_lint)>( +pub fn decorate_builtin_lint( + ctx: &D, sess: &Session, tcx: Option>, diagnostic: BuiltinLintDiag, - callback: F, + lint: &'static Lint, ) { match diagnostic { BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => { @@ -41,12 +40,15 @@ pub fn decorate_builtin_lint)>( spans: spans.iter().map(|(_c, span)| *span).collect(), }); - callback(lints::UnicodeTextFlow { - comment_span, - characters, - suggestions, - num_codepoints: spans.len(), - }); + ctx.emit( + lint, + lints::UnicodeTextFlow { + comment_span, + characters, + suggestions, + num_codepoints: spans.len(), + }, + ); } BuiltinLintDiag::AbsPathWithModule(mod_span) => { let (replacement, applicability) = match sess.source_map().span_to_snippet(mod_span) { @@ -59,20 +61,30 @@ pub fn decorate_builtin_lint)>( } Err(_) => ("crate::".to_string(), Applicability::HasPlaceholders), }; - callback(lints::AbsPathWithModule { - sugg: lints::AbsPathWithModuleSugg { span: mod_span, applicability, replacement }, - }); + ctx.emit( + lint, + lints::AbsPathWithModule { + sugg: lints::AbsPathWithModuleSugg { + span: mod_span, + applicability, + replacement, + }, + }, + ); } BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => { - callback(lints::ElidedLifetimesInPaths { - subdiag: elided_lifetime_in_path_suggestion( - sess.source_map(), - n, - path_span, - incl_angl_brckt, - insertion_span, - ), - }); + ctx.emit( + lint, + lints::ElidedLifetimesInPaths { + subdiag: elided_lifetime_in_path_suggestion( + sess.source_map(), + n, + path_span, + incl_angl_brckt, + insertion_span, + ), + }, + ); } BuiltinLintDiag::UnusedImports { remove_whole_use, @@ -89,14 +101,17 @@ pub fn decorate_builtin_lint)>( let test_module_span = test_module_span.map(|span| sess.source_map().guess_head_span(span)); - callback(lints::UnusedImports { - sugg, - test_module_span, - num_snippets: span_snippets.len(), - span_snippets: DiagArgValue::StrListSepByAnd( - span_snippets.into_iter().map(Cow::Owned).collect(), - ), - }); + ctx.emit( + lint, + lints::UnusedImports { + sugg, + test_module_span, + num_snippets: span_snippets.len(), + span_snippets: DiagArgValue::StrListSepByAnd( + span_snippets.into_iter().map(Cow::Owned).collect(), + ), + }, + ); } BuiltinLintDiag::RedundantImport(spans, ident) => { let subs = spans @@ -108,7 +123,7 @@ pub fn decorate_builtin_lint)>( (true, false) => lints::RedundantImportSub::DefinedPrelude { span, ident }, }) .collect(); - callback(lints::RedundantImport { subs, ident }); + ctx.emit(lint, lints::RedundantImport { subs, ident }); } BuiltinLintDiag::DeprecatedMacro { suggestion, @@ -123,46 +138,55 @@ pub fn decorate_builtin_lint)>( suggestion, }); - callback(stability::Deprecated { - sub, - kind: "macro".to_owned(), - path, - note, - since_kind, - }); + ctx.emit( + lint, + stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind }, + ); } BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => { let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span }; - callback(if is_foreign { - lints::PatternsInFnsWithoutBody::Foreign { sub } - } else { - lints::PatternsInFnsWithoutBody::Bodiless { sub } - }); + ctx.emit( + lint, + if is_foreign { + lints::PatternsInFnsWithoutBody::Foreign { sub } + } else { + lints::PatternsInFnsWithoutBody::Bodiless { sub } + }, + ); } BuiltinLintDiag::ReservedPrefix(label_span, prefix) => { - callback(lints::ReservedPrefix { - label: label_span, - suggestion: label_span.shrink_to_hi(), - prefix, - }); + ctx.emit( + lint, + lints::ReservedPrefix { + label: label_span, + suggestion: label_span.shrink_to_hi(), + prefix, + }, + ); } BuiltinLintDiag::RawPrefix(label_span) => { - callback(lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }); + ctx.emit( + lint, + lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }, + ); } BuiltinLintDiag::ReservedString { is_string, suggestion } => { if is_string { - callback(lints::ReservedString { suggestion }); + ctx.emit(lint, lints::ReservedString { suggestion }); } else { - callback(lints::ReservedMultihash { suggestion }); + ctx.emit(lint, lints::ReservedMultihash { suggestion }); } } BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => { - callback(lints::BreakWithLabelAndLoop { - sub: lints::BreakWithLabelAndLoopSub { - left: sugg_span.shrink_to_lo(), - right: sugg_span.shrink_to_hi(), + ctx.emit( + lint, + lints::BreakWithLabelAndLoop { + sub: lints::BreakWithLabelAndLoopSub { + left: sugg_span.shrink_to_lo(), + right: sugg_span.shrink_to_hi(), + }, }, - }); + ); } BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { let suggestion = match sugg { @@ -173,7 +197,7 @@ pub fn decorate_builtin_lint)>( }, None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp }, }; - callback(lints::DeprecatedWhereClauseLocation { suggestion }); + ctx.emit(lint, lints::DeprecatedWhereClauseLocation { suggestion }); } BuiltinLintDiag::SingleUseLifetime { param_span, @@ -200,10 +224,10 @@ pub fn decorate_builtin_lint)>( None }; - callback(lints::SingleUseLifetime { suggestion, param_span, use_span, ident }); + ctx.emit(lint, lints::SingleUseLifetime { suggestion, param_span, use_span, ident }); } BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => { - callback(lints::UnusedLifetime { deletion_span, ident }); + ctx.emit(lint, lints::UnusedLifetime { deletion_span, ident }); } BuiltinLintDiag::NamedArgumentUsedPositionally { position_sp_to_replace, @@ -231,13 +255,16 @@ pub fn decorate_builtin_lint)>( (None, String::new()) }; - callback(lints::NamedArgumentUsedPositionally { - named_arg_sp, - position_label_sp: position_sp_for_msg, - suggestion, - name, - named_arg_name, - }); + ctx.emit( + lint, + lints::NamedArgumentUsedPositionally { + named_arg_sp, + position_label_sp: position_sp_for_msg, + suggestion, + name, + named_arg_name, + }, + ); } BuiltinLintDiag::AmbiguousGlobReexports { name, @@ -245,12 +272,15 @@ pub fn decorate_builtin_lint)>( first_reexport_span, duplicate_reexport_span, } => { - callback(lints::AmbiguousGlobReexports { - first_reexport: first_reexport_span, - duplicate_reexport: duplicate_reexport_span, - name, - namespace, - }); + ctx.emit( + lint, + lints::AmbiguousGlobReexports { + first_reexport: first_reexport_span, + duplicate_reexport: duplicate_reexport_span, + name, + namespace, + }, + ); } BuiltinLintDiag::HiddenGlobReexports { name, @@ -258,16 +288,19 @@ pub fn decorate_builtin_lint)>( glob_reexport_span, private_item_span, } => { - callback(lints::HiddenGlobReexports { - glob_reexport: glob_reexport_span, - private_item: private_item_span, - - name, - namespace, - }); + ctx.emit( + lint, + lints::HiddenGlobReexports { + glob_reexport: glob_reexport_span, + private_item: private_item_span, + + name, + namespace, + }, + ); } BuiltinLintDiag::UnusedQualifications { removal_span } => { - callback(lints::UnusedQualifications { removal_span }); + ctx.emit(lint, lints::UnusedQualifications { removal_span }); } BuiltinLintDiag::AssociatedConstElidedLifetime { elided, @@ -276,57 +309,67 @@ pub fn decorate_builtin_lint)>( } => { let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span }; let code = if elided { "'static " } else { "'static" }; - callback(lints::AssociatedConstElidedLifetime { - span: lt_span, - code, - elided, - lifetimes_in_scope, - }); + ctx.emit( + lint, + lints::AssociatedConstElidedLifetime { + span: lt_span, + code, + elided, + lifetimes_in_scope, + }, + ); } BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => match wildcard_span { Some(wildcard_span) => { - callback(lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span }) + ctx.emit(lint, lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span }) } - None => callback(lints::UnreachableCfgSelectPredicate { span }), + None => ctx.emit(lint, lints::UnreachableCfgSelectPredicate { span }), }, BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { - callback(lints::UnusedCrateDependency { extern_crate, local_crate }) + ctx.emit(lint, lints::UnusedCrateDependency { extern_crate, local_crate }) + } + BuiltinLintDiag::UnusedVisibility(span) => ctx.emit(lint, lints::UnusedVisibility { span }), + BuiltinLintDiag::AttributeLint(kind) => { + decorate_attribute_lint(ctx, sess, tcx, &kind, lint) } - BuiltinLintDiag::UnusedVisibility(span) => callback(lints::UnusedVisibility { span }), - BuiltinLintDiag::AttributeLint(kind) => decorate_attribute_lint(sess, tcx, &kind, callback), } } -pub fn decorate_attribute_lint)>( +pub fn decorate_attribute_lint( + ctx: &D, sess: &Session, tcx: Option>, kind: &AttributeLintKind, - callback: F, + lint: &'static Lint, ) { match kind { &AttributeLintKind::UnusedDuplicate { this, other, warning } => { - callback(lints::UnusedDuplicate { this, other, warning }) + ctx.emit(lint, lints::UnusedDuplicate { this, other, warning }) } - AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => { - callback(lints::IllFormedAttributeInput { + AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => ctx.emit( + lint, + lints::IllFormedAttributeInput { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), ), has_docs: docs.is_some(), docs: docs.unwrap_or(""), - }) - } - AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { - callback(lints::EmptyAttributeList { - attr_span: *first_span, - attr_path: attr_path.clone(), - valid_without_list: *valid_without_list, - }) - } - AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => { - callback(lints::InvalidTargetLint { + }, + ), + AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => ctx + .emit( + lint, + lints::EmptyAttributeList { + attr_span: *first_span, + attr_path: attr_path.clone(), + valid_without_list: *valid_without_list, + }, + ), + AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => ctx.emit( + lint, + lints::InvalidTargetLint { name: name.clone(), target, applied: DiagArgValue::StrListSepByAnd( @@ -334,119 +377,124 @@ pub fn decorate_attribute_lint)>( ), only, attr_span: *attr_span, - }) - } - &AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, target, target_span } => { - callback(lints::InvalidAttrStyle { - name: name.clone(), - is_used_as_inner, - target_span: (!is_used_as_inner).then_some(target_span), - target, - }) - } - &AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span, sugg_spans } => { - callback(lints::UnsafeAttrOutsideUnsafeLint { - span: attribute_name_span, - suggestion: sugg_spans - .map(|(left, right)| lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }), - }) - } + }, + ), + &AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, target, target_span } => ctx + .emit( + lint, + lints::InvalidAttrStyle { + name: name.clone(), + is_used_as_inner, + target_span: (!is_used_as_inner).then_some(target_span), + target, + }, + ), + &AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span, sugg_spans } => ctx + .emit( + lint, + lints::UnsafeAttrOutsideUnsafeLint { + span: attribute_name_span, + suggestion: sugg_spans.map(|(left, right)| { + lints::UnsafeAttrOutsideUnsafeSuggestion { left, right } + }), + }, + ), &AttributeLintKind::UnexpectedCfgName(name, value) => { - callback(check_cfg::unexpected_cfg_name(sess, tcx, name, value)) + ctx.emit(lint, check_cfg::unexpected_cfg_name(sess, tcx, name, value)) } &AttributeLintKind::UnexpectedCfgValue(name, value) => { - callback(check_cfg::unexpected_cfg_value(sess, tcx, name, value)) + ctx.emit(lint, check_cfg::unexpected_cfg_value(sess, tcx, name, value)) } &AttributeLintKind::DuplicateDocAlias { first_definition } => { - callback(lints::DocAliasDuplicated { first_defn: first_definition }) + ctx.emit(lint, lints::DocAliasDuplicated { first_defn: first_definition }) } &AttributeLintKind::DocAutoCfgExpectsHideOrShow => { - callback(lints::DocAutoCfgExpectsHideOrShow) + ctx.emit(lint, lints::DocAutoCfgExpectsHideOrShow) } - &AttributeLintKind::AmbiguousDeriveHelpers => callback(lints::AmbiguousDeriveHelpers), + &AttributeLintKind::AmbiguousDeriveHelpers => ctx.emit(lint, lints::AmbiguousDeriveHelpers), &AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name } => { - callback(lints::DocAutoCfgHideShowUnexpectedItem { attr_name }) + ctx.emit(lint, lints::DocAutoCfgHideShowUnexpectedItem { attr_name }) } &AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name } => { - callback(lints::DocAutoCfgHideShowExpectsList { attr_name }) + ctx.emit(lint, lints::DocAutoCfgHideShowExpectsList { attr_name }) } - &AttributeLintKind::DocInvalid => callback(lints::DocInvalid), + &AttributeLintKind::DocInvalid => ctx.emit(lint, lints::DocInvalid), - &AttributeLintKind::DocUnknownInclude { span, inner, value } => { - callback(lints::DocUnknownInclude { - inner, - value, - sugg: (span, Applicability::MaybeIncorrect), - }) - } + &AttributeLintKind::DocUnknownInclude { span, inner, value } => ctx.emit( + lint, + lints::DocUnknownInclude { inner, value, sugg: (span, Applicability::MaybeIncorrect) }, + ), &AttributeLintKind::DocUnknownSpotlight { span } => { - callback(lints::DocUnknownSpotlight { sugg_span: span }) + ctx.emit(lint, lints::DocUnknownSpotlight { sugg_span: span }) } &AttributeLintKind::DocUnknownPasses { name, span } => { - callback(lints::DocUnknownPasses { name, note_span: span }) + ctx.emit(lint, lints::DocUnknownPasses { name, note_span: span }) } &AttributeLintKind::DocUnknownPlugins { span } => { - callback(lints::DocUnknownPlugins { label_span: span }) + ctx.emit(lint, lints::DocUnknownPlugins { label_span: span }) } - &AttributeLintKind::DocUnknownAny { name } => callback(lints::DocUnknownAny { name }), + &AttributeLintKind::DocUnknownAny { name } => ctx.emit(lint, lints::DocUnknownAny { name }), - &AttributeLintKind::DocAutoCfgWrongLiteral => callback(lints::DocAutoCfgWrongLiteral), + &AttributeLintKind::DocAutoCfgWrongLiteral => ctx.emit(lint, lints::DocAutoCfgWrongLiteral), - &AttributeLintKind::DocTestTakesList => callback(lints::DocTestTakesList), + &AttributeLintKind::DocTestTakesList => ctx.emit(lint, lints::DocTestTakesList), - &AttributeLintKind::DocTestUnknown { name } => callback(lints::DocTestUnknown { name }), + &AttributeLintKind::DocTestUnknown { name } => { + ctx.emit(lint, lints::DocTestUnknown { name }) + } - &AttributeLintKind::DocTestLiteral => callback(lints::DocTestLiteral), + &AttributeLintKind::DocTestLiteral => ctx.emit(lint, lints::DocTestLiteral), - &AttributeLintKind::AttrCrateLevelOnly => callback(lints::AttrCrateLevelOnly), + &AttributeLintKind::AttrCrateLevelOnly => ctx.emit(lint, lints::AttrCrateLevelOnly), &AttributeLintKind::DoNotRecommendDoesNotExpectArgs => { - callback(lints::DoNotRecommendDoesNotExpectArgs) + ctx.emit(lint, lints::DoNotRecommendDoesNotExpectArgs) } - &AttributeLintKind::CrateTypeUnknown { span, suggested } => { - callback(lints::UnknownCrateTypes { + &AttributeLintKind::CrateTypeUnknown { span, suggested } => ctx.emit( + lint, + lints::UnknownCrateTypes { sugg: suggested.map(|s| lints::UnknownCrateTypesSuggestion { span, snippet: s }), - }) - } + }, + ), - &AttributeLintKind::MalformedDoc => callback(lints::MalformedDoc), + &AttributeLintKind::MalformedDoc => ctx.emit(lint, lints::MalformedDoc), - &AttributeLintKind::ExpectedNoArgs => callback(lints::ExpectedNoArgs), + &AttributeLintKind::ExpectedNoArgs => ctx.emit(lint, lints::ExpectedNoArgs), - &AttributeLintKind::ExpectedNameValue => callback(lints::ExpectedNameValue), + &AttributeLintKind::ExpectedNameValue => ctx.emit(lint, lints::ExpectedNameValue), &AttributeLintKind::MalformedOnUnimplementedAttr { span } => { - callback(lints::MalformedOnUnimplementedAttrLint { span }) + ctx.emit(lint, lints::MalformedOnUnimplementedAttrLint { span }) } &AttributeLintKind::MalformedOnConstAttr { span } => { - callback(lints::MalformedOnConstAttrLint { span }) + ctx.emit(lint, lints::MalformedOnConstAttrLint { span }) } AttributeLintKind::MalformedDiagnosticFormat { warning } => match warning { FormatWarning::PositionalArgument { .. } => { - callback(lints::DisallowedPositionalArgument) + ctx.emit(lint, lints::DisallowedPositionalArgument) } - FormatWarning::InvalidSpecifier { .. } => callback(lints::InvalidFormatSpecifier), + FormatWarning::InvalidSpecifier { .. } => ctx.emit(lint, lints::InvalidFormatSpecifier), }, AttributeLintKind::DiagnosticWrappedParserError { description, label, span } => { - callback(lints::WrappedParserError { description, label, span: *span }) + ctx.emit(lint, lints::WrappedParserError { description, label, span: *span }) } &AttributeLintKind::IgnoredDiagnosticOption { option_name, first_span, later_span } => { - callback(lints::IgnoredDiagnosticOption { option_name, first_span, later_span }) + ctx.emit(lint, lints::IgnoredDiagnosticOption { option_name, first_span, later_span }) } &AttributeLintKind::MissingOptionsForOnUnimplemented => { - callback(lints::MissingOptionsForOnUnimplementedAttr) + ctx.emit(lint, lints::MissingOptionsForOnUnimplementedAttr) } &AttributeLintKind::MissingOptionsForOnConst => { - callback(lints::MissingOptionsForOnConstAttr) + ctx.emit(lint, lints::MissingOptionsForOnConstAttr) } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 34276eb76cf39..e524a66910d93 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -132,7 +132,7 @@ use unused::*; pub use builtin::{MissingDoc, SoftLints}; pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore}; pub use early::diagnostics::{decorate_attribute_lint, decorate_builtin_lint}; -pub use early::{EarlyCheckNode, check_ast_node}; +pub use early::{EarlyCheckNode, EmitDiag, check_ast_node}; pub use late::{check_crate, late_lint_mod, unerased_lint_store}; pub use levels::LintLevelsBuilder; pub use passes::{EarlyLintPass, LateLintPass}; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 541ab3d1c295e..4b659ff8f4f46 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -772,6 +772,22 @@ fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> { Ok(()) } +struct DiagEmitter<'tcx> { + hir_id: rustc_hir::HirId, + tcx: TyCtxt<'tcx>, + span: rustc_span::Span, +} + +impl rustc_lint::EmitDiag for DiagEmitter<'_> { + fn emit( + &self, + lint: &'static rustc_lint::Lint, + diag: impl for<'a> rustc_errors::Diagnostic<'a, ()>, + ) { + self.tcx.emit_node_span_lint(lint, self.hir_id, self.span, diag); + } +} + fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { // Throw away the first argument, the name of the binary. // In case of at_args being empty, as might be the case by @@ -912,18 +928,16 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { for lint in &delayed_lints.lints { match lint { DelayedLint::AttributeParsing(attribute_lint) => { - tcx.node_span_lint( - attribute_lint.lint_id.lint, - attribute_lint.id, - attribute_lint.span, - |diag| { - rustc_lint::decorate_attribute_lint( - tcx.sess, - Some(tcx), - &attribute_lint.kind, - diag, - ); + rustc_lint::decorate_attribute_lint( + &DiagEmitter { + hir_id: attribute_lint.id, + tcx, + span: attribute_lint.span, }, + tcx.sess, + Some(tcx), + &attribute_lint.kind, + attribute_lint.lint_id.lint, ); } } diff --git a/tests/ui/consts/assoc-const-elided-lifetime.stderr b/tests/ui/consts/assoc-const-elided-lifetime.stderr index 9582152683578..6277b079bdac7 100644 --- a/tests/ui/consts/assoc-const-elided-lifetime.stderr +++ b/tests/ui/consts/assoc-const-elided-lifetime.stderr @@ -4,13 +4,13 @@ error: `'_` cannot be used here LL | const FOO: Foo<'_> = Foo { x: PhantomData::<&()> }; | ^^ | - = 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 #115010 note: cannot automatically infer `'static` because of other lifetimes in scope --> $DIR/assoc-const-elided-lifetime.rs:9:6 | LL | impl<'a> Foo<'a> { | ^^ + = 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 #115010 note: the lint level is defined here --> $DIR/assoc-const-elided-lifetime.rs:1:9 | @@ -28,13 +28,13 @@ error: `&` without an explicit lifetime name cannot be used here LL | const BAR: &() = &(); | ^ | - = 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 #115010 note: cannot automatically infer `'static` because of other lifetimes in scope --> $DIR/assoc-const-elided-lifetime.rs:9:6 | LL | impl<'a> Foo<'a> { | ^^ + = 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 #115010 help: use the `'static` lifetime | LL | const BAR: &'static () = &(); diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr index ae4a48e4e9328..370e6655d8607 100644 --- a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr @@ -4,13 +4,13 @@ error: `&` without an explicit lifetime name cannot be used here LL | const STATIC: &str = ""; | ^ | - = 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 #115010 note: cannot automatically infer `'static` because of other lifetimes in scope --> $DIR/elided-lifetime.rs:5:10 | LL | impl Foo<'_> { | ^^ + = 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 #115010 note: the lint level is defined here --> $DIR/elided-lifetime.rs:1:9 | @@ -27,13 +27,13 @@ error: `&` without an explicit lifetime name cannot be used here LL | const STATIC: &str = ""; | ^ | - = 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 #115010 note: cannot automatically infer `'static` because of other lifetimes in scope --> $DIR/elided-lifetime.rs:15:18 | LL | impl Bar for Foo<'_> { | ^^ + = 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 #115010 help: use the `'static` lifetime | LL | const STATIC: &'static str = ""; diff --git a/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr b/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr index 2ecab3442a96e..3680ef61e0c4c 100644 --- a/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr +++ b/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr @@ -24,13 +24,13 @@ error: `&` without an explicit lifetime name cannot be used here LL | const GAC_LIFETIME<'a>: &str = ""; | ^ | - = 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 #115010 note: cannot automatically infer `'static` because of other lifetimes in scope --> $DIR/generic-associated-const.rs:8:24 | LL | const GAC_LIFETIME<'a>: &str = ""; | ^^ + = 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 #115010 note: the lint level is defined here --> $DIR/generic-associated-const.rs:1:9 | diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr index 2bc271dccad91..ab82515162014 100644 --- a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr +++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr @@ -4,13 +4,13 @@ error: `&` without an explicit lifetime name cannot be used here LL | const STATIC: &str = ""; | ^ | - = 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 #115010 note: cannot automatically infer `'static` because of other lifetimes in scope --> $DIR/static-trait-impl.rs:8:10 | LL | impl Bar<'_> for A { | ^^ + = 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 #115010 note: the lint level is defined here --> $DIR/static-trait-impl.rs:1:9 | From 71e2ecd149503bf9e254f79d140db1a29b12fefe Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 27 Feb 2026 00:09:09 +0100 Subject: [PATCH 5/8] Simplify `rustc_lint::EmitDiag` by removing `Lint` from its API --- compiler/rustc_hir_analysis/src/lib.rs | 17 +- compiler/rustc_lint/src/early.rs | 10 +- compiler/rustc_lint/src/early/diagnostics.rs | 359 ++++++++----------- src/librustdoc/lib.rs | 11 +- 4 files changed, 171 insertions(+), 226 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 4c3abe5cd3a09..2afb17afe78b5 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -153,26 +153,27 @@ fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { hir_id: rustc_hir::HirId, tcx: TyCtxt<'tcx>, span: Span, + lint: &'static rustc_lint::Lint, } impl rustc_lint::EmitDiag for DiagEmitter<'_> { - fn emit( - &self, - lint: &'static rustc_lint::Lint, - diag: impl for<'a> rustc_errors::Diagnostic<'a, ()>, - ) { - self.tcx.emit_node_span_lint(lint, self.hir_id, self.span, diag); + fn emit(&self, diag: impl for<'a> rustc_errors::Diagnostic<'a, ()>) { + self.tcx.emit_node_span_lint(self.lint, self.hir_id, self.span, diag); } } match lint { DelayedLint::AttributeParsing(attribute_lint) => { rustc_lint::decorate_attribute_lint( - &DiagEmitter { hir_id: attribute_lint.id, tcx, span: attribute_lint.span }, + &DiagEmitter { + hir_id: attribute_lint.id, + tcx, + span: attribute_lint.span, + lint: attribute_lint.lint_id.lint, + }, tcx.sess, Some(tcx), &attribute_lint.kind, - attribute_lint.lint_id.lint, ); } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 6d87a488373d5..c9ecdd930064c 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -34,17 +34,18 @@ pub struct EarlyContextAndPass<'ecx, 'tcx, T: EarlyLintPass> { } pub trait EmitDiag { - fn emit(&self, lint: &'static Lint, diag: impl for<'a> Diagnostic<'a, ()>); + fn emit(&self, diag: impl for<'a> Diagnostic<'a, ()>); } struct DiagEmitter<'a, 'b> { ctx: &'a EarlyContext<'b>, span: Option, + lint: &'static Lint, } impl EmitDiag for DiagEmitter<'_, '_> { - fn emit(&self, lint: &'static Lint, diag: impl for<'a> Diagnostic<'a, ()>) { - self.ctx.opt_span_diag_lint(lint, self.span.clone(), diag); + fn emit(&self, diag: impl for<'a> Diagnostic<'a, ()>) { + self.ctx.opt_span_diag_lint(self.lint, self.span.clone(), diag); } } @@ -55,11 +56,10 @@ impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> { match diagnostic { DecorateDiagCompat::Builtin(b) => { diagnostics::decorate_builtin_lint( - &DiagEmitter { ctx: &self.context, span }, + &DiagEmitter { ctx: &self.context, span, lint: lint_id.lint }, self.context.sess(), self.tcx, b, - lint_id.lint, ); } DecorateDiagCompat::Dynamic(d) => { diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index bc1f51f2b65a9..b2e072d5a711e 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -10,7 +10,7 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_span::BytePos; use tracing::debug; -use crate::{EmitDiag, Lint, lints}; +use crate::{EmitDiag, lints}; mod check_cfg; @@ -19,7 +19,6 @@ pub fn decorate_builtin_lint( sess: &Session, tcx: Option>, diagnostic: BuiltinLintDiag, - lint: &'static Lint, ) { match diagnostic { BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => { @@ -40,15 +39,12 @@ pub fn decorate_builtin_lint( spans: spans.iter().map(|(_c, span)| *span).collect(), }); - ctx.emit( - lint, - lints::UnicodeTextFlow { - comment_span, - characters, - suggestions, - num_codepoints: spans.len(), - }, - ); + ctx.emit(lints::UnicodeTextFlow { + comment_span, + characters, + suggestions, + num_codepoints: spans.len(), + }); } BuiltinLintDiag::AbsPathWithModule(mod_span) => { let (replacement, applicability) = match sess.source_map().span_to_snippet(mod_span) { @@ -61,30 +57,20 @@ pub fn decorate_builtin_lint( } Err(_) => ("crate::".to_string(), Applicability::HasPlaceholders), }; - ctx.emit( - lint, - lints::AbsPathWithModule { - sugg: lints::AbsPathWithModuleSugg { - span: mod_span, - applicability, - replacement, - }, - }, - ); + ctx.emit(lints::AbsPathWithModule { + sugg: lints::AbsPathWithModuleSugg { span: mod_span, applicability, replacement }, + }); } BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => { - ctx.emit( - lint, - lints::ElidedLifetimesInPaths { - subdiag: elided_lifetime_in_path_suggestion( - sess.source_map(), - n, - path_span, - incl_angl_brckt, - insertion_span, - ), - }, - ); + ctx.emit(lints::ElidedLifetimesInPaths { + subdiag: elided_lifetime_in_path_suggestion( + sess.source_map(), + n, + path_span, + incl_angl_brckt, + insertion_span, + ), + }); } BuiltinLintDiag::UnusedImports { remove_whole_use, @@ -101,17 +87,14 @@ pub fn decorate_builtin_lint( let test_module_span = test_module_span.map(|span| sess.source_map().guess_head_span(span)); - ctx.emit( - lint, - lints::UnusedImports { - sugg, - test_module_span, - num_snippets: span_snippets.len(), - span_snippets: DiagArgValue::StrListSepByAnd( - span_snippets.into_iter().map(Cow::Owned).collect(), - ), - }, - ); + ctx.emit(lints::UnusedImports { + sugg, + test_module_span, + num_snippets: span_snippets.len(), + span_snippets: DiagArgValue::StrListSepByAnd( + span_snippets.into_iter().map(Cow::Owned).collect(), + ), + }); } BuiltinLintDiag::RedundantImport(spans, ident) => { let subs = spans @@ -123,7 +106,7 @@ pub fn decorate_builtin_lint( (true, false) => lints::RedundantImportSub::DefinedPrelude { span, ident }, }) .collect(); - ctx.emit(lint, lints::RedundantImport { subs, ident }); + ctx.emit(lints::RedundantImport { subs, ident }); } BuiltinLintDiag::DeprecatedMacro { suggestion, @@ -138,55 +121,46 @@ pub fn decorate_builtin_lint( suggestion, }); - ctx.emit( - lint, - stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind }, - ); + ctx.emit(stability::Deprecated { + sub, + kind: "macro".to_owned(), + path, + note, + since_kind, + }); } BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => { let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span }; - ctx.emit( - lint, - if is_foreign { - lints::PatternsInFnsWithoutBody::Foreign { sub } - } else { - lints::PatternsInFnsWithoutBody::Bodiless { sub } - }, - ); + ctx.emit(if is_foreign { + lints::PatternsInFnsWithoutBody::Foreign { sub } + } else { + lints::PatternsInFnsWithoutBody::Bodiless { sub } + }); } BuiltinLintDiag::ReservedPrefix(label_span, prefix) => { - ctx.emit( - lint, - lints::ReservedPrefix { - label: label_span, - suggestion: label_span.shrink_to_hi(), - prefix, - }, - ); + ctx.emit(lints::ReservedPrefix { + label: label_span, + suggestion: label_span.shrink_to_hi(), + prefix, + }); } BuiltinLintDiag::RawPrefix(label_span) => { - ctx.emit( - lint, - lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }, - ); + ctx.emit(lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }); } BuiltinLintDiag::ReservedString { is_string, suggestion } => { if is_string { - ctx.emit(lint, lints::ReservedString { suggestion }); + ctx.emit(lints::ReservedString { suggestion }); } else { - ctx.emit(lint, lints::ReservedMultihash { suggestion }); + ctx.emit(lints::ReservedMultihash { suggestion }); } } BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => { - ctx.emit( - lint, - lints::BreakWithLabelAndLoop { - sub: lints::BreakWithLabelAndLoopSub { - left: sugg_span.shrink_to_lo(), - right: sugg_span.shrink_to_hi(), - }, + ctx.emit(lints::BreakWithLabelAndLoop { + sub: lints::BreakWithLabelAndLoopSub { + left: sugg_span.shrink_to_lo(), + right: sugg_span.shrink_to_hi(), }, - ); + }); } BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { let suggestion = match sugg { @@ -197,7 +171,7 @@ pub fn decorate_builtin_lint( }, None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp }, }; - ctx.emit(lint, lints::DeprecatedWhereClauseLocation { suggestion }); + ctx.emit(lints::DeprecatedWhereClauseLocation { suggestion }); } BuiltinLintDiag::SingleUseLifetime { param_span, @@ -224,10 +198,10 @@ pub fn decorate_builtin_lint( None }; - ctx.emit(lint, lints::SingleUseLifetime { suggestion, param_span, use_span, ident }); + ctx.emit(lints::SingleUseLifetime { suggestion, param_span, use_span, ident }); } BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => { - ctx.emit(lint, lints::UnusedLifetime { deletion_span, ident }); + ctx.emit(lints::UnusedLifetime { deletion_span, ident }); } BuiltinLintDiag::NamedArgumentUsedPositionally { position_sp_to_replace, @@ -255,16 +229,13 @@ pub fn decorate_builtin_lint( (None, String::new()) }; - ctx.emit( - lint, - lints::NamedArgumentUsedPositionally { - named_arg_sp, - position_label_sp: position_sp_for_msg, - suggestion, - name, - named_arg_name, - }, - ); + ctx.emit(lints::NamedArgumentUsedPositionally { + named_arg_sp, + position_label_sp: position_sp_for_msg, + suggestion, + name, + named_arg_name, + }); } BuiltinLintDiag::AmbiguousGlobReexports { name, @@ -272,15 +243,12 @@ pub fn decorate_builtin_lint( first_reexport_span, duplicate_reexport_span, } => { - ctx.emit( - lint, - lints::AmbiguousGlobReexports { - first_reexport: first_reexport_span, - duplicate_reexport: duplicate_reexport_span, - name, - namespace, - }, - ); + ctx.emit(lints::AmbiguousGlobReexports { + first_reexport: first_reexport_span, + duplicate_reexport: duplicate_reexport_span, + name, + namespace, + }); } BuiltinLintDiag::HiddenGlobReexports { name, @@ -288,19 +256,16 @@ pub fn decorate_builtin_lint( glob_reexport_span, private_item_span, } => { - ctx.emit( - lint, - lints::HiddenGlobReexports { - glob_reexport: glob_reexport_span, - private_item: private_item_span, - - name, - namespace, - }, - ); + ctx.emit(lints::HiddenGlobReexports { + glob_reexport: glob_reexport_span, + private_item: private_item_span, + + name, + namespace, + }); } BuiltinLintDiag::UnusedQualifications { removal_span } => { - ctx.emit(lint, lints::UnusedQualifications { removal_span }); + ctx.emit(lints::UnusedQualifications { removal_span }); } BuiltinLintDiag::AssociatedConstElidedLifetime { elided, @@ -309,30 +274,25 @@ pub fn decorate_builtin_lint( } => { let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span }; let code = if elided { "'static " } else { "'static" }; - ctx.emit( - lint, - lints::AssociatedConstElidedLifetime { - span: lt_span, - code, - elided, - lifetimes_in_scope, - }, - ); + ctx.emit(lints::AssociatedConstElidedLifetime { + span: lt_span, + code, + elided, + lifetimes_in_scope, + }); } BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => match wildcard_span { Some(wildcard_span) => { - ctx.emit(lint, lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span }) + ctx.emit(lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span }) } - None => ctx.emit(lint, lints::UnreachableCfgSelectPredicate { span }), + None => ctx.emit(lints::UnreachableCfgSelectPredicate { span }), }, BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { - ctx.emit(lint, lints::UnusedCrateDependency { extern_crate, local_crate }) - } - BuiltinLintDiag::UnusedVisibility(span) => ctx.emit(lint, lints::UnusedVisibility { span }), - BuiltinLintDiag::AttributeLint(kind) => { - decorate_attribute_lint(ctx, sess, tcx, &kind, lint) + ctx.emit(lints::UnusedCrateDependency { extern_crate, local_crate }) } + BuiltinLintDiag::UnusedVisibility(span) => ctx.emit(lints::UnusedVisibility { span }), + BuiltinLintDiag::AttributeLint(kind) => decorate_attribute_lint(ctx, sess, tcx, &kind), } } @@ -341,35 +301,29 @@ pub fn decorate_attribute_lint( sess: &Session, tcx: Option>, kind: &AttributeLintKind, - lint: &'static Lint, ) { match kind { &AttributeLintKind::UnusedDuplicate { this, other, warning } => { - ctx.emit(lint, lints::UnusedDuplicate { this, other, warning }) + ctx.emit(lints::UnusedDuplicate { this, other, warning }) } - AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => ctx.emit( - lint, - lints::IllFormedAttributeInput { + AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => { + ctx.emit(lints::IllFormedAttributeInput { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), ), has_docs: docs.is_some(), docs: docs.unwrap_or(""), - }, - ), + }) + } AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => ctx - .emit( - lint, - lints::EmptyAttributeList { - attr_span: *first_span, - attr_path: attr_path.clone(), - valid_without_list: *valid_without_list, - }, - ), - AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => ctx.emit( - lint, - lints::InvalidTargetLint { + .emit(lints::EmptyAttributeList { + attr_span: *first_span, + attr_path: attr_path.clone(), + valid_without_list: *valid_without_list, + }), + AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => { + ctx.emit(lints::InvalidTargetLint { name: name.clone(), target, applied: DiagArgValue::StrListSepByAnd( @@ -377,124 +331,117 @@ pub fn decorate_attribute_lint( ), only, attr_span: *attr_span, - }, - ), + }) + } &AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, target, target_span } => ctx - .emit( - lint, - lints::InvalidAttrStyle { - name: name.clone(), - is_used_as_inner, - target_span: (!is_used_as_inner).then_some(target_span), - target, - }, - ), + .emit(lints::InvalidAttrStyle { + name: name.clone(), + is_used_as_inner, + target_span: (!is_used_as_inner).then_some(target_span), + target, + }), &AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span, sugg_spans } => ctx - .emit( - lint, - lints::UnsafeAttrOutsideUnsafeLint { - span: attribute_name_span, - suggestion: sugg_spans.map(|(left, right)| { - lints::UnsafeAttrOutsideUnsafeSuggestion { left, right } - }), - }, - ), + .emit(lints::UnsafeAttrOutsideUnsafeLint { + span: attribute_name_span, + suggestion: sugg_spans + .map(|(left, right)| lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }), + }), &AttributeLintKind::UnexpectedCfgName(name, value) => { - ctx.emit(lint, check_cfg::unexpected_cfg_name(sess, tcx, name, value)) + ctx.emit(check_cfg::unexpected_cfg_name(sess, tcx, name, value)) } &AttributeLintKind::UnexpectedCfgValue(name, value) => { - ctx.emit(lint, check_cfg::unexpected_cfg_value(sess, tcx, name, value)) + ctx.emit(check_cfg::unexpected_cfg_value(sess, tcx, name, value)) } &AttributeLintKind::DuplicateDocAlias { first_definition } => { - ctx.emit(lint, lints::DocAliasDuplicated { first_defn: first_definition }) + ctx.emit(lints::DocAliasDuplicated { first_defn: first_definition }) } &AttributeLintKind::DocAutoCfgExpectsHideOrShow => { - ctx.emit(lint, lints::DocAutoCfgExpectsHideOrShow) + ctx.emit(lints::DocAutoCfgExpectsHideOrShow) } - &AttributeLintKind::AmbiguousDeriveHelpers => ctx.emit(lint, lints::AmbiguousDeriveHelpers), + &AttributeLintKind::AmbiguousDeriveHelpers => ctx.emit(lints::AmbiguousDeriveHelpers), &AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name } => { - ctx.emit(lint, lints::DocAutoCfgHideShowUnexpectedItem { attr_name }) + ctx.emit(lints::DocAutoCfgHideShowUnexpectedItem { attr_name }) } &AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name } => { - ctx.emit(lint, lints::DocAutoCfgHideShowExpectsList { attr_name }) + ctx.emit(lints::DocAutoCfgHideShowExpectsList { attr_name }) } - &AttributeLintKind::DocInvalid => ctx.emit(lint, lints::DocInvalid), + &AttributeLintKind::DocInvalid => ctx.emit(lints::DocInvalid), - &AttributeLintKind::DocUnknownInclude { span, inner, value } => ctx.emit( - lint, - lints::DocUnknownInclude { inner, value, sugg: (span, Applicability::MaybeIncorrect) }, - ), + &AttributeLintKind::DocUnknownInclude { span, inner, value } => { + ctx.emit(lints::DocUnknownInclude { + inner, + value, + sugg: (span, Applicability::MaybeIncorrect), + }) + } &AttributeLintKind::DocUnknownSpotlight { span } => { - ctx.emit(lint, lints::DocUnknownSpotlight { sugg_span: span }) + ctx.emit(lints::DocUnknownSpotlight { sugg_span: span }) } &AttributeLintKind::DocUnknownPasses { name, span } => { - ctx.emit(lint, lints::DocUnknownPasses { name, note_span: span }) + ctx.emit(lints::DocUnknownPasses { name, note_span: span }) } &AttributeLintKind::DocUnknownPlugins { span } => { - ctx.emit(lint, lints::DocUnknownPlugins { label_span: span }) + ctx.emit(lints::DocUnknownPlugins { label_span: span }) } - &AttributeLintKind::DocUnknownAny { name } => ctx.emit(lint, lints::DocUnknownAny { name }), + &AttributeLintKind::DocUnknownAny { name } => ctx.emit(lints::DocUnknownAny { name }), - &AttributeLintKind::DocAutoCfgWrongLiteral => ctx.emit(lint, lints::DocAutoCfgWrongLiteral), + &AttributeLintKind::DocAutoCfgWrongLiteral => ctx.emit(lints::DocAutoCfgWrongLiteral), - &AttributeLintKind::DocTestTakesList => ctx.emit(lint, lints::DocTestTakesList), + &AttributeLintKind::DocTestTakesList => ctx.emit(lints::DocTestTakesList), - &AttributeLintKind::DocTestUnknown { name } => { - ctx.emit(lint, lints::DocTestUnknown { name }) - } + &AttributeLintKind::DocTestUnknown { name } => ctx.emit(lints::DocTestUnknown { name }), - &AttributeLintKind::DocTestLiteral => ctx.emit(lint, lints::DocTestLiteral), + &AttributeLintKind::DocTestLiteral => ctx.emit(lints::DocTestLiteral), - &AttributeLintKind::AttrCrateLevelOnly => ctx.emit(lint, lints::AttrCrateLevelOnly), + &AttributeLintKind::AttrCrateLevelOnly => ctx.emit(lints::AttrCrateLevelOnly), &AttributeLintKind::DoNotRecommendDoesNotExpectArgs => { - ctx.emit(lint, lints::DoNotRecommendDoesNotExpectArgs) + ctx.emit(lints::DoNotRecommendDoesNotExpectArgs) } - &AttributeLintKind::CrateTypeUnknown { span, suggested } => ctx.emit( - lint, - lints::UnknownCrateTypes { + &AttributeLintKind::CrateTypeUnknown { span, suggested } => { + ctx.emit(lints::UnknownCrateTypes { sugg: suggested.map(|s| lints::UnknownCrateTypesSuggestion { span, snippet: s }), - }, - ), + }) + } - &AttributeLintKind::MalformedDoc => ctx.emit(lint, lints::MalformedDoc), + &AttributeLintKind::MalformedDoc => ctx.emit(lints::MalformedDoc), - &AttributeLintKind::ExpectedNoArgs => ctx.emit(lint, lints::ExpectedNoArgs), + &AttributeLintKind::ExpectedNoArgs => ctx.emit(lints::ExpectedNoArgs), - &AttributeLintKind::ExpectedNameValue => ctx.emit(lint, lints::ExpectedNameValue), + &AttributeLintKind::ExpectedNameValue => ctx.emit(lints::ExpectedNameValue), &AttributeLintKind::MalformedOnUnimplementedAttr { span } => { - ctx.emit(lint, lints::MalformedOnUnimplementedAttrLint { span }) + ctx.emit(lints::MalformedOnUnimplementedAttrLint { span }) } &AttributeLintKind::MalformedOnConstAttr { span } => { - ctx.emit(lint, lints::MalformedOnConstAttrLint { span }) + ctx.emit(lints::MalformedOnConstAttrLint { span }) } AttributeLintKind::MalformedDiagnosticFormat { warning } => match warning { FormatWarning::PositionalArgument { .. } => { - ctx.emit(lint, lints::DisallowedPositionalArgument) + ctx.emit(lints::DisallowedPositionalArgument) } - FormatWarning::InvalidSpecifier { .. } => ctx.emit(lint, lints::InvalidFormatSpecifier), + FormatWarning::InvalidSpecifier { .. } => ctx.emit(lints::InvalidFormatSpecifier), }, AttributeLintKind::DiagnosticWrappedParserError { description, label, span } => { - ctx.emit(lint, lints::WrappedParserError { description, label, span: *span }) + ctx.emit(lints::WrappedParserError { description, label, span: *span }) } &AttributeLintKind::IgnoredDiagnosticOption { option_name, first_span, later_span } => { - ctx.emit(lint, lints::IgnoredDiagnosticOption { option_name, first_span, later_span }) + ctx.emit(lints::IgnoredDiagnosticOption { option_name, first_span, later_span }) } &AttributeLintKind::MissingOptionsForOnUnimplemented => { - ctx.emit(lint, lints::MissingOptionsForOnUnimplementedAttr) + ctx.emit(lints::MissingOptionsForOnUnimplementedAttr) } &AttributeLintKind::MissingOptionsForOnConst => { - ctx.emit(lint, lints::MissingOptionsForOnConstAttr) + ctx.emit(lints::MissingOptionsForOnConstAttr) } } } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 4b659ff8f4f46..0c9f4b5d202f9 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -776,15 +776,12 @@ struct DiagEmitter<'tcx> { hir_id: rustc_hir::HirId, tcx: TyCtxt<'tcx>, span: rustc_span::Span, + lint: &'static rustc_lint::Lint, } impl rustc_lint::EmitDiag for DiagEmitter<'_> { - fn emit( - &self, - lint: &'static rustc_lint::Lint, - diag: impl for<'a> rustc_errors::Diagnostic<'a, ()>, - ) { - self.tcx.emit_node_span_lint(lint, self.hir_id, self.span, diag); + fn emit(&self, diag: impl for<'a> rustc_errors::Diagnostic<'a, ()>) { + self.tcx.emit_node_span_lint(self.lint, self.hir_id, self.span, diag); } } @@ -933,11 +930,11 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { hir_id: attribute_lint.id, tcx, span: attribute_lint.span, + lint: attribute_lint.lint_id.lint, }, tcx.sess, Some(tcx), &attribute_lint.kind, - attribute_lint.lint_id.lint, ); } } From 62cb683ff585ad9bdafecaecd87c33eb88c58be1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 27 Feb 2026 00:18:06 +0100 Subject: [PATCH 6/8] Remove duplicated code for delayed lints between `rustc_hir_analysis` and `rustdoc` --- compiler/rustc_hir_analysis/src/lib.rs | 2 +- src/librustdoc/lib.rs | 30 +------------------------- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 2afb17afe78b5..8f39c6ec99e5c 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -148,7 +148,7 @@ pub fn provide(providers: &mut Providers) { }; } -fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { +pub fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { struct DiagEmitter<'tcx> { hir_id: rustc_hir::HirId, tcx: TyCtxt<'tcx>, diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 0c9f4b5d202f9..8cad0210ea346 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -74,7 +74,6 @@ use std::process::ExitCode; use rustc_errors::DiagCtxtHandle; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_hir::lints::DelayedLint; use rustc_interface::interface; use rustc_middle::ty::TyCtxt; use rustc_session::config::{ErrorOutputType, RustcOptGroup, make_crate_type_option}; @@ -772,19 +771,6 @@ fn run_merge_finalize(opt: config::RenderOptions) -> Result<(), error::Error> { Ok(()) } -struct DiagEmitter<'tcx> { - hir_id: rustc_hir::HirId, - tcx: TyCtxt<'tcx>, - span: rustc_span::Span, - lint: &'static rustc_lint::Lint, -} - -impl rustc_lint::EmitDiag for DiagEmitter<'_> { - fn emit(&self, diag: impl for<'a> rustc_errors::Diagnostic<'a, ()>) { - self.tcx.emit_node_span_lint(self.lint, self.hir_id, self.span, diag); - } -} - fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { // Throw away the first argument, the name of the binary. // In case of at_args being empty, as might be the case by @@ -923,21 +909,7 @@ fn main_args(early_dcx: &mut EarlyDiagCtxt, at_args: &[String]) { for owner_id in tcx.hir_crate_items(()).delayed_lint_items() { if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { for lint in &delayed_lints.lints { - match lint { - DelayedLint::AttributeParsing(attribute_lint) => { - rustc_lint::decorate_attribute_lint( - &DiagEmitter { - hir_id: attribute_lint.id, - tcx, - span: attribute_lint.span, - lint: attribute_lint.lint_id.lint, - }, - tcx.sess, - Some(tcx), - &attribute_lint.kind, - ); - } - } + rustc_hir_analysis::emit_delayed_lint(lint, tcx); } } } From 2be5835a7e0dea5deb0f5595b0c02264e5fa3d11 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 28 Feb 2026 22:20:54 +0100 Subject: [PATCH 7/8] Make `DiagEmitter::emit` take `self` by value --- compiler/rustc_hir_analysis/src/lib.rs | 4 ++-- compiler/rustc_lint/src/early.rs | 8 ++++---- compiler/rustc_lint/src/early/diagnostics.rs | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 8f39c6ec99e5c..e4038a41ab130 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -157,7 +157,7 @@ pub fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { } impl rustc_lint::EmitDiag for DiagEmitter<'_> { - fn emit(&self, diag: impl for<'a> rustc_errors::Diagnostic<'a, ()>) { + fn emit(self, diag: impl for<'a> rustc_errors::Diagnostic<'a, ()>) { self.tcx.emit_node_span_lint(self.lint, self.hir_id, self.span, diag); } } @@ -165,7 +165,7 @@ pub fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { match lint { DelayedLint::AttributeParsing(attribute_lint) => { rustc_lint::decorate_attribute_lint( - &DiagEmitter { + DiagEmitter { hir_id: attribute_lint.id, tcx, span: attribute_lint.span, diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index c9ecdd930064c..335cc1a3248b3 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -34,7 +34,7 @@ pub struct EarlyContextAndPass<'ecx, 'tcx, T: EarlyLintPass> { } pub trait EmitDiag { - fn emit(&self, diag: impl for<'a> Diagnostic<'a, ()>); + fn emit(self, diag: impl for<'a> Diagnostic<'a, ()>); } struct DiagEmitter<'a, 'b> { @@ -44,8 +44,8 @@ struct DiagEmitter<'a, 'b> { } impl EmitDiag for DiagEmitter<'_, '_> { - fn emit(&self, diag: impl for<'a> Diagnostic<'a, ()>) { - self.ctx.opt_span_diag_lint(self.lint, self.span.clone(), diag); + fn emit(self, diag: impl for<'a> Diagnostic<'a, ()>) { + self.ctx.opt_span_diag_lint(self.lint, self.span, diag); } } @@ -56,7 +56,7 @@ impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> { match diagnostic { DecorateDiagCompat::Builtin(b) => { diagnostics::decorate_builtin_lint( - &DiagEmitter { ctx: &self.context, span, lint: lint_id.lint }, + DiagEmitter { ctx: &self.context, span, lint: lint_id.lint }, self.context.sess(), self.tcx, b, diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index b2e072d5a711e..d56f64be48c83 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -14,8 +14,8 @@ use crate::{EmitDiag, lints}; mod check_cfg; -pub fn decorate_builtin_lint( - ctx: &D, +pub fn decorate_builtin_lint( + ctx: impl EmitDiag, sess: &Session, tcx: Option>, diagnostic: BuiltinLintDiag, @@ -296,8 +296,8 @@ pub fn decorate_builtin_lint( } } -pub fn decorate_attribute_lint( - ctx: &D, +pub fn decorate_attribute_lint( + ctx: impl EmitDiag, sess: &Session, tcx: Option>, kind: &AttributeLintKind, From 8a824ee3019c77c5c26b3e7b8a0855ba34759f5a Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Mon, 2 Mar 2026 23:27:55 +0100 Subject: [PATCH 8/8] Fix performance of early lints --- compiler/rustc_hir_analysis/src/lib.rs | 31 +- compiler/rustc_lint/src/early.rs | 33 +- compiler/rustc_lint/src/early/diagnostics.rs | 778 ++++++++++--------- compiler/rustc_lint/src/lib.rs | 4 +- 4 files changed, 438 insertions(+), 408 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index e4038a41ab130..00b335fff3b40 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -88,6 +88,7 @@ use rustc_abi::{CVariadicStatus, ExternAbi}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::lints::DelayedLint; +use rustc_lint::DecorateAttrLint; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; use rustc_middle::ty::{Const, Ty, TyCtxt}; @@ -149,31 +150,17 @@ pub fn provide(providers: &mut Providers) { } pub fn emit_delayed_lint(lint: &DelayedLint, tcx: TyCtxt<'_>) { - struct DiagEmitter<'tcx> { - hir_id: rustc_hir::HirId, - tcx: TyCtxt<'tcx>, - span: Span, - lint: &'static rustc_lint::Lint, - } - - impl rustc_lint::EmitDiag for DiagEmitter<'_> { - fn emit(self, diag: impl for<'a> rustc_errors::Diagnostic<'a, ()>) { - self.tcx.emit_node_span_lint(self.lint, self.hir_id, self.span, diag); - } - } - match lint { DelayedLint::AttributeParsing(attribute_lint) => { - rustc_lint::decorate_attribute_lint( - DiagEmitter { - hir_id: attribute_lint.id, - tcx, - span: attribute_lint.span, - lint: attribute_lint.lint_id.lint, + tcx.emit_node_span_lint( + attribute_lint.lint_id.lint, + attribute_lint.id, + attribute_lint.span, + DecorateAttrLint { + sess: tcx.sess, + tcx: Some(tcx), + diagnostic: &attribute_lint.kind, }, - tcx.sess, - Some(tcx), - &attribute_lint.kind, ); } } diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 335cc1a3248b3..a2ee7936685b3 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -7,7 +7,7 @@ use rustc_ast::visit::{self as ast_visit, Visitor, walk_list}; use rustc_ast::{self as ast, AttrVec, HasAttrs}; use rustc_data_structures::stack::ensure_sufficient_stack; -use rustc_errors::{BufferedEarlyLint, DecorateDiagCompat, Diagnostic, LintBuffer, MultiSpan}; +use rustc_errors::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer}; use rustc_feature::Features; use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::Session; @@ -15,7 +15,7 @@ use rustc_session::lint::LintPass; use rustc_span::{Ident, Span}; use tracing::debug; -use crate::Lint; +use crate::DecorateBuiltinLint; use crate::context::{EarlyContext, LintContext, LintStore}; use crate::passes::{EarlyLintPass, EarlyLintPassObject}; @@ -33,33 +33,20 @@ pub struct EarlyContextAndPass<'ecx, 'tcx, T: EarlyLintPass> { pass: T, } -pub trait EmitDiag { - fn emit(self, diag: impl for<'a> Diagnostic<'a, ()>); -} - -struct DiagEmitter<'a, 'b> { - ctx: &'a EarlyContext<'b>, - span: Option, - lint: &'static Lint, -} - -impl EmitDiag for DiagEmitter<'_, '_> { - fn emit(self, diag: impl for<'a> Diagnostic<'a, ()>) { - self.ctx.opt_span_diag_lint(self.lint, self.span, diag); - } -} - impl<'ecx, 'tcx, T: EarlyLintPass> EarlyContextAndPass<'ecx, 'tcx, T> { fn check_id(&mut self, id: ast::NodeId) { for early_lint in self.context.buffered.take(id) { let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint; match diagnostic { DecorateDiagCompat::Builtin(b) => { - diagnostics::decorate_builtin_lint( - DiagEmitter { ctx: &self.context, span, lint: lint_id.lint }, - self.context.sess(), - self.tcx, - b, + self.context.opt_span_diag_lint( + lint_id.lint, + span, + DecorateBuiltinLint { + sess: self.context.sess(), + tcx: self.tcx, + diagnostic: b, + }, ); } DecorateDiagCompat::Dynamic(d) => { diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index d56f64be48c83..458553fa747ca 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -1,7 +1,10 @@ use std::borrow::Cow; use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS; -use rustc_errors::{Applicability, DiagArgValue, elided_lifetime_in_path_suggestion}; +use rustc_errors::{ + Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level, + elided_lifetime_in_path_suggestion, +}; use rustc_hir::lints::{AttributeLintKind, FormatWarning}; use rustc_middle::middle::stability; use rustc_middle::ty::TyCtxt; @@ -10,438 +13,491 @@ use rustc_session::lint::BuiltinLintDiag; use rustc_span::BytePos; use tracing::debug; -use crate::{EmitDiag, lints}; +use crate::lints; mod check_cfg; -pub fn decorate_builtin_lint( - ctx: impl EmitDiag, - sess: &Session, - tcx: Option>, - diagnostic: BuiltinLintDiag, -) { - match diagnostic { - BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => { - let spans: Vec<_> = content - .char_indices() - .filter_map(|(i, c)| { - TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| { - let lo = comment_span.lo() + BytePos(2 + i as u32); - (c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) +/// This is a diagnostic struct that will decorate a `BuiltinLintDiag` +/// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed. +pub struct DecorateBuiltinLint<'sess, 'tcx> { + pub sess: &'sess Session, + pub tcx: Option>, + pub diagnostic: BuiltinLintDiag, +} + +impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + match self.diagnostic { + BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => { + let spans: Vec<_> = content + .char_indices() + .filter_map(|(i, c)| { + TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| { + let lo = comment_span.lo() + BytePos(2 + i as u32); + (c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32))) + }) }) - }) - .collect(); - let characters = spans - .iter() - .map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: format!("{c:?}") }) - .collect(); - let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion { - spans: spans.iter().map(|(_c, span)| *span).collect(), - }); - - ctx.emit(lints::UnicodeTextFlow { - comment_span, - characters, - suggestions, - num_codepoints: spans.len(), - }); - } - BuiltinLintDiag::AbsPathWithModule(mod_span) => { - let (replacement, applicability) = match sess.source_map().span_to_snippet(mod_span) { - Ok(ref s) => { - // FIXME(Manishearth) ideally the emitting code - // can tell us whether or not this is global - let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" }; - - (format!("crate{opt_colon}{s}"), Applicability::MachineApplicable) + .collect(); + let characters = spans + .iter() + .map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: format!("{c:?}") }) + .collect(); + let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion { + spans: spans.iter().map(|(_c, span)| *span).collect(), + }); + + lints::UnicodeTextFlow { + comment_span, + characters, + suggestions, + num_codepoints: spans.len(), } - Err(_) => ("crate::".to_string(), Applicability::HasPlaceholders), - }; - ctx.emit(lints::AbsPathWithModule { - sugg: lints::AbsPathWithModuleSugg { span: mod_span, applicability, replacement }, - }); - } - BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => { - ctx.emit(lints::ElidedLifetimesInPaths { + .into_diag(dcx, level) + } + BuiltinLintDiag::AbsPathWithModule(mod_span) => { + let (replacement, applicability) = + match self.sess.source_map().span_to_snippet(mod_span) { + Ok(ref s) => { + // FIXME(Manishearth) ideally the emitting code + // can tell us whether or not this is global + let opt_colon = + if s.trim_start().starts_with("::") { "" } else { "::" }; + + (format!("crate{opt_colon}{s}"), Applicability::MachineApplicable) + } + Err(_) => ("crate::".to_string(), Applicability::HasPlaceholders), + }; + lints::AbsPathWithModule { + sugg: lints::AbsPathWithModuleSugg { + span: mod_span, + applicability, + replacement, + }, + } + .into_diag(dcx, level) + } + BuiltinLintDiag::ElidedLifetimesInPaths( + n, + path_span, + incl_angl_brckt, + insertion_span, + ) => lints::ElidedLifetimesInPaths { subdiag: elided_lifetime_in_path_suggestion( - sess.source_map(), + self.sess.source_map(), n, path_span, incl_angl_brckt, insertion_span, ), - }); - } - BuiltinLintDiag::UnusedImports { - remove_whole_use, - num_to_remove, - remove_spans, - test_module_span, - span_snippets, - } => { - let sugg = if remove_whole_use { - lints::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] } - } else { - lints::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove } - }; - let test_module_span = - test_module_span.map(|span| sess.source_map().guess_head_span(span)); - - ctx.emit(lints::UnusedImports { - sugg, + } + .into_diag(dcx, level), + BuiltinLintDiag::UnusedImports { + remove_whole_use, + num_to_remove, + remove_spans, test_module_span, - num_snippets: span_snippets.len(), - span_snippets: DiagArgValue::StrListSepByAnd( - span_snippets.into_iter().map(Cow::Owned).collect(), - ), - }); - } - BuiltinLintDiag::RedundantImport(spans, ident) => { - let subs = spans - .into_iter() - .map(|(span, is_imported)| match (span.is_dummy(), is_imported) { - (false, true) => lints::RedundantImportSub::ImportedHere { span, ident }, - (false, false) => lints::RedundantImportSub::DefinedHere { span, ident }, - (true, true) => lints::RedundantImportSub::ImportedPrelude { span, ident }, - (true, false) => lints::RedundantImportSub::DefinedPrelude { span, ident }, - }) - .collect(); - ctx.emit(lints::RedundantImport { subs, ident }); - } - BuiltinLintDiag::DeprecatedMacro { - suggestion, - suggestion_span, - note, - path, - since_kind, - } => { - let sub = suggestion.map(|suggestion| stability::DeprecationSuggestion { - span: suggestion_span, - kind: "macro".to_owned(), - suggestion, - }); + span_snippets, + } => { + let sugg = if remove_whole_use { + lints::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] } + } else { + lints::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove } + }; + let test_module_span = + test_module_span.map(|span| self.sess.source_map().guess_head_span(span)); - ctx.emit(stability::Deprecated { - sub, - kind: "macro".to_owned(), - path, + lints::UnusedImports { + sugg, + test_module_span, + num_snippets: span_snippets.len(), + span_snippets: DiagArgValue::StrListSepByAnd( + span_snippets.into_iter().map(Cow::Owned).collect(), + ), + } + .into_diag(dcx, level) + } + BuiltinLintDiag::RedundantImport(spans, ident) => { + let subs = spans + .into_iter() + .map(|(span, is_imported)| match (span.is_dummy(), is_imported) { + (false, true) => lints::RedundantImportSub::ImportedHere { span, ident }, + (false, false) => lints::RedundantImportSub::DefinedHere { span, ident }, + (true, true) => lints::RedundantImportSub::ImportedPrelude { span, ident }, + (true, false) => lints::RedundantImportSub::DefinedPrelude { span, ident }, + }) + .collect(); + lints::RedundantImport { subs, ident }.into_diag(dcx, level) + } + BuiltinLintDiag::DeprecatedMacro { + suggestion, + suggestion_span, note, + path, since_kind, - }); - } - BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => { - let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span }; - ctx.emit(if is_foreign { - lints::PatternsInFnsWithoutBody::Foreign { sub } - } else { - lints::PatternsInFnsWithoutBody::Bodiless { sub } - }); - } - BuiltinLintDiag::ReservedPrefix(label_span, prefix) => { - ctx.emit(lints::ReservedPrefix { + } => { + let sub = suggestion.map(|suggestion| stability::DeprecationSuggestion { + span: suggestion_span, + kind: "macro".to_owned(), + suggestion, + }); + + stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind } + .into_diag(dcx, level) + } + BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => { + let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span }; + if is_foreign { + lints::PatternsInFnsWithoutBody::Foreign { sub } + } else { + lints::PatternsInFnsWithoutBody::Bodiless { sub } + } + .into_diag(dcx, level) + } + BuiltinLintDiag::ReservedPrefix(label_span, prefix) => lints::ReservedPrefix { label: label_span, suggestion: label_span.shrink_to_hi(), prefix, - }); - } - BuiltinLintDiag::RawPrefix(label_span) => { - ctx.emit(lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }); - } - BuiltinLintDiag::ReservedString { is_string, suggestion } => { - if is_string { - ctx.emit(lints::ReservedString { suggestion }); - } else { - ctx.emit(lints::ReservedMultihash { suggestion }); } - } - BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => { - ctx.emit(lints::BreakWithLabelAndLoop { + .into_diag(dcx, level), + BuiltinLintDiag::RawPrefix(label_span) => { + lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() } + .into_diag(dcx, level) + } + BuiltinLintDiag::ReservedString { is_string, suggestion } => { + if is_string { + lints::ReservedString { suggestion }.into_diag(dcx, level) + } else { + lints::ReservedMultihash { suggestion }.into_diag(dcx, level) + } + } + BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => lints::BreakWithLabelAndLoop { sub: lints::BreakWithLabelAndLoopSub { left: sugg_span.shrink_to_lo(), right: sugg_span.shrink_to_hi(), }, - }); - } - BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { - let suggestion = match sugg { - Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd { - left: left_sp, - right: right_sp, - sugg, - }, - None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp }, - }; - ctx.emit(lints::DeprecatedWhereClauseLocation { suggestion }); - } - BuiltinLintDiag::SingleUseLifetime { - param_span, - use_span: Some((use_span, elide)), - deletion_span, - ident, - } => { - debug!(?param_span, ?use_span, ?deletion_span); - let suggestion = if let Some(deletion_span) = deletion_span { - let (use_span, replace_lt) = if elide { - let use_span = sess.source_map().span_extend_while_whitespace(use_span); - (use_span, String::new()) - } else { - (use_span, "'_".to_owned()) - }; - debug!(?deletion_span, ?use_span); - - // issue 107998 for the case such as a wrong function pointer type - // `deletion_span` is empty and there is no need to report lifetime uses here - let deletion_span = - if deletion_span.is_empty() { None } else { Some(deletion_span) }; - Some(lints::SingleUseLifetimeSugg { deletion_span, use_span, replace_lt }) - } else { - None - }; - - ctx.emit(lints::SingleUseLifetime { suggestion, param_span, use_span, ident }); - } - BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => { - ctx.emit(lints::UnusedLifetime { deletion_span, ident }); - } - BuiltinLintDiag::NamedArgumentUsedPositionally { - position_sp_to_replace, - position_sp_for_msg, - named_arg_sp, - named_arg_name, - is_formatting_arg, - } => { - let (suggestion, name) = if let Some(positional_arg_to_replace) = position_sp_to_replace - { - let mut name = named_arg_name.clone(); - if is_formatting_arg { - name.push('$') + } + .into_diag(dcx, level), + BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => { + let suggestion = match sugg { + Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd { + left: left_sp, + right: right_sp, + sugg, + }, + None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp }, }; - let span_to_replace = if let Ok(positional_arg_content) = - sess.source_map().span_to_snippet(positional_arg_to_replace) - && positional_arg_content.starts_with(':') - { - positional_arg_to_replace.shrink_to_lo() + lints::DeprecatedWhereClauseLocation { suggestion }.into_diag(dcx, level) + } + BuiltinLintDiag::SingleUseLifetime { + param_span, + use_span: Some((use_span, elide)), + deletion_span, + ident, + } => { + debug!(?param_span, ?use_span, ?deletion_span); + let suggestion = if let Some(deletion_span) = deletion_span { + let (use_span, replace_lt) = if elide { + let use_span = + self.sess.source_map().span_extend_while_whitespace(use_span); + (use_span, String::new()) + } else { + (use_span, "'_".to_owned()) + }; + debug!(?deletion_span, ?use_span); + + // issue 107998 for the case such as a wrong function pointer type + // `deletion_span` is empty and there is no need to report lifetime uses here + let deletion_span = + if deletion_span.is_empty() { None } else { Some(deletion_span) }; + Some(lints::SingleUseLifetimeSugg { deletion_span, use_span, replace_lt }) } else { - positional_arg_to_replace + None }; - (Some(span_to_replace), name) - } else { - (None, String::new()) - }; - ctx.emit(lints::NamedArgumentUsedPositionally { + lints::SingleUseLifetime { suggestion, param_span, use_span, ident } + .into_diag(dcx, level) + } + BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => { + lints::UnusedLifetime { deletion_span, ident }.into_diag(dcx, level) + } + BuiltinLintDiag::NamedArgumentUsedPositionally { + position_sp_to_replace, + position_sp_for_msg, named_arg_sp, - position_label_sp: position_sp_for_msg, - suggestion, - name, named_arg_name, - }); - } - BuiltinLintDiag::AmbiguousGlobReexports { - name, - namespace, - first_reexport_span, - duplicate_reexport_span, - } => { - ctx.emit(lints::AmbiguousGlobReexports { + is_formatting_arg, + } => { + let (suggestion, name) = + if let Some(positional_arg_to_replace) = position_sp_to_replace { + let mut name = named_arg_name.clone(); + if is_formatting_arg { + name.push('$') + }; + let span_to_replace = if let Ok(positional_arg_content) = + self.sess.source_map().span_to_snippet(positional_arg_to_replace) + && positional_arg_content.starts_with(':') + { + positional_arg_to_replace.shrink_to_lo() + } else { + positional_arg_to_replace + }; + (Some(span_to_replace), name) + } else { + (None, String::new()) + }; + + lints::NamedArgumentUsedPositionally { + named_arg_sp, + position_label_sp: position_sp_for_msg, + suggestion, + name, + named_arg_name, + } + .into_diag(dcx, level) + } + BuiltinLintDiag::AmbiguousGlobReexports { + name, + namespace, + first_reexport_span, + duplicate_reexport_span, + } => lints::AmbiguousGlobReexports { first_reexport: first_reexport_span, duplicate_reexport: duplicate_reexport_span, name, namespace, - }); - } - BuiltinLintDiag::HiddenGlobReexports { - name, - namespace, - glob_reexport_span, - private_item_span, - } => { - ctx.emit(lints::HiddenGlobReexports { + } + .into_diag(dcx, level), + BuiltinLintDiag::HiddenGlobReexports { + name, + namespace, + glob_reexport_span, + private_item_span, + } => lints::HiddenGlobReexports { glob_reexport: glob_reexport_span, private_item: private_item_span, name, namespace, - }); - } - BuiltinLintDiag::UnusedQualifications { removal_span } => { - ctx.emit(lints::UnusedQualifications { removal_span }); - } - BuiltinLintDiag::AssociatedConstElidedLifetime { - elided, - span: lt_span, - lifetimes_in_scope, - } => { - let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span }; - let code = if elided { "'static " } else { "'static" }; - ctx.emit(lints::AssociatedConstElidedLifetime { - span: lt_span, - code, + } + .into_diag(dcx, level), + BuiltinLintDiag::UnusedQualifications { removal_span } => { + lints::UnusedQualifications { removal_span }.into_diag(dcx, level) + } + BuiltinLintDiag::AssociatedConstElidedLifetime { elided, + span: lt_span, lifetimes_in_scope, - }); - } - BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => match wildcard_span { - Some(wildcard_span) => { - ctx.emit(lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span }) + } => { + let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span }; + let code = if elided { "'static " } else { "'static" }; + lints::AssociatedConstElidedLifetime { + span: lt_span, + code, + elided, + lifetimes_in_scope, + } + .into_diag(dcx, level) } - None => ctx.emit(lints::UnreachableCfgSelectPredicate { span }), - }, + BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => match wildcard_span { + Some(wildcard_span) => { + lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span } + .into_diag(dcx, level) + } + None => lints::UnreachableCfgSelectPredicate { span }.into_diag(dcx, level), + }, - BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { - ctx.emit(lints::UnusedCrateDependency { extern_crate, local_crate }) + BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => { + lints::UnusedCrateDependency { extern_crate, local_crate }.into_diag(dcx, level) + } + BuiltinLintDiag::UnusedVisibility(span) => { + lints::UnusedVisibility { span }.into_diag(dcx, level) + } + BuiltinLintDiag::AttributeLint(kind) => { + DecorateAttrLint { sess: self.sess, tcx: self.tcx, diagnostic: &kind } + .into_diag(dcx, level) + } } - BuiltinLintDiag::UnusedVisibility(span) => ctx.emit(lints::UnusedVisibility { span }), - BuiltinLintDiag::AttributeLint(kind) => decorate_attribute_lint(ctx, sess, tcx, &kind), } } -pub fn decorate_attribute_lint( - ctx: impl EmitDiag, - sess: &Session, - tcx: Option>, - kind: &AttributeLintKind, -) { - match kind { - &AttributeLintKind::UnusedDuplicate { this, other, warning } => { - ctx.emit(lints::UnusedDuplicate { this, other, warning }) - } - AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => { - ctx.emit(lints::IllFormedAttributeInput { - num_suggestions: suggestions.len(), - suggestions: DiagArgValue::StrListSepByAnd( - suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), - ), - has_docs: docs.is_some(), - docs: docs.unwrap_or(""), - }) - } - AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => ctx - .emit(lints::EmptyAttributeList { - attr_span: *first_span, - attr_path: attr_path.clone(), - valid_without_list: *valid_without_list, - }), - AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => { - ctx.emit(lints::InvalidTargetLint { - name: name.clone(), +/// This is a diagnostic struct that will decorate a `AttributeLintKind` +/// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed. +pub struct DecorateAttrLint<'a, 'sess, 'tcx> { + pub sess: &'sess Session, + pub tcx: Option>, + pub diagnostic: &'a AttributeLintKind, +} + +impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + match self.diagnostic { + &AttributeLintKind::UnusedDuplicate { this, other, warning } => { + lints::UnusedDuplicate { this, other, warning }.into_diag(dcx, level) + } + AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => { + lints::IllFormedAttributeInput { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + has_docs: docs.is_some(), + docs: docs.unwrap_or(""), + } + .into_diag(dcx, level) + } + AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { + lints::EmptyAttributeList { + attr_span: *first_span, + attr_path: attr_path.clone(), + valid_without_list: *valid_without_list, + } + .into_diag(dcx, level) + } + AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => { + lints::InvalidTargetLint { + name: name.clone(), + target, + applied: DiagArgValue::StrListSepByAnd( + applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(), + ), + only, + attr_span: *attr_span, + } + .into_diag(dcx, level) + } + &AttributeLintKind::InvalidStyle { + ref name, + is_used_as_inner, target, - applied: DiagArgValue::StrListSepByAnd( - applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(), - ), - only, - attr_span: *attr_span, - }) - } - &AttributeLintKind::InvalidStyle { ref name, is_used_as_inner, target, target_span } => ctx - .emit(lints::InvalidAttrStyle { + target_span, + } => lints::InvalidAttrStyle { name: name.clone(), is_used_as_inner, target_span: (!is_used_as_inner).then_some(target_span), target, - }), - &AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span, sugg_spans } => ctx - .emit(lints::UnsafeAttrOutsideUnsafeLint { - span: attribute_name_span, - suggestion: sugg_spans - .map(|(left, right)| lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }), - }), - &AttributeLintKind::UnexpectedCfgName(name, value) => { - ctx.emit(check_cfg::unexpected_cfg_name(sess, tcx, name, value)) - } - &AttributeLintKind::UnexpectedCfgValue(name, value) => { - ctx.emit(check_cfg::unexpected_cfg_value(sess, tcx, name, value)) - } - &AttributeLintKind::DuplicateDocAlias { first_definition } => { - ctx.emit(lints::DocAliasDuplicated { first_defn: first_definition }) - } + } + .into_diag(dcx, level), + &AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span, sugg_spans } => { + lints::UnsafeAttrOutsideUnsafeLint { + span: attribute_name_span, + suggestion: sugg_spans.map(|(left, right)| { + lints::UnsafeAttrOutsideUnsafeSuggestion { left, right } + }), + } + .into_diag(dcx, level) + } + &AttributeLintKind::UnexpectedCfgName(name, value) => { + check_cfg::unexpected_cfg_name(self.sess, self.tcx, name, value) + .into_diag(dcx, level) + } + &AttributeLintKind::UnexpectedCfgValue(name, value) => { + check_cfg::unexpected_cfg_value(self.sess, self.tcx, name, value) + .into_diag(dcx, level) + } + &AttributeLintKind::DuplicateDocAlias { first_definition } => { + lints::DocAliasDuplicated { first_defn: first_definition }.into_diag(dcx, level) + } - &AttributeLintKind::DocAutoCfgExpectsHideOrShow => { - ctx.emit(lints::DocAutoCfgExpectsHideOrShow) - } + &AttributeLintKind::DocAutoCfgExpectsHideOrShow => { + lints::DocAutoCfgExpectsHideOrShow.into_diag(dcx, level) + } - &AttributeLintKind::AmbiguousDeriveHelpers => ctx.emit(lints::AmbiguousDeriveHelpers), + &AttributeLintKind::AmbiguousDeriveHelpers => { + lints::AmbiguousDeriveHelpers.into_diag(dcx, level) + } - &AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name } => { - ctx.emit(lints::DocAutoCfgHideShowUnexpectedItem { attr_name }) - } + &AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name } => { + lints::DocAutoCfgHideShowUnexpectedItem { attr_name }.into_diag(dcx, level) + } - &AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name } => { - ctx.emit(lints::DocAutoCfgHideShowExpectsList { attr_name }) - } + &AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name } => { + lints::DocAutoCfgHideShowExpectsList { attr_name }.into_diag(dcx, level) + } - &AttributeLintKind::DocInvalid => ctx.emit(lints::DocInvalid), + &AttributeLintKind::DocInvalid => lints::DocInvalid.into_diag(dcx, level), - &AttributeLintKind::DocUnknownInclude { span, inner, value } => { - ctx.emit(lints::DocUnknownInclude { - inner, - value, - sugg: (span, Applicability::MaybeIncorrect), - }) - } + &AttributeLintKind::DocUnknownInclude { span, inner, value } => { + lints::DocUnknownInclude { + inner, + value, + sugg: (span, Applicability::MaybeIncorrect), + } + .into_diag(dcx, level) + } - &AttributeLintKind::DocUnknownSpotlight { span } => { - ctx.emit(lints::DocUnknownSpotlight { sugg_span: span }) - } + &AttributeLintKind::DocUnknownSpotlight { span } => { + lints::DocUnknownSpotlight { sugg_span: span }.into_diag(dcx, level) + } - &AttributeLintKind::DocUnknownPasses { name, span } => { - ctx.emit(lints::DocUnknownPasses { name, note_span: span }) - } + &AttributeLintKind::DocUnknownPasses { name, span } => { + lints::DocUnknownPasses { name, note_span: span }.into_diag(dcx, level) + } - &AttributeLintKind::DocUnknownPlugins { span } => { - ctx.emit(lints::DocUnknownPlugins { label_span: span }) - } + &AttributeLintKind::DocUnknownPlugins { span } => { + lints::DocUnknownPlugins { label_span: span }.into_diag(dcx, level) + } - &AttributeLintKind::DocUnknownAny { name } => ctx.emit(lints::DocUnknownAny { name }), + &AttributeLintKind::DocUnknownAny { name } => { + lints::DocUnknownAny { name }.into_diag(dcx, level) + } - &AttributeLintKind::DocAutoCfgWrongLiteral => ctx.emit(lints::DocAutoCfgWrongLiteral), + &AttributeLintKind::DocAutoCfgWrongLiteral => { + lints::DocAutoCfgWrongLiteral.into_diag(dcx, level) + } - &AttributeLintKind::DocTestTakesList => ctx.emit(lints::DocTestTakesList), + &AttributeLintKind::DocTestTakesList => lints::DocTestTakesList.into_diag(dcx, level), - &AttributeLintKind::DocTestUnknown { name } => ctx.emit(lints::DocTestUnknown { name }), + &AttributeLintKind::DocTestUnknown { name } => { + lints::DocTestUnknown { name }.into_diag(dcx, level) + } - &AttributeLintKind::DocTestLiteral => ctx.emit(lints::DocTestLiteral), + &AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.into_diag(dcx, level), - &AttributeLintKind::AttrCrateLevelOnly => ctx.emit(lints::AttrCrateLevelOnly), + &AttributeLintKind::AttrCrateLevelOnly => { + lints::AttrCrateLevelOnly.into_diag(dcx, level) + } - &AttributeLintKind::DoNotRecommendDoesNotExpectArgs => { - ctx.emit(lints::DoNotRecommendDoesNotExpectArgs) - } + &AttributeLintKind::DoNotRecommendDoesNotExpectArgs => { + lints::DoNotRecommendDoesNotExpectArgs.into_diag(dcx, level) + } - &AttributeLintKind::CrateTypeUnknown { span, suggested } => { - ctx.emit(lints::UnknownCrateTypes { + &AttributeLintKind::CrateTypeUnknown { span, suggested } => lints::UnknownCrateTypes { sugg: suggested.map(|s| lints::UnknownCrateTypesSuggestion { span, snippet: s }), - }) - } + } + .into_diag(dcx, level), - &AttributeLintKind::MalformedDoc => ctx.emit(lints::MalformedDoc), + &AttributeLintKind::MalformedDoc => lints::MalformedDoc.into_diag(dcx, level), - &AttributeLintKind::ExpectedNoArgs => ctx.emit(lints::ExpectedNoArgs), + &AttributeLintKind::ExpectedNoArgs => lints::ExpectedNoArgs.into_diag(dcx, level), - &AttributeLintKind::ExpectedNameValue => ctx.emit(lints::ExpectedNameValue), - &AttributeLintKind::MalformedOnUnimplementedAttr { span } => { - ctx.emit(lints::MalformedOnUnimplementedAttrLint { span }) - } - &AttributeLintKind::MalformedOnConstAttr { span } => { - ctx.emit(lints::MalformedOnConstAttrLint { span }) - } - AttributeLintKind::MalformedDiagnosticFormat { warning } => match warning { - FormatWarning::PositionalArgument { .. } => { - ctx.emit(lints::DisallowedPositionalArgument) - } - FormatWarning::InvalidSpecifier { .. } => ctx.emit(lints::InvalidFormatSpecifier), - }, - AttributeLintKind::DiagnosticWrappedParserError { description, label, span } => { - ctx.emit(lints::WrappedParserError { description, label, span: *span }) - } - &AttributeLintKind::IgnoredDiagnosticOption { option_name, first_span, later_span } => { - ctx.emit(lints::IgnoredDiagnosticOption { option_name, first_span, later_span }) - } - &AttributeLintKind::MissingOptionsForOnUnimplemented => { - ctx.emit(lints::MissingOptionsForOnUnimplementedAttr) - } - &AttributeLintKind::MissingOptionsForOnConst => { - ctx.emit(lints::MissingOptionsForOnConstAttr) + &AttributeLintKind::ExpectedNameValue => lints::ExpectedNameValue.into_diag(dcx, level), + &AttributeLintKind::MalformedOnUnimplementedAttr { span } => { + lints::MalformedOnUnimplementedAttrLint { span }.into_diag(dcx, level) + } + &AttributeLintKind::MalformedOnConstAttr { span } => { + lints::MalformedOnConstAttrLint { span }.into_diag(dcx, level) + } + AttributeLintKind::MalformedDiagnosticFormat { warning } => match warning { + FormatWarning::PositionalArgument { .. } => { + lints::DisallowedPositionalArgument.into_diag(dcx, level) + } + FormatWarning::InvalidSpecifier { .. } => { + lints::InvalidFormatSpecifier.into_diag(dcx, level) + } + }, + AttributeLintKind::DiagnosticWrappedParserError { description, label, span } => { + lints::WrappedParserError { description, label, span: *span }.into_diag(dcx, level) + } + &AttributeLintKind::IgnoredDiagnosticOption { option_name, first_span, later_span } => { + lints::IgnoredDiagnosticOption { option_name, first_span, later_span } + .into_diag(dcx, level) + } + &AttributeLintKind::MissingOptionsForOnUnimplemented => { + lints::MissingOptionsForOnUnimplementedAttr.into_diag(dcx, level) + } + &AttributeLintKind::MissingOptionsForOnConst => { + lints::MissingOptionsForOnConstAttr.into_diag(dcx, level) + } } } } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index e524a66910d93..194a8cfc2ea3d 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -131,8 +131,8 @@ use unused::*; #[rustfmt::skip] pub use builtin::{MissingDoc, SoftLints}; pub use context::{CheckLintNameResult, EarlyContext, LateContext, LintContext, LintStore}; -pub use early::diagnostics::{decorate_attribute_lint, decorate_builtin_lint}; -pub use early::{EarlyCheckNode, EmitDiag, check_ast_node}; +pub use early::diagnostics::{DecorateAttrLint, DecorateBuiltinLint}; +pub use early::{EarlyCheckNode, check_ast_node}; pub use late::{check_crate, late_lint_mod, unerased_lint_store}; pub use levels::LintLevelsBuilder; pub use passes::{EarlyLintPass, LateLintPass};