Skip to content

Commit d1fd617

Browse files
Set up API to make it possible to pass closures instead of AttributeLint.
The end goal being to completely remove `AttributeLint`.
1 parent 25a54d4 commit d1fd617

15 files changed

Lines changed: 135 additions & 63 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3995,6 +3995,7 @@ dependencies = [
39953995
"rustc_ast_pretty",
39963996
"rustc_data_structures",
39973997
"rustc_error_messages",
3998+
"rustc_errors",
39983999
"rustc_hashes",
39994000
"rustc_hir_id",
40004001
"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::AssocCtxt;
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::{DefPathData, DisambiguatorState};
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,
@@ -1183,13 +1183,23 @@ impl<'hir, R: ResolverAstLoweringExt<'hir>> LoweringContext<'_, 'hir, R> {
11831183
target,
11841184
OmitDoc::Lower,
11851185
|s| l.lower(s),
1186-
|lint_id, span, kind| {
1187-
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
1188-
lint_id,
1189-
id: target_hir_id,
1190-
span,
1191-
kind,
1192-
}));
1186+
|lint_id, span, kind| match kind {
1187+
EmitAttribute::Static(attr_kind) => {
1188+
self.delayed_lints.push(DelayedLint::AttributeParsing(AttributeLint {
1189+
lint_id,
1190+
id: target_hir_id,
1191+
span,
1192+
kind: attr_kind,
1193+
}));
1194+
}
1195+
EmitAttribute::Dynamic(callback) => {
1196+
self.delayed_lints.push(DelayedLint::Dynamic(DynAttribute {
1197+
lint_id,
1198+
id: target_hir_id,
1199+
span,
1200+
callback,
1201+
}));
1202+
}
11931203
},
11941204
)
11951205
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ use rustc_session::Session;
1717
use rustc_session::lint::{Lint, LintId};
1818
use rustc_span::{ErrorGuaranteed, Span, Symbol};
1919

20-
use crate::AttributeParser;
2120
// Glob imports to avoid big, bitrotty import lists
2221
use crate::attributes::allow_unstable::*;
2322
use crate::attributes::autodiff::*;
@@ -65,6 +64,7 @@ use crate::session_diagnostics::{
6564
ParsedDescription,
6665
};
6766
use crate::target_checking::AllowedTargets;
67+
use crate::{AttributeParser, EmitAttribute};
6868
type GroupType<S> = LazyLock<GroupTypeInner<S>>;
6969

7070
pub(super) struct GroupTypeInner<S: Stage> {
@@ -462,7 +462,7 @@ impl<'f, 'sess: 'f, S: Stage> SharedContext<'f, 'sess, S> {
462462
) {
463463
return;
464464
}
465-
(self.emit_lint)(LintId::of(lint), span, kind);
465+
(self.emit_lint)(LintId::of(lint), span, EmitAttribute::Static(kind));
466466
}
467467

468468
pub(crate) fn warn_unused_duplicate(&mut self, used_span: Span, unused_span: Span) {
@@ -528,7 +528,7 @@ pub struct SharedContext<'p, 'sess, S: Stage> {
528528

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

534534
/// 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: 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;
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> {
@@ -118,7 +128,14 @@ impl<'sess> AttributeParser<'sess, Early> {
118128
target,
119129
OmitDoc::Skip,
120130
std::convert::identity,
121-
|lint_id, span, kind| sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind),
131+
|lint_id, span, kind| match kind {
132+
EmitAttribute::Static(kind) => {
133+
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
134+
}
135+
EmitAttribute::Dynamic(callback) => {
136+
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
137+
}
138+
},
122139
)
123140
}
124141

@@ -195,11 +212,16 @@ impl<'sess> AttributeParser<'sess, Early> {
195212
sess,
196213
stage: Early { emit_errors },
197214
};
198-
let mut emit_lint = |lint_id: LintId, span: Span, kind: AttributeLintKind| {
199-
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
215+
let mut emit_lint = |lint_id: LintId, span: Span, kind: EmitAttribute| match kind {
216+
EmitAttribute::Static(kind) => {
217+
sess.psess.buffer_lint(lint_id.lint, span, target_node_id, kind)
218+
}
219+
EmitAttribute::Dynamic(callback) => {
220+
sess.psess.dyn_buffer_lint(lint_id.lint, span, target_node_id, callback)
221+
}
200222
};
201223
if let Some(safety) = attr_safety {
202-
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint)
224+
parser.check_attribute_safety(&attr_path, inner_span, safety, &mut emit_lint);
203225
}
204226
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
205227
shared: SharedContext {
@@ -256,7 +278,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
256278
target: Target,
257279
omit_doc: OmitDoc,
258280
lower_span: impl Copy + Fn(Span) -> Span,
259-
mut emit_lint: impl FnMut(LintId, Span, AttributeLintKind),
281+
mut emit_lint: impl FnMut(LintId, Span, EmitAttribute),
260282
) -> Vec<Attribute> {
261283
let mut attributes = Vec::new();
262284
// 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: 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: 2 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,

compiler/rustc_hir/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ rustc_ast = { path = "../rustc_ast" }
1313
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
1414
rustc_data_structures = { path = "../rustc_data_structures" }
1515
rustc_error_messages = { path = "../rustc_error_messages" }
16+
rustc_errors = { path = "../rustc_errors" }
1617
rustc_hashes = { path = "../rustc_hashes" }
1718
rustc_hir_id = { path = "../rustc_hir_id" }
1819
rustc_index = { path = "../rustc_index" }

0 commit comments

Comments
 (0)