Skip to content

Commit d12af20

Browse files
Rollup merge of #154432 - GuillaumeGomez:try-rm-AttributeLint, r=JonathanBrouwer
Set up API to make it possible to pass closures instead of `AttributeLint` Part of #153099. This PR sets up the base implementations needed to remove `AttributeLintKind` entirely and migrate two variants as examples. r? @JonathanBrouwer
2 parents eca0926 + ded2eea commit d12af20

17 files changed

Lines changed: 200 additions & 103 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4004,6 +4004,7 @@ dependencies = [
40044004
"rustc_ast_pretty",
40054005
"rustc_data_structures",
40064006
"rustc_error_messages",
4007+
"rustc_errors",
40074008
"rustc_hashes",
40084009
"rustc_hir_id",
40094010
"rustc_index",

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use std::sync::Arc;
4141
use rustc_ast::node_id::NodeMap;
4242
use rustc_ast::visit::Visitor;
4343
use rustc_ast::{self as ast, *};
44-
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
44+
use rustc_attr_parsing::{AttributeParser, EmitAttribute, Late, OmitDoc};
4545
use rustc_data_structures::fingerprint::Fingerprint;
4646
use rustc_data_structures::fx::FxIndexSet;
4747
use rustc_data_structures::sorted_map::SortedMap;
@@ -52,7 +52,7 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
5252
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
5353
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
5454
use rustc_hir::definitions::PerParentDisambiguatorState;
55-
use rustc_hir::lints::{AttributeLint, DelayedLint};
55+
use rustc_hir::lints::{AttributeLint, DelayedLint, DynAttribute};
5656
use rustc_hir::{
5757
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
5858
LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr,
@@ -1174,13 +1174,23 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
11741174
target,
11751175
OmitDoc::Lower,
11761176
|s| l.lower(s),
1177-
|lint_id, span, kind| {
1178-
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
1179-
lint_id,
1180-
id: target_hir_id,
1181-
span,
1182-
kind,
1183-
}));
1177+
|lint_id, span, kind| match kind {
1178+
EmitAttribute::Static(attr_kind) => {
1179+
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
1180+
lint_id,
1181+
id: target_hir_id,
1182+
span,
1183+
kind: attr_kind,
1184+
}));
1185+
}
1186+
EmitAttribute::Dynamic(callback) => {
1187+
self.delayed_lints.push(DelayedLint::Dynamic(DynAttribute {
1188+
lint_id,
1189+
id: target_hir_id,
1190+
span,
1191+
callback,
1192+
}));
1193+
}
11841194
},
11851195
)
11861196
}

compiler/rustc_attr_parsing/src/attributes/doc.rs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit};
2-
use rustc_errors::msg;
2+
use rustc_errors::{Diagnostic, msg};
33
use rustc_feature::template;
44
use rustc_hir::Target;
55
use rustc_hir::attrs::{
@@ -171,12 +171,15 @@ impl DocParser {
171171

172172
if let Some(used_span) = self.attribute.no_crate_inject {
173173
let unused_span = path.span();
174-
cx.emit_lint(
174+
cx.emit_dyn_lint(
175175
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
176-
AttributeLintKind::UnusedDuplicate {
177-
this: unused_span,
178-
other: used_span,
179-
warning: true,
176+
move |dcx, level| {
177+
rustc_errors::lints::UnusedDuplicate {
178+
this: unused_span,
179+
other: used_span,
180+
warning: true,
181+
}
182+
.into_diag(dcx, level)
180183
},
181184
unused_span,
182185
);

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ use std::sync::LazyLock;
77

88
use private::Sealed;
99
use rustc_ast::{AttrStyle, MetaItemLit, NodeId};
10-
use rustc_errors::{Diag, Diagnostic, Level, MultiSpan};
10+
use rustc_data_structures::sync::{DynSend, DynSync};
11+
use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, MultiSpan};
1112
use rustc_feature::{AttrSuggestionStyle, AttributeTemplate};
1213
use rustc_hir::attrs::AttributeKind;
1314
use rustc_hir::lints::AttributeLintKind;
@@ -17,7 +18,6 @@ use rustc_session::Session;
1718
use rustc_session::lint::{Lint, LintId};
1819
use rustc_span::{ErrorGuaranteed, Span, Symbol};
1920

20-
use crate::AttributeParser;
2121
// Glob imports to avoid big, bitrotty import lists
2222
use crate::attributes::allow_unstable::*;
2323
use crate::attributes::autodiff::*;
@@ -66,6 +66,7 @@ use crate::session_diagnostics::{
6666
ParsedDescription,
6767
};
6868
use crate::target_checking::AllowedTargets;
69+
use crate::{AttributeParser, EmitAttribute};
6970
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
7071

7172
pub(super) struct GroupTypeInner<S: Stage> {
@@ -461,11 +462,34 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
461462
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
462463
/// must be delayed until after HIR is built. This method will take care of the details of
463464
/// that.
464-
pub(crate) fn emit_lint<M: Into<MultiSpan>>(
465+
pub(crate) fn emit_lint(
465466
&mut self,
466467
lint: &'static Lint,
467468
kind: AttributeLintKind,
468-
span: M,
469+
span: impl Into<MultiSpan>,
470+
) {
471+
self.emit_lint_inner(lint, EmitAttribute::Static(kind), span);
472+
}
473+
474+
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
475+
/// must be delayed until after HIR is built. This method will take care of the details of
476+
/// that.
477+
pub(crate) fn emit_dyn_lint<
478+
F: for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
479+
>(
480+
&mut self,
481+
lint: &'static Lint,
482+
callback: F,
483+
span: impl Into<MultiSpan>,
484+
) {
485+
self.emit_lint_inner(lint, EmitAttribute::Dynamic(Box::new(callback)), span);
486+
}
487+
488+
fn emit_lint_inner(
489+
&mut self,
490+
lint: &'static Lint,
491+
kind: EmitAttribute,
492+
span: impl Into<MultiSpan>,
469493
) {
470494
if !matches!(
471495
self.stage.should_emit(),
@@ -477,12 +501,15 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
477501
}
478502

479503
pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
480-
self.emit_lint(
504+
self.emit_dyn_lint(
481505
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
482-
AttributeLintKind::UnusedDuplicate {
483-
this: unused_span,
484-
other: used_span,
485-
warning: false,
506+
move |dcx, level| {
507+
rustc_errors::lints::UnusedDuplicate {
508+
this: unused_span,
509+
other: used_span,
510+
warning: false,
511+
}
512+
.into_diag(dcx, level)
486513
},
487514
unused_span,
488515
)
@@ -493,12 +520,15 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
493520
used_span: Span,
494521
unused_span: Span,
495522
) {
496-
self.emit_lint(
523+
self.emit_dyn_lint(
497524
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
498-
AttributeLintKind::UnusedDuplicate {
499-
this: unused_span,
500-
other: used_span,
501-
warning: true,
525+
move |dcx, level| {
526+
rustc_errors::lints::UnusedDuplicate {
527+
this: unused_span,
528+
other: used_span,
529+
warning: true,
530+
}
531+
.into_diag(dcx, level)
502532
},
503533
unused_span,
504534
)
@@ -569,7 +599,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
569599

570600
/// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S`
571601
/// is `Late` and is the ID of the syntactical component this attribute was applied to.
572-
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, AttributeLintKind),
602+
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, MultiSpan, EmitAttribute),
573603
}
574604

575605
/// Context given to every attribute parser during finalization.

compiler/rustc_attr_parsing/src/errors.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,12 @@ pub(crate) struct MustBeNameOfAssociatedFunction {
5757
#[primary_span]
5858
pub span: Span,
5959
}
60+
61+
#[derive(Diagnostic)]
62+
#[diag("unsafe attribute used without unsafe")]
63+
pub(crate) struct UnsafeAttrOutsideUnsafeLint {
64+
#[label("usage of unsafe attribute")]
65+
pub span: Span,
66+
#[subdiagnostic]
67+
pub suggestion: Option<crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion>,
68+
}

compiler/rustc_attr_parsing/src/interface.rs

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use std::convert::identity;
33
use rustc_ast as ast;
44
use rustc_ast::token::DocFragmentKind;
55
use rustc_ast::{AttrItemKind, AttrStyle, NodeId, Safety};
6-
use rustc_errors::{DiagCtxtHandle, MultiSpan};
6+
use rustc_data_structures::sync::{DynSend, DynSync};
7+
use rustc_errors::{Diag, DiagCtxtHandle, Level, MultiSpan};
78
use rustc_feature::{AttributeTemplate, Features};
89
use rustc_hir::attrs::AttributeKind;
910
use rustc_hir::lints::AttributeLintKind;
@@ -19,6 +20,15 @@ use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser};
1920
use crate::session_diagnostics::ParsedDescription;
2021
use crate::{Early, Late, OmitDoc, ShouldEmit};
2122

23+
pub enum EmitAttribute {
24+
Static(AttributeLintKind),
25+
Dynamic(
26+
Box<
27+
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
28+
>,
29+
),
30+
}
31+
2232
/// Context created once, for example as part of the ast lowering
2333
/// context, through which all attributes can be lowered.
2434
pub struct AttributeParser<'sess, S: Stage = Late> {
@@ -119,7 +129,14 @@ impl<'sess> AttributeParser<'sess, Early> {
119129
target,
120130
OmitDoc::Skip,
121131
std::convert::identity,
122-
|lint_id, span, kind| sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind),
132+
|lint_id, span, kind| match kind {
133+
EmitAttribute::Static(kind) => {
134+
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
135+
}
136+
EmitAttribute::Dynamic(callback) => {
137+
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
138+
}
139+
},
123140
)
124141
}
125142

@@ -199,8 +216,13 @@ impl<'sess> AttributeParser<'sess, Early> {
199216
sess,
200217
stage: Early { emit_errors },
201218
};
202-
let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: AttributeLintKind| {
203-
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
219+
let mut emit_lint = |lint_id: LintId, span: MultiSpan, kind: EmitAttribute| match kind {
220+
EmitAttribute::Static(kind) => {
221+
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
222+
}
223+
EmitAttribute::Dynamic(callback) => {
224+
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
225+
}
204226
};
205227
if let Some(safety) = attr_safety {
206228
parser.check_attribute_safety(
@@ -209,7 +231,7 @@ impl<'sess> AttributeParser<'sess, Early> {
209231
safety,
210232
expected_safety,
211233
&mut emit_lint,
212-
)
234+
);
213235
}
214236
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
215237
shared: SharedContext {
@@ -266,7 +288,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
266288
target: Target,
267289
omit_doc: OmitDoc,
268290
lower_span: impl Copy + Fn(Span) -> Span,
269-
mut emit_lint: impl FnMut(LintId, MultiSpan, AttributeLintKind),
291+
mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute),
270292
) -> Vec<Attribute> {
271293
let mut attributes = Vec::new();
272294
// We store the attributes we intend to discard at the end of this function in order to

compiler/rustc_attr_parsing/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,5 +113,5 @@ pub use attributes::cfg::{
113113
pub use attributes::cfg_select::*;
114114
pub use attributes::util::{is_builtin_attr, parse_version};
115115
pub use context::{Early, Late, OmitDoc, ShouldEmit};
116-
pub use interface::AttributeParser;
116+
pub use interface::{AttributeParser, EmitAttribute};
117117
pub use session_diagnostics::ParsedDescription;

compiler/rustc_attr_parsing/src/safety.rs

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use rustc_ast::Safety;
2-
use rustc_errors::MultiSpan;
2+
use rustc_errors::{Diagnostic, MultiSpan};
33
use rustc_hir::AttrPath;
4-
use rustc_hir::lints::AttributeLintKind;
54
use rustc_session::lint::LintId;
65
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
76
use rustc_span::Span;
87

98
use crate::attributes::AttributeSafety;
109
use crate::context::Stage;
11-
use crate::{AttributeParser, ShouldEmit};
10+
use crate::{AttributeParser, EmitAttribute, ShouldEmit, errors};
1211

1312
impl<'sess, S: Stage> AttributeParser<'sess, S> {
1413
pub fn check_attribute_safety(
@@ -17,7 +16,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
1716
attr_span: Span,
1817
attr_safety: Safety,
1918
expected_safety: AttributeSafety,
20-
emit_lint: &mut impl FnMut(LintId, MultiSpan, AttributeLintKind),
19+
emit_lint: &mut impl FnMut(LintId, MultiSpan, EmitAttribute),
2120
) {
2221
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
2322
return;
@@ -80,11 +79,17 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
8079
emit_lint(
8180
LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
8281
path_span.into(),
83-
AttributeLintKind::UnsafeAttrOutsideUnsafe {
84-
attribute_name_span: path_span,
85-
sugg_spans: not_from_proc_macro
86-
.then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi())),
87-
},
82+
EmitAttribute::Dynamic(Box::new(move |dcx, level| {
83+
errors::UnsafeAttrOutsideUnsafeLint {
84+
span: path_span,
85+
suggestion: not_from_proc_macro
86+
.then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()))
87+
.map(|(left, right)| {
88+
crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { left, right }
89+
}),
90+
}
91+
.into_diag(dcx, level)
92+
})),
8893
)
8994
}
9095
}

compiler/rustc_errors/src/diagnostic.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::panic;
77
use std::path::PathBuf;
88
use std::thread::panicking;
99

10+
use rustc_data_structures::sync::{DynSend, DynSync};
1011
use rustc_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg};
1112
use rustc_lint_defs::{Applicability, LintExpectationId};
1213
use rustc_macros::{Decodable, Encodable};
@@ -118,6 +119,28 @@ where
118119
}
119120
}
120121

122+
impl<'a> Diagnostic<'a, ()>
123+
for Box<
124+
dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSync + DynSend + 'static,
125+
>
126+
{
127+
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
128+
self(dcx, level)
129+
}
130+
}
131+
132+
pub struct DiagCallback<'a>(
133+
pub &'a Box<
134+
dyn for<'b> Fn(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSend + DynSync + 'static,
135+
>,
136+
);
137+
138+
impl<'a, 'b> Diagnostic<'a, ()> for DiagCallback<'b> {
139+
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
140+
(self.0)(dcx, level)
141+
}
142+
}
143+
121144
/// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait.
122145
pub struct DiagDecorator<F: FnOnce(&mut Diag<'_, ()>)>(pub F);
123146

compiler/rustc_errors/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ pub use anstyle::{
3636
pub use codes::*;
3737
pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer};
3838
pub use diagnostic::{
39-
BugAbort, Diag, DiagDecorator, DiagInner, DiagLocation, DiagStyledString, Diagnostic,
40-
EmissionGuarantee, FatalAbort, StringPart, Subdiag, Subdiagnostic,
39+
BugAbort, Diag, DiagCallback, DiagDecorator, DiagInner, DiagLocation, DiagStyledString,
40+
Diagnostic, EmissionGuarantee, FatalAbort, StringPart, Subdiag, Subdiagnostic,
4141
};
4242
pub use diagnostic_impls::{
4343
DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter,
@@ -77,6 +77,7 @@ mod diagnostic_impls;
7777
pub mod emitter;
7878
pub mod formatting;
7979
pub mod json;
80+
pub mod lints;
8081
mod lock;
8182
pub mod markdown;
8283
pub mod timings;

0 commit comments

Comments
 (0)