Skip to content

Commit 8dcd0b9

Browse files
committed
Auto merge of #154432 - GuillaumeGomez:try-rm-AttributeLint, r=<try>
Set up API to make it possible to pass closures instead of `AttributeLint`
2 parents 23903d0 + 5bbb314 commit 8dcd0b9

File tree

17 files changed

+193
-110
lines changed

17 files changed

+193
-110
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3994,6 +3994,7 @@ dependencies = [
39943994
"rustc_ast_pretty",
39953995
"rustc_data_structures",
39963996
"rustc_error_messages",
3997+
"rustc_errors",
39973998
"rustc_hashes",
39983999
"rustc_hir_id",
39994000
"rustc_index",

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use std::sync::Arc;
4040

4141
use rustc_ast::node_id::NodeMap;
4242
use rustc_ast::{self as ast, *};
43-
use rustc_attr_parsing::{AttributeParser, Late, OmitDoc};
43+
use rustc_attr_parsing::{AttributeParser, EmitAttribute, Late, OmitDoc};
4444
use rustc_data_structures::fingerprint::Fingerprint;
4545
use rustc_data_structures::fx::FxIndexSet;
4646
use rustc_data_structures::sorted_map::SortedMap;
@@ -51,7 +51,7 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle};
5151
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
5252
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId};
5353
use rustc_hir::definitions::{DefPathData, DisambiguatorState};
54-
use rustc_hir::lints::{AttributeLint, DelayedLint};
54+
use rustc_hir::lints::{AttributeLint, DelayedLint, DynAttribute};
5555
use rustc_hir::{
5656
self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource,
5757
LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr,
@@ -1166,13 +1166,23 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
11661166
target,
11671167
OmitDoc::Lower,
11681168
|s| l.lower(s),
1169-
|lint_id, span, kind| {
1170-
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
1171-
lint_id,
1172-
id: target_hir_id,
1173-
span,
1174-
kind,
1175-
}));
1169+
|lint_id, span, kind| match kind {
1170+
EmitAttribute::Static(attr_kind) => {
1171+
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
1172+
lint_id,
1173+
id: target_hir_id,
1174+
span,
1175+
kind: attr_kind,
1176+
}));
1177+
}
1178+
EmitAttribute::Dynamic(callback) => {
1179+
self.delayed_lints.push(DelayedLint::Dynamic(DynAttribute {
1180+
lint_id,
1181+
id: target_hir_id,
1182+
span,
1183+
callback,
1184+
}));
1185+
}
11761186
},
11771187
)
11781188
}

compiler/rustc_attr_parsing/src/attributes/doc.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_ast::ast::{AttrStyle, LitKind, MetaItemLit};
2+
use rustc_errors::Diagnostic;
23
use rustc_feature::template;
34
use rustc_hir::Target;
45
use rustc_hir::attrs::{
@@ -169,12 +170,15 @@ impl DocParser {
169170

170171
if let Some(used_span) = self.attribute.no_crate_inject {
171172
let unused_span = path.span();
172-
cx.emit_lint(
173+
cx.emit_dyn_lint(
173174
rustc_session::lint::builtin::INVALID_DOC_ATTRIBUTES,
174-
AttributeLintKind::UnusedDuplicate {
175-
this: unused_span,
176-
other: used_span,
177-
warning: true,
175+
move |dcx, level| {
176+
rustc_errors::lints::UnusedDuplicate {
177+
this: unused_span,
178+
other: used_span,
179+
warning: true,
180+
}
181+
.into_diag(dcx, level)
178182
},
179183
unused_span,
180184
);

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use std::sync::LazyLock;
66

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

19-
use crate::AttributeParser;
2020
// Glob imports to avoid big, bitrotty import lists
2121
use crate::attributes::allow_unstable::*;
2222
use crate::attributes::autodiff::*;
@@ -63,6 +63,7 @@ use crate::session_diagnostics::{
6363
AttributeParseError, AttributeParseErrorReason, ParsedDescription,
6464
};
6565
use crate::target_checking::AllowedTargets;
66+
use crate::{AttributeParser, EmitAttribute};
6667
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
6768

6869
pub(super) struct GroupTypeInner<S: Stage> {
@@ -448,6 +449,24 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
448449
/// must be delayed until after HIR is built. This method will take care of the details of
449450
/// that.
450451
pub(crate) fn emit_lint(&mut self, lint: &'static Lint, kind: AttributeLintKind, span: Span) {
452+
self.emit_lint_inner(lint, EmitAttribute::Static(kind), span);
453+
}
454+
455+
/// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing
456+
/// must be delayed until after HIR is built. This method will take care of the details of
457+
/// that.
458+
pub(crate) fn emit_dyn_lint<
459+
F: for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
460+
>(
461+
&mut self,
462+
lint: &'static Lint,
463+
callback: F,
464+
span: Span,
465+
) {
466+
self.emit_lint_inner(lint, EmitAttribute::Dynamic(Box::new(callback)), span);
467+
}
468+
469+
fn emit_lint_inner(&mut self, lint: &'static Lint, kind: EmitAttribute, span: Span) {
451470
if !matches!(
452471
self.stage.should_emit(),
453472
ShouldEmit::ErrorsAndLints { .. } | ShouldEmit::EarlyFatal { also_emit_lints: true }
@@ -458,12 +477,15 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
458477
}
459478

460479
pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
461-
self.emit_lint(
480+
self.emit_dyn_lint(
462481
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
463-
AttributeLintKind::UnusedDuplicate {
464-
this: unused_span,
465-
other: used_span,
466-
warning: false,
482+
move |dcx, level| {
483+
rustc_errors::lints::UnusedDuplicate {
484+
this: unused_span,
485+
other: used_span,
486+
warning: false,
487+
}
488+
.into_diag(dcx, level)
467489
},
468490
unused_span,
469491
)
@@ -474,12 +496,15 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
474496
used_span: Span,
475497
unused_span: Span,
476498
) {
477-
self.emit_lint(
499+
self.emit_dyn_lint(
478500
rustc_session::lint::builtin::UNUSED_ATTRIBUTES,
479-
AttributeLintKind::UnusedDuplicate {
480-
this: unused_span,
481-
other: used_span,
482-
warning: true,
501+
move |dcx, level| {
502+
rustc_errors::lints::UnusedDuplicate {
503+
this: unused_span,
504+
other: used_span,
505+
warning: true,
506+
}
507+
.into_diag(dcx, level)
483508
},
484509
unused_span,
485510
)
@@ -720,7 +745,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
720745

721746
/// The second argument of the closure is a [`NodeId`] if `S` is `Early` and a [`HirId`] if `S`
722747
/// is `Late` and is the ID of the syntactical component this attribute was applied to.
723-
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, Span, AttributeLintKind),
748+
pub(crate) emit_lint: &'p mut dyn FnMut(LintId, Span, EmitAttribute),
724749
}
725750

726751
/// 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
@@ -50,3 +50,12 @@ pub(crate) struct UnreachableCfgSelectPredicateWildcard {
5050
#[label("always matches")]
5151
pub wildcard_span: Span,
5252
}
53+
54+
#[derive(Diagnostic)]
55+
#[diag("unsafe attribute used without unsafe")]
56+
pub(crate) struct UnsafeAttrOutsideUnsafeLint {
57+
#[label("usage of unsafe attribute")]
58+
pub span: Span,
59+
#[subdiagnostic]
60+
pub suggestion: Option<crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion>,
61+
}

compiler/rustc_attr_parsing/src/interface.rs

Lines changed: 37 additions & 17 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;
6+
use rustc_data_structures::sync::{DynSend, DynSync};
7+
use rustc_errors::{Diag, DiagCtxtHandle, Level};
78
use rustc_feature::{AttributeTemplate, Features};
89
use rustc_hir::attrs::AttributeKind;
910
use rustc_hir::lints::AttributeLintKind;
@@ -18,6 +19,15 @@ use crate::parser::{AllowExprMetavar, ArgParser, PathParser, RefPathParser};
1819
use crate::session_diagnostics::ParsedDescription;
1920
use crate::{Early, Late, OmitDoc, ShouldEmit};
2021

22+
pub enum EmitAttribute {
23+
Static(AttributeLintKind),
24+
Dynamic(
25+
Box<
26+
dyn for<'a> Fn(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + DynSend + DynSync + 'static,
27+
>,
28+
),
29+
}
30+
2131
/// Context created once, for example as part of the ast lowering
2232
/// context, through which all attributes can be lowered.
2333
pub struct AttributeParser<'sess, S: Stage = Late> {
@@ -116,13 +126,18 @@ impl<'sess> AttributeParser<'sess, Early> {
116126
target,
117127
OmitDoc::Skip,
118128
std::convert::identity,
119-
|lint_id, span, kind| {
120-
sess.psess.buffer_lint(
121-
lint_id.lint,
122-
span,
123-
target_node_id,
124-
BuiltinLintDiag::AttributeLint(kind),
125-
)
129+
|lint_id, span, kind| match kind {
130+
EmitAttribute::Static(attr_kind) => {
131+
sess.psess.buffer_lint(
132+
lint_id.lint,
133+
span,
134+
target_node_id,
135+
BuiltinLintDiag::AttributeLint(attr_kind),
136+
);
137+
}
138+
EmitAttribute::Dynamic(callback) => {
139+
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback);
140+
}
126141
},
127142
)
128143
}
@@ -200,16 +215,21 @@ impl<'sess> AttributeParser<'sess, Early> {
200215
sess,
201216
stage: Early { emit_errors },
202217
};
203-
let mut emit_lint = |lint_id: LintId, span: Span, kind: AttributeLintKind| {
204-
sess.psess.buffer_lint(
205-
lint_id.lint,
206-
span,
207-
target_node_id,
208-
BuiltinLintDiag::AttributeLint(kind),
209-
)
218+
let mut emit_lint = |lint_id: LintId, span: Span, kind: EmitAttribute| match kind {
219+
EmitAttribute::Static(attr_kind) => {
220+
sess.psess.buffer_lint(
221+
lint_id.lint,
222+
span,
223+
target_node_id,
224+
BuiltinLintDiag::AttributeLint(attr_kind),
225+
);
226+
}
227+
EmitAttribute::Dynamic(callback) => {
228+
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback);
229+
}
210230
};
211231
if let Some(safety) = attr_safety {
212-
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
232+
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint);
213233
}
214234
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
215235
shared: SharedContext {
@@ -266,7 +286,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
266286
target: Target,
267287
omit_doc: OmitDoc,
268288
lower_span: impl Copy + Fn(Span) -> Span,
269-
mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind),
289+
mut emit_lint: impl FnMut(LintId, Span, EmitAttribute),
270290
) -> Vec<Attribute> {
271291
let mut attributes = Vec::new();
272292
// 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
@@ -112,5 +112,5 @@ pub use attributes::cfg::{
112112
pub use attributes::cfg_select::*;
113113
pub use attributes::util::{is_builtin_attr, parse_version};
114114
pub use context::{Early, Late, OmitDoc, ShouldEmit};
115-
pub use interface::AttributeParser;
115+
pub use interface::{AttributeParser, EmitAttribute};
116116
pub use session_diagnostics::ParsedDescription;

compiler/rustc_attr_parsing/src/safety.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
use rustc_ast::Safety;
2+
use rustc_errors::Diagnostic;
23
use rustc_feature::{AttributeSafety, BUILTIN_ATTRIBUTE_MAP};
34
use rustc_hir::AttrPath;
4-
use rustc_hir::lints::AttributeLintKind;
55
use rustc_session::lint::LintId;
66
use rustc_session::lint::builtin::UNSAFE_ATTR_OUTSIDE_UNSAFE;
77
use rustc_span::Span;
88

99
use crate::context::Stage;
10-
use crate::{AttributeParser, ShouldEmit};
10+
use crate::{AttributeParser, EmitAttribute, ShouldEmit, errors};
1111

1212
impl<'sess, S: Stage> AttributeParser<'sess, S> {
1313
pub fn check_attribute_safety(
1414
&mut self,
1515
attr_path: &AttrPath,
1616
attr_span: Span,
1717
attr_safety: Safety,
18-
emit_lint: &mut impl FnMut(LintId, Span, AttributeLintKind),
18+
emit_lint: &mut impl FnMut(LintId, Span, EmitAttribute),
1919
) {
2020
if matches!(self.stage.should_emit(), ShouldEmit::Nothing) {
2121
return;
@@ -84,11 +84,17 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
8484
emit_lint(
8585
LintId::of(UNSAFE_ATTR_OUTSIDE_UNSAFE),
8686
path_span,
87-
AttributeLintKind::UnsafeAttrOutsideUnsafe {
88-
attribute_name_span: path_span,
89-
sugg_spans: not_from_proc_macro
90-
.then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi())),
91-
},
87+
EmitAttribute::Dynamic(Box::new(move |dcx, level| {
88+
errors::UnsafeAttrOutsideUnsafeLint {
89+
span: path_span,
90+
suggestion: not_from_proc_macro
91+
.then(|| (diag_span.shrink_to_lo(), diag_span.shrink_to_hi()))
92+
.map(|(left, right)| {
93+
crate::session_diagnostics::UnsafeAttrOutsideUnsafeSuggestion { left, right }
94+
}),
95+
}
96+
.into_diag(dcx, level)
97+
})),
9298
)
9399
}
94100
}

compiler/rustc_errors/src/diagnostic.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,18 @@ impl<'a> Diagnostic<'a, ()>
129129
}
130130
}
131131

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+
132144
/// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait.
133145
pub struct DiagDecorator<F: FnOnce(&mut Diag<'_, ()>)>(pub F);
134146

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)