Skip to content

Commit a31ed16

Browse files
committed
Make lint diagnostics responsible for storing their span
1 parent 7c4ac06 commit a31ed16

File tree

6 files changed

+63
-55
lines changed

6 files changed

+63
-55
lines changed

compiler/rustc_errors/src/diagnostic.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -198,10 +198,11 @@ pub trait SubdiagMessageOp<G: EmissionGuarantee> =
198198
/// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
199199
#[rustc_diagnostic_item = "LintDiagnostic"]
200200
pub trait LintDiagnostic<'a, G: EmissionGuarantee> {
201-
/// Decorate and emit a lint.
201+
/// Decorate a lint.
202202
fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>);
203203

204204
fn msg(&self) -> DiagMessage;
205+
fn span(&self) -> Option<MultiSpan>;
205206
}
206207

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

compiler/rustc_lint/src/context.rs

+1-14
Original file line numberDiff line numberDiff line change
@@ -566,19 +566,6 @@ pub trait LintContext {
566566
decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
567567
);
568568

569-
/// Emit a lint at `span` from a lint struct (some type that implements `LintDiagnostic`,
570-
/// typically generated by `#[derive(LintDiagnostic)]`).
571-
fn emit_span_lint<S: Into<MultiSpan>>(
572-
&self,
573-
lint: &'static Lint,
574-
span: S,
575-
decorator: impl for<'a> LintDiagnostic<'a, ()>,
576-
) {
577-
self.opt_span_lint(lint, Some(span), decorator.msg(), |diag| {
578-
decorator.decorate_lint(diag);
579-
});
580-
}
581-
582569
/// Emit a lint at the appropriate level, with an associated span.
583570
///
584571
/// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
@@ -596,7 +583,7 @@ pub trait LintContext {
596583
/// Emit a lint from a lint struct (some type that implements `LintDiagnostic`, typically
597584
/// generated by `#[derive(LintDiagnostic)]`).
598585
fn emit_lint(&self, lint: &'static Lint, decorator: impl for<'a> LintDiagnostic<'a, ()>) {
599-
self.opt_span_lint(lint, None as Option<Span>, decorator.msg(), |diag| {
586+
self.opt_span_lint(lint, decorator.span(), decorator.msg(), |diag| {
600587
decorator.decorate_lint(diag);
601588
});
602589
}

compiler/rustc_macros/src/diagnostics/diagnostic.rs

+49-6
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,28 @@ use crate::diagnostics::diagnostic_builder::DiagnosticDeriveKind;
66
use crate::diagnostics::error::{span_err, DiagnosticDeriveError};
77
use crate::diagnostics::utils::SetOnce;
88
use proc_macro2::TokenStream;
9-
use quote::quote;
9+
use quote::{quote, quote_spanned};
1010
use syn::spanned::Spanned;
1111
use synstructure::Structure;
1212

13+
use super::utils::FieldInnerTy;
14+
1315
/// The central struct for constructing the `into_diag` method from an annotated struct.
1416
pub(crate) struct DiagnosticDerive<'a> {
1517
structure: Structure<'a>,
1618
}
1719

1820
impl<'a> DiagnosticDerive<'a> {
21+
const KIND: DiagnosticDeriveKind = DiagnosticDeriveKind::Diagnostic;
22+
1923
pub(crate) fn new(structure: Structure<'a>) -> Self {
2024
Self { structure }
2125
}
2226

2327
pub(crate) fn into_tokens(self) -> TokenStream {
2428
let DiagnosticDerive { mut structure } = self;
25-
let kind = DiagnosticDeriveKind::Diagnostic;
2629
let slugs = RefCell::new(Vec::new());
27-
let implementation = kind.each_variant(&mut structure, |mut builder, variant| {
30+
let implementation = Self::KIND.each_variant(&mut structure, |mut builder, variant| {
2831
let preamble = builder.preamble(variant);
2932
let body = builder.body(variant);
3033

@@ -98,14 +101,15 @@ pub(crate) struct LintDiagnosticDerive<'a> {
98101
}
99102

100103
impl<'a> LintDiagnosticDerive<'a> {
104+
const KIND: DiagnosticDeriveKind = DiagnosticDeriveKind::LintDiagnostic;
105+
101106
pub(crate) fn new(structure: Structure<'a>) -> Self {
102107
Self { structure }
103108
}
104109

105110
pub(crate) fn into_tokens(self) -> TokenStream {
106111
let LintDiagnosticDerive { mut structure } = self;
107-
let kind = DiagnosticDeriveKind::LintDiagnostic;
108-
let implementation = kind.each_variant(&mut structure, |mut builder, variant| {
112+
let implementation = Self::KIND.each_variant(&mut structure, |mut builder, variant| {
109113
let preamble = builder.preamble(variant);
110114
let body = builder.body(variant);
111115

@@ -119,7 +123,7 @@ impl<'a> LintDiagnosticDerive<'a> {
119123
});
120124

121125
let slugs = RefCell::new(Vec::new());
122-
let msg = kind.each_variant(&mut structure, |mut builder, variant| {
126+
let msg = Self::KIND.each_variant(&mut structure, |mut builder, variant| {
123127
// Collect the slug by generating the preamble.
124128
let _ = builder.preamble(variant);
125129

@@ -152,6 +156,41 @@ impl<'a> LintDiagnosticDerive<'a> {
152156
}
153157
});
154158

159+
let span = Self::KIND.each_variant(&mut structure, |_, variant| {
160+
variant
161+
.bindings()
162+
.iter()
163+
.find_map(|binding_info| {
164+
let field = binding_info.ast();
165+
166+
field.attrs.iter().find_map(|attr| {
167+
if attr.path().segments.last().unwrap().ident != "primary_span"
168+
|| !matches!(attr.meta, syn::Meta::Path(_))
169+
{
170+
return None;
171+
}
172+
173+
let ident = &binding_info.binding;
174+
175+
// Generate `.clone()` unconditionally as the inner type may
176+
// contain a `MultiSpan` which is not `Copy`.
177+
Some(match FieldInnerTy::from_type(&field.ty) {
178+
FieldInnerTy::Plain(_) | FieldInnerTy::Vec(_) => {
179+
quote_spanned! {field.ty.span()=>
180+
std::option::Option::Some(#ident.clone().into())
181+
}
182+
}
183+
FieldInnerTy::Option(_) => {
184+
quote_spanned! {field.ty.span()=>
185+
#ident.clone().into()
186+
}
187+
}
188+
})
189+
})
190+
})
191+
.unwrap_or_else(|| quote! { std::option::Option::None })
192+
});
193+
155194
let mut imp = structure.gen_impl(quote! {
156195
gen impl<'__a> rustc_errors::LintDiagnostic<'__a, ()> for @Self {
157196
#[track_caller]
@@ -165,6 +204,10 @@ impl<'a> LintDiagnosticDerive<'a> {
165204
fn msg(&self) -> rustc_errors::DiagMessage {
166205
#msg
167206
}
207+
208+
fn span(&self) -> std::option::Option<rustc_errors::MultiSpan> {
209+
#span
210+
}
168211
}
169212
});
170213
for test in slugs.borrow().iter().map(|s| generate_test(s, &structure)) {

compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs

+5-13
Original file line numberDiff line numberDiff line change
@@ -315,20 +315,12 @@ impl DiagnosticDeriveVariantBuilder {
315315
// `arg` call will not be generated.
316316
(Meta::Path(_), "skip_arg") => return Ok(quote! {}),
317317
(Meta::Path(_), "primary_span") => {
318-
match self.kind {
319-
DiagnosticDeriveKind::Diagnostic => {
320-
report_error_if_not_applied_to_span(attr, &info)?;
318+
report_error_if_not_applied_to_span(attr, &info)?;
321319

322-
return Ok(quote! {
323-
diag.span(#binding);
324-
});
325-
}
326-
DiagnosticDeriveKind::LintDiagnostic => {
327-
throw_invalid_attr!(attr, |diag| {
328-
diag.help("the `primary_span` field attribute is not valid for lint diagnostics")
329-
})
330-
}
331-
}
320+
return Ok(match self.kind {
321+
DiagnosticDeriveKind::Diagnostic => quote! { diag.span(#binding); },
322+
DiagnosticDeriveKind::LintDiagnostic => quote! {},
323+
});
332324
}
333325
(Meta::Path(_), "subdiagnostic") => {
334326
return Ok(quote! { diag.subdiagnostic(diag.dcx, #binding); });

compiler/rustc_macros/src/diagnostics/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ pub 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 fn diagnostic_derive(mut s: Structure<'_>) -> TokenStream {
9192
/// Then, later, to emit the error:
9293
///
9394
/// ```ignore (rust)
94-
/// cx.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

+4-20
Original file line numberDiff line numberDiff line change
@@ -2384,23 +2384,6 @@ impl<'tcx> TyCtxt<'tcx> {
23842384
T::collect_and_apply(iter, |xs| self.mk_bound_variable_kinds(xs))
23852385
}
23862386

2387-
/// Emit a lint at `span` from a lint struct (some type that implements `LintDiagnostic`,
2388-
/// typically generated by `#[derive(LintDiagnostic)]`).
2389-
#[track_caller]
2390-
pub fn emit_node_span_lint(
2391-
self,
2392-
lint: &'static Lint,
2393-
hir_id: HirId,
2394-
span: impl Into<MultiSpan>,
2395-
decorator: impl for<'a> LintDiagnostic<'a, ()>,
2396-
) {
2397-
let msg = decorator.msg();
2398-
let (level, src) = self.lint_level_at_node(lint, hir_id);
2399-
lint_level(self.sess, lint, level, src, Some(span.into()), msg, |diag| {
2400-
decorator.decorate_lint(diag);
2401-
})
2402-
}
2403-
24042387
/// Emit a lint at the appropriate level for a hir node, with an associated span.
24052388
///
24062389
/// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
@@ -2466,9 +2449,10 @@ impl<'tcx> TyCtxt<'tcx> {
24662449
id: HirId,
24672450
decorator: impl for<'a> LintDiagnostic<'a, ()>,
24682451
) {
2469-
self.node_lint(lint, id, decorator.msg(), |diag| {
2470-
decorator.decorate_lint(diag);
2471-
})
2452+
let (level, src) = self.lint_level_at_node(lint, id);
2453+
lint_level(self.sess, lint, level, src, decorator.span(), decorator.msg(), |diag| {
2454+
decorator.decorate_lint(diag)
2455+
});
24722456
}
24732457

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

0 commit comments

Comments
 (0)