diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index c15dc024736..0d1d017d874 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,7 +1,7 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DiagnosticMessage, Level, MultiSpan, SubdiagnosticMessage, Substitution, - SubstitutionPart, SuggestionStyle, + CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, MultiSpan, + SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::stable_map::FxHashMap; use rustc_error_messages::FluentValue; @@ -168,6 +168,14 @@ pub trait AddSubdiagnostic { fn add_to_diagnostic(self, diag: &mut Diagnostic); } +/// Trait implemented by lint types. This should not be implemented manually. Instead, use +/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. +#[rustc_diagnostic_item = "DecorateLint"] +pub trait DecorateLint<'a, G: EmissionGuarantee> { + /// Decorate and emit a lint. + fn decorate_lint(self, diag: LintDiagnosticBuilder<'a, G>); +} + #[must_use] #[derive(Clone, Debug, Encodable, Decodable)] pub struct Diagnostic { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a64dd42ec77..ffe4ecebb2e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -370,7 +370,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { impl error::Error for ExplicitBug {} pub use diagnostic::{ - AddSubdiagnostic, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, + AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder}; diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 1e1c423982b..83328093e9f 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -22,7 +22,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync; use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err}; -use rustc_errors::{Applicability, LintDiagnosticBuilder, MultiSpan, SuggestionStyle}; +use rustc_errors::{ + Applicability, DecorateLint, LintDiagnosticBuilder, MultiSpan, SuggestionStyle, +}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::def_id::{CrateNum, DefId}; @@ -870,6 +872,17 @@ fn lookup>( decorate: impl for<'a> FnOnce(LintDiagnosticBuilder<'a, ()>), ); + /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, + /// typically generated by `#[derive(LintDiagnostic)]`). + fn emit_spanned_lint>( + &self, + lint: &'static Lint, + span: S, + decorator: impl for<'a> DecorateLint<'a, ()>, + ) { + self.lookup(lint, Some(span), |diag| decorator.decorate_lint(diag)); + } + fn struct_span_lint>( &self, lint: &'static Lint, @@ -878,6 +891,13 @@ fn struct_span_lint>( ) { self.lookup(lint, Some(span), decorate); } + + /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically + /// generated by `#[derive(LintDiagnostic)]`). + fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> DecorateLint<'a, ()>) { + self.lookup(lint, None as Option, |diag| decorator.decorate_lint(diag)); + } + /// Emit a lint at the appropriate level, with no associated span. fn lint( &self, diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 5bcf9390c07..738f475983e 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -414,7 +414,7 @@ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { let Impl { of_trait: Some(of_trait), .. } = impl_ && let Some(def_id) = of_trait.trait_def_id() && let Some(name) = cx.tcx.get_diagnostic_name(def_id) && - matches!(name, sym::SessionDiagnostic | sym::AddSubdiagnostic) + matches!(name, sym::SessionDiagnostic | sym::AddSubdiagnostic | sym::DecorateLint) { found_impl = true; break; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index e0942f86f16..3d8b0763122 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -34,7 +34,7 @@ use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; use rustc_data_structures::vec_map::VecMap; -use rustc_errors::{ErrorGuaranteed, LintDiagnosticBuilder, MultiSpan}; +use rustc_errors::{DecorateLint, ErrorGuaranteed, LintDiagnosticBuilder, MultiSpan}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; @@ -2787,6 +2787,18 @@ pub fn lint_level_at_node( } } + /// Emit a lint at `span` from a lint struct (some type that implements `DecorateLint`, + /// typically generated by `#[derive(LintDiagnostic)]`). + pub fn emit_spanned_lint( + self, + lint: &'static Lint, + hir_id: HirId, + span: impl Into, + decorator: impl for<'a> DecorateLint<'a, ()>, + ) { + self.struct_span_lint_hir(lint, hir_id, span, |diag| decorator.decorate_lint(diag)) + } + pub fn struct_span_lint_hir( self, lint: &'static Lint, @@ -2798,6 +2810,17 @@ pub fn struct_span_lint_hir( struct_lint_level(self.sess, lint, level, src, Some(span.into()), decorate); } + /// Emit a lint from a lint struct (some type that implements `DecorateLint`, typically + /// generated by `#[derive(LintDiagnostic)]`). + pub fn emit_lint( + self, + lint: &'static Lint, + id: HirId, + decorator: impl for<'a> DecorateLint<'a, ()>, + ) { + self.struct_lint_node(lint, id, |diag| decorator.decorate_lint(diag)) + } + pub fn struct_lint_node( self, lint: &'static Lint, diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 4e28d2b6001..65a2a18e02f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -173,6 +173,7 @@ DebugTuple, Decodable, Decoder, + DecorateLint, Default, Deref, DiagnosticMessage,