Skip to content

Commit 1f6b731

Browse files
committed
Make lint diagnostics responsible for storing their span
1 parent f61306d commit 1f6b731

File tree

6 files changed

+64
-54
lines changed

6 files changed

+64
-54
lines changed

compiler/rustc_errors/src/diagnostic.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,10 @@ pub trait SubdiagMessageOp<G: EmissionGuarantee> =
195195
/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
196196
#[rustc_diagnostic_item = "LintDiagnostic"]
197197
pub trait LintDiagnostic<'a, G: EmissionGuarantee> {
198-
/// Decorate and emit a lint.
198+
/// Decorate a lint.
199199
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>);
200+
201+
fn span(&self) -> Option<MultiSpan>;
200202
}
201203

202204
#[derive(Clone, Debug, Encodable, Decodable)]

compiler/rustc_lint/src/context.rs

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -574,19 +574,6 @@ pub trait LintContext {
574574
decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
575575
);
576576

577-
/// Emit a lint at `span` from a lint struct (some type that implements `LintDiagnostic`,
578-
/// typically generated by `#[derive(LintDiagnostic)]`).
579-
fn emit_span_lint<S: Into<MultiSpan>>(
580-
&self,
581-
lint: &'static Lint,
582-
span: S,
583-
decorator: impl for<'a> LintDiagnostic<'a, ()>,
584-
) {
585-
self.opt_span_lint(lint, Some(span), |lint| {
586-
decorator.decorate_lint(lint);
587-
});
588-
}
589-
590577
/// Emit a lint at the appropriate level, with an associated span.
591578
///
592579
/// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
@@ -603,8 +590,8 @@ pub trait LintContext {
603590
/// Emit a lint from a lint struct (some type that implements `LintDiagnostic`, typically
604591
/// generated by `#[derive(LintDiagnostic)]`).
605592
fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> LintDiagnostic<'a, ()>) {
606-
self.opt_span_lint(lint, None as Option<Span>, |lint| {
607-
decorator.decorate_lint(lint);
593+
self.opt_span_lint(lint, decorator.span(), |diag| {
594+
decorator.decorate_lint(diag);
608595
});
609596
}
610597

compiler/rustc_macros/src/diagnostics/diagnostic.rs

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
use std::cell::RefCell;
44

55
use proc_macro2::TokenStream;
6-
use quote::quote;
6+
use quote::{quote, quote_spanned};
77
use syn::spanned::Spanned;
88
use synstructure::Structure;
99

10+
use super::utils::FieldInnerTy;
1011
use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind;
1112
use crate::diagnostics::error::{DiagnosticDeriveError, span_err};
1213
use crate::diagnostics::utils::SetOnce;
@@ -17,15 +18,16 @@ pub(crate) struct DiagnosticDerive<'a> {
1718
}
1819

1920
impl<'a> DiagnosticDerive<'a> {
21+
const KIND: DiagnosticDeriveKind = DiagnosticDeriveKind::Diagnostic;
22+
2023
pub(crate) fn new(structure: Structure<'a>) -> Self {
2124
Self { structure }
2225
}
2326

2427
pub(crate) fn into_tokens(self) -> TokenStream {
2528
let DiagnosticDerive { mut structure } = self;
26-
let kind = DiagnosticDeriveKind::Diagnostic;
2729
let slugs = RefCell::new(Vec::new());
28-
let implementation = kind.each_variant(&mut structure, |mut builder, variant| {
30+
let implementation = Self::KIND.each_variant(&mut structure, |mut builder, variant| {
2931
let preamble = builder.preamble(variant);
3032
let body = builder.body(variant);
3133

@@ -101,15 +103,16 @@ pub(crate) struct LintDiagnosticDerive<'a> {
101103
}
102104

103105
impl<'a> LintDiagnosticDerive<'a> {
106+
const KIND: DiagnosticDeriveKind = DiagnosticDeriveKind::LintDiagnostic;
107+
104108
pub(crate) fn new(structure: Structure<'a>) -> Self {
105109
Self { structure }
106110
}
107111

108112
pub(crate) fn into_tokens(self) -> TokenStream {
109113
let LintDiagnosticDerive { mut structure } = self;
110-
let kind = DiagnosticDeriveKind::LintDiagnostic;
111114
let slugs = RefCell::new(Vec::new());
112-
let implementation = kind.each_variant(&mut structure, |mut builder, variant| {
115+
let implementation = Self::KIND.each_variant(&mut structure, |mut builder, variant| {
113116
let preamble = builder.preamble(variant);
114117
let body = builder.body(variant);
115118

@@ -151,6 +154,41 @@ impl<'a> LintDiagnosticDerive<'a> {
151154
}
152155
});
153156

157+
let span = Self::KIND.each_variant(&mut structure, |_, variant| {
158+
variant
159+
.bindings()
160+
.iter()
161+
.find_map(|binding_info| {
162+
let field = binding_info.ast();
163+
164+
field.attrs.iter().find_map(|attr| {
165+
if attr.path().segments.last().unwrap().ident != "primary_span"
166+
|| !matches!(attr.meta, syn::Meta::Path(_))
167+
{
168+
return None;
169+
}
170+
171+
let ident = &binding_info.binding;
172+
173+
// Generate `.clone()` unconditionally as the inner type may
174+
// contain a `MultiSpan` which is not `Copy`.
175+
Some(match FieldInnerTy::from_type(&field.ty) {
176+
FieldInnerTy::Plain(_) | FieldInnerTy::Vec(_) => {
177+
quote_spanned! {field.ty.span()=>
178+
std::option::Option::Some(#ident.clone().into())
179+
}
180+
}
181+
FieldInnerTy::Option(_) => {
182+
quote_spanned! {field.ty.span()=>
183+
#ident.clone().into()
184+
}
185+
}
186+
})
187+
})
188+
})
189+
.unwrap_or_else(|| quote! { std::option::Option::None })
190+
});
191+
154192
// FIXME(edition_2024): Fix the `keyword_idents_2024` lint to not trigger here?
155193
#[allow(keyword_idents_2024)]
156194
let mut imp = structure.gen_impl(quote! {
@@ -162,6 +200,10 @@ impl<'a> LintDiagnosticDerive<'a> {
162200
) {
163201
#implementation;
164202
}
203+
204+
fn span(&self) -> std::option::Option<rustc_errors::MultiSpan> {
205+
#span
206+
}
165207
}
166208
});
167209
for test in slugs.borrow().iter().map(|s| generate_test(s, &structure)) {

compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -328,20 +328,13 @@ impl DiagnosticDeriveVariantBuilder {
328328
// `arg` call will not be generated.
329329
(Meta::Path(_), "skip_arg") => return Ok(quote! {}),
330330
(Meta::Path(_), "primary_span") => {
331-
match self.kind {
332-
DiagnosticDeriveKind::Diagnostic => {
333-
report_error_if_not_applied_to_span(attr, &info)?;
331+
report_error_if_not_applied_to_span(attr, &info)?;
334332

335-
return Ok(quote! {
336-
diag.span(#binding);
337-
});
338-
}
339-
DiagnosticDeriveKind::LintDiagnostic => {
340-
throw_invalid_attr!(attr, |diag| {
341-
diag.help("the `primary_span` field attribute is not valid for lint diagnostics")
342-
})
343-
}
344-
}
333+
return Ok(match self.kind {
334+
DiagnosticDeriveKind::Diagnostic => quote! { diag.span(#binding); },
335+
// Handled separately in `LintDiagnosticDerive::into_tokens`.
336+
DiagnosticDeriveKind::LintDiagnostic => quote! {},
337+
});
345338
}
346339
(Meta::Path(_), "subdiagnostic") => {
347340
return Ok(quote! { diag.subdiagnostic(#binding); });

compiler/rustc_macros/src/diagnostics/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub(super) fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
7070
/// method: Symbol,
7171
/// success_ordering: Symbol,
7272
/// fail_ordering: Symbol,
73+
/// #[primary_span]
7374
/// #[label(fail_label)]
7475
/// fail_order_arg_span: Span,
7576
/// #[label(success_label)]
@@ -91,7 +92,7 @@ pub(super) fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
9192
/// Then, later, to emit the error:
9293
///
9394
/// ```ignore (rust)
94-
/// cx.emit_span_lint(INVALID_ATOMIC_ORDERING, fail_order_arg_span, AtomicOrderingInvalidLint {
95+
/// tcx.emit_lint(INVALID_ATOMIC_ORDERING, AtomicOrderingInvalidLint {
9596
/// method,
9697
/// success_ordering,
9798
/// fail_ordering,

compiler/rustc_middle/src/ty/context.rs

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2909,22 +2909,6 @@ impl<'tcx> TyCtxt<'tcx> {
29092909
T::collect_and_apply(iter, |xs| self.mk_bound_variable_kinds(xs))
29102910
}
29112911

2912-
/// Emit a lint at `span` from a lint struct (some type that implements `LintDiagnostic`,
2913-
/// typically generated by `#[derive(LintDiagnostic)]`).
2914-
#[track_caller]
2915-
pub fn emit_node_span_lint(
2916-
self,
2917-
lint: &'static Lint,
2918-
hir_id: HirId,
2919-
span: impl Into<MultiSpan>,
2920-
decorator: impl for<'a> LintDiagnostic<'a, ()>,
2921-
) {
2922-
let (level, src) = self.lint_level_at_node(lint, hir_id);
2923-
lint_level(self.sess, lint, level, src, Some(span.into()), |lint| {
2924-
decorator.decorate_lint(lint);
2925-
})
2926-
}
2927-
29282912
/// Emit a lint at the appropriate level for a hir node, with an associated span.
29292913
///
29302914
/// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
@@ -2989,9 +2973,10 @@ impl<'tcx> TyCtxt<'tcx> {
29892973
id: HirId,
29902974
decorator: impl for<'a> LintDiagnostic<'a, ()>,
29912975
) {
2992-
self.node_lint(lint, id, |lint| {
2993-
decorator.decorate_lint(lint);
2994-
})
2976+
let (level, src) = self.lint_level_at_node(lint, id);
2977+
lint_level(self.sess, lint, level, src, decorator.span(), |diag| {
2978+
decorator.decorate_lint(diag)
2979+
});
29952980
}
29962981

29972982
/// Emit a lint at the appropriate level for a hir node.

0 commit comments

Comments
 (0)