Skip to content

Commit 6568db4

Browse files
committed
port #[allow] to attribute parser
1 parent 6efa357 commit 6568db4

22 files changed

Lines changed: 614 additions & 170 deletions

File tree

Cargo.lock

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3545,6 +3545,7 @@ dependencies = [
35453545
"rustc_hir",
35463546
"rustc_lexer",
35473547
"rustc_macros",
3548+
"rustc_middle",
35483549
"rustc_parse",
35493550
"rustc_session",
35503551
"rustc_span",

compiler/rustc_ast_lowering/src/delegation.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
297297
DUMMY_NODE_ID,
298298
Some(self.tcx.features()),
299299
ShouldEmit::Nothing,
300+
None,
300301
));
301302
}
302303
}

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ struct LoweringContext<'a, 'hir> {
151151

152152
impl<'a, 'hir> LoweringContext<'a, 'hir> {
153153
fn new(tcx: TyCtxt<'hir>, resolver: &'a mut ResolverAstLowering) -> Self {
154-
let registered_tools = tcx.registered_tools(()).iter().map(|x| x.name).collect();
154+
let registered_tools = tcx.registered_tools(());
155155
Self {
156156
// Pseudo-globals.
157157
tcx,
@@ -205,7 +205,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
205205
attribute_parser: AttributeParser::new(
206206
tcx.sess,
207207
tcx.features(),
208-
registered_tools,
208+
registered_tools.clone(),
209209
Late,
210210
),
211211
delayed_lints: Vec::new(),

compiler/rustc_attr_parsing/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ rustc_feature = { path = "../rustc_feature" }
1414
rustc_hir = { path = "../rustc_hir" }
1515
rustc_lexer = { path = "../rustc_lexer" }
1616
rustc_macros = { path = "../rustc_macros" }
17+
rustc_middle = {path = "../rustc_middle"}
1718
rustc_parse = { path = "../rustc_parse" }
1819
rustc_session = { path = "../rustc_session" }
1920
rustc_span = { path = "../rustc_span" }

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
262262
// conditional compilation
263263
sym::cfg_trace,
264264
sym::cfg_attr_trace,
265+
sym::cfg,
265266
// testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`)
266267
sym::test,
267268
sym::ignore,
@@ -294,10 +295,11 @@ impl<S: Stage> AttributeParser<S> for NakedParser {
294295

295296
let span = self.span?;
296297

298+
let tools = cx.tools.iter().map(|tool| tool.name).collect::<Vec<_>>();
297299
// only if we found a naked attribute do we do the somewhat expensive check
298300
'outer: for other_attr in cx.all_attrs {
299301
for allowed_attr in ALLOW_LIST {
300-
if other_attr.segments().next().is_some_and(|i| cx.tools.contains(&i.name)) {
302+
if other_attr.segments().next().is_some_and(|i| tools.contains(&i.name)) {
301303
// effectively skips the error message being emitted below
302304
// if it's a tool attribute
303305
continue 'outer;
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
use std::sync::Arc;
2+
3+
use rustc_middle::ty::RegisteredTools;
4+
use rustc_middle::{bug};
5+
use rustc_session::DynLintStore;
6+
use rustc_session::lint::CheckLintNameResult;
7+
8+
use super::prelude::*;
9+
10+
#[derive(Default)]
11+
pub(crate) struct AllowParser {
12+
lint_ids: ThinVec<(Symbol, Span)>,
13+
reason: Option<Symbol>,
14+
errored: bool,
15+
}
16+
17+
// Needs to be manually impl:ed as `AttributeParser`, because otherwise deduplication occurs
18+
impl<S: Stage> AttributeParser<S> for AllowParser {
19+
const ATTRIBUTES: AcceptMapping<Self, S> = &[(
20+
&[sym::allow],
21+
template!(
22+
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
23+
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
24+
),
25+
|this, cx, args| {
26+
let Some(lint_store) = &cx.sess.lint_store else {
27+
bug!("lint_store required while parsing attributes");
28+
};
29+
30+
let Some(list) = args.list().map(MetaItemListParser::mixed) else {
31+
cx.expected_list(cx.inner_span, args);
32+
return;
33+
};
34+
35+
let mut list = list.peekable();
36+
37+
while let Some(item) = list.next() {
38+
let Some(meta_item) = item.meta_item() else {
39+
this.errored = true;
40+
return;
41+
};
42+
if let Some(args) = meta_item.word_is(sym::reason) {
43+
let ArgParser::NameValue(nv) = args else {
44+
// TODO: proper error
45+
this.errored = true;
46+
continue;
47+
};
48+
if list.peek().is_some() {
49+
// TODO: proper error
50+
this.errored = true;
51+
continue;
52+
}
53+
let Some(s) = nv.value_as_str() else {
54+
// TODO: proper error
55+
this.errored = true;
56+
continue;
57+
};
58+
this.reason = Some(s);
59+
} else {
60+
let mut segments = meta_item.path().segments();
61+
62+
let Some(tool_or_name) = segments.next() else {
63+
bug!("first segment should always exist");
64+
};
65+
66+
let rest = segments.collect::<Vec<_>>();
67+
let (tool, name): (Option<Symbol>, _) = if rest.is_empty() {
68+
let name = tool_or_name.name;
69+
(None, name.to_string())
70+
} else {
71+
let tool = tool_or_name;
72+
let name = rest
73+
.into_iter()
74+
.map(|ident| ident.to_string())
75+
.collect::<Vec<_>>()
76+
.join("::");
77+
(Some(tool.name), name)
78+
};
79+
80+
if let Some(ids) =
81+
check_lint(&name, tool, &cx.tools, lint_store, meta_item.span())
82+
{
83+
this.lint_ids.extend(ids);
84+
} else if tool.is_none() {
85+
dbg!(name, tool);
86+
for tool in cx.tools.iter() {
87+
dbg!(tool);
88+
}
89+
}
90+
}
91+
}
92+
},
93+
)];
94+
fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option<AttributeKind> {
95+
if !self.lint_ids.is_empty() && !self.errored {
96+
Some(AttributeKind::Allow { lint_ids: self.lint_ids, reason: self.reason })
97+
} else {
98+
None
99+
}
100+
}
101+
102+
const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
103+
}
104+
105+
fn check_lint(
106+
name: &str,
107+
tool: Option<Symbol>,
108+
tools: &RegisteredTools,
109+
lint_store: &Arc<dyn DynLintStore>,
110+
meta_item_span: Span,
111+
) -> Option<Vec<(Symbol, Span)>> {
112+
let mut lint_ids = Vec::new();
113+
match lint_store.check_lint_name(name, tool, tools) {
114+
CheckLintNameResult::Ok(ids) => {
115+
for id in ids {
116+
if id.to_string() == "unsafe_op_in_unsafe_fn" {
117+
//span_bug!(meta_item_span, "we found it");
118+
}
119+
lint_ids.push((Symbol::intern(&id.to_string()), meta_item_span));
120+
}
121+
}
122+
// TODO fix tools
123+
CheckLintNameResult::Tool(ids, new_lint_name) => {
124+
let _name = match new_lint_name {
125+
None => {
126+
let complete_name = &format!("{}::{}", tool.unwrap(), name);
127+
Symbol::intern(complete_name)
128+
}
129+
Some(new_lint_name) => {
130+
/*self.emit_span_lint(
131+
builtin::RENAMED_AND_REMOVED_LINTS,
132+
sp.into(),
133+
DeprecatedLintName {
134+
name,
135+
suggestion: sp,
136+
replace: &new_lint_name,
137+
},
138+
);*/
139+
Symbol::intern(&new_lint_name)
140+
}
141+
};
142+
for id in ids {
143+
144+
lint_ids.push((Symbol::intern(&id.to_string()), meta_item_span));
145+
}
146+
}
147+
148+
CheckLintNameResult::MissingTool => {
149+
// If `MissingTool` is returned, then either the lint does not
150+
// exist in the tool or the code was not compiled with the tool and
151+
// therefore the lint was never added to the `LintStore`. To detect
152+
// this is the responsibility of the lint tool.
153+
return None;
154+
}
155+
156+
CheckLintNameResult::NoTool => {
157+
/*self.dcx().emit_err(UnknownToolInScopedLint {
158+
span: tool_ident.map(|ident| ident.span),
159+
tool_name: tool_name.unwrap(),
160+
lint_name: pprust::path_to_string(&meta_item.path),
161+
is_nightly_build: sess.is_nightly_build(),
162+
});*/
163+
return None;
164+
}
165+
166+
CheckLintNameResult::Renamed(ref replace) => {
167+
/*if self.lint_added_lints {
168+
let suggestion =
169+
RenamedLintSuggestion::WithSpan { suggestion: sp, replace };
170+
let name =
171+
tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
172+
let lint = RenamedLint { name: name.as_str(), replace, suggestion };
173+
self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
174+
}*/
175+
176+
// If this lint was renamed, apply the new lint instead of ignoring the
177+
// attribute. Ignore any errors or warnings that happen because the new
178+
// name is inaccurate.
179+
// NOTE: `new_name` already includes the tool name, so we don't
180+
// have to add it again.
181+
let CheckLintNameResult::Ok(ids) = lint_store.check_lint_name(replace, None, tools)
182+
else {
183+
panic!("renamed lint does not exist: {replace}");
184+
};
185+
186+
for id in ids {
187+
let name = Symbol::intern(&id.to_string());
188+
lint_ids.push((name, meta_item_span));
189+
}
190+
}
191+
192+
CheckLintNameResult::Removed(ref _reason) => {
193+
/*if self.lint_added_lints {
194+
let name =
195+
tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
196+
let lint = RemovedLint { name: name.as_str(), reason };
197+
self.emit_span_lint(RENAMED_AND_REMOVED_LINTS, sp.into(), lint);
198+
}*/
199+
return None;
200+
}
201+
202+
CheckLintNameResult::NoLint(_suggestion) => {
203+
/*if self.lint_added_lints {
204+
let name =
205+
tool_ident.map(|tool| format!("{tool}::{name}")).unwrap_or(name);
206+
let suggestion = suggestion.map(|(replace, from_rustc)| {
207+
UnknownLintSuggestion::WithSpan {
208+
suggestion: sp,
209+
replace,
210+
from_rustc,
211+
}
212+
});
213+
let lint = UnknownLint { name, suggestion };
214+
self.emit_span_lint(UNKNOWN_LINTS, sp.into(), lint);
215+
}
216+
*/
217+
return None;
218+
}
219+
}
220+
Some(lint_ids)
221+
}

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ pub(crate) mod dummy;
4545
pub(crate) mod inline;
4646
pub(crate) mod instruction_set;
4747
pub(crate) mod link_attrs;
48+
pub(crate) mod lint;
4849
pub(crate) mod lint_helpers;
4950
pub(crate) mod loop_match;
5051
pub(crate) mod macro_attrs;

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use crate::attributes::dummy::*;
3232
use crate::attributes::inline::*;
3333
use crate::attributes::instruction_set::*;
3434
use crate::attributes::link_attrs::*;
35+
use crate::attributes::lint::*;
3536
use crate::attributes::lint_helpers::*;
3637
use crate::attributes::loop_match::*;
3738
use crate::attributes::macro_attrs::*;
@@ -141,6 +142,7 @@ attribute_parsers!(
141142
// tidy-alphabetical-start
142143
AlignParser,
143144
AlignStaticParser,
145+
AllowParser,
144146
BodyStabilityParser,
145147
ConfusablesParser,
146148
ConstStabilityParser,

compiler/rustc_attr_parsing/src/early_parsed.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ pub(crate) struct EarlyParsedState {
2323
cfg_attr_trace: bool,
2424
}
2525

26+
2627
impl EarlyParsedState {
2728
pub(crate) fn accept_early_parsed_attribute(
2829
&mut self,
@@ -39,6 +40,7 @@ impl EarlyParsedState {
3940
EarlyParsedAttribute::CfgAttrTrace => {
4041
self.cfg_attr_trace = true;
4142
}
43+
4244
}
4345
}
4446

compiler/rustc_attr_parsing/src/interface.rs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_feature::{AttributeTemplate, Features};
88
use rustc_hir::attrs::AttributeKind;
99
use rustc_hir::lints::AttributeLintKind;
1010
use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, Target};
11+
use rustc_middle::ty::RegisteredTools;
1112
use rustc_session::Session;
1213
use rustc_session::lint::{BuiltinLintDiag, LintId};
1314
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
@@ -21,7 +22,7 @@ use crate::{Early, Late, OmitDoc, ShouldEmit};
2122
/// Context created once, for example as part of the ast lowering
2223
/// context, through which all attributes can be lowered.
2324
pub struct AttributeParser<'sess, S: Stage = Late> {
24-
pub(crate) tools: Vec<Symbol>,
25+
pub(crate) tools: RegisteredTools,
2526
pub(crate) features: Option<&'sess Features>,
2627
pub(crate) sess: &'sess Session,
2728
pub(crate) stage: S,
@@ -86,6 +87,7 @@ impl<'sess> AttributeParser<'sess, Early> {
8687
target_node_id,
8788
features,
8889
should_emit,
90+
None,
8991
);
9092
assert!(parsed.len() <= 1);
9193
parsed.pop()
@@ -107,9 +109,15 @@ impl<'sess> AttributeParser<'sess, Early> {
107109
target_node_id: NodeId,
108110
features: Option<&'sess Features>,
109111
emit_errors: ShouldEmit,
112+
tools: Option<RegisteredTools>,
110113
) -> Vec<Attribute> {
111-
let mut p =
112-
Self { features, tools: Vec::new(), parse_only, sess, stage: Early { emit_errors } };
114+
let mut p = Self {
115+
features,
116+
tools: tools.unwrap_or_default(),
117+
parse_only,
118+
sess,
119+
stage: Early { emit_errors },
120+
};
113121
p.parse_attribute_list(
114122
attrs,
115123
target_span,
@@ -193,7 +201,7 @@ impl<'sess> AttributeParser<'sess, Early> {
193201
) -> T {
194202
let mut parser = Self {
195203
features,
196-
tools: Vec::new(),
204+
tools: RegisteredTools::default(),
197205
parse_only: None,
198206
sess,
199207
stage: Early { emit_errors },
@@ -231,7 +239,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
231239
pub fn new(
232240
sess: &'sess Session,
233241
features: &'sess Features,
234-
tools: Vec<Symbol>,
242+
tools: RegisteredTools,
235243
stage: S,
236244
) -> Self {
237245
Self { features: Some(features), tools, parse_only: None, sess, stage }

0 commit comments

Comments
 (0)