Skip to content

Commit f5703d5

Browse files
committed
Auto merge of #144689 - JonathanBrouwer:share_parse_path, r=jdonszelmann
Rewrite the new attribute argument parser Fixes #143940 This rewrites the parser, should improve performance and maintainability. This can be reviewed commit by commit
2 parents 831e291 + ec5b2cc commit f5703d5

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+665
-519
lines changed

Cargo.lock

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3459,7 +3459,6 @@ dependencies = [
34593459
"rustc_feature",
34603460
"rustc_fluent_macro",
34613461
"rustc_macros",
3462-
"rustc_parse",
34633462
"rustc_session",
34643463
"rustc_span",
34653464
"rustc_target",
@@ -3490,6 +3489,7 @@ dependencies = [
34903489
"rustc_hir",
34913490
"rustc_lexer",
34923491
"rustc_macros",
3492+
"rustc_parse",
34933493
"rustc_session",
34943494
"rustc_span",
34953495
"thin-vec",
@@ -4355,7 +4355,6 @@ dependencies = [
43554355
"rustc-literal-escaper",
43564356
"rustc_ast",
43574357
"rustc_ast_pretty",
4358-
"rustc_attr_parsing",
43594358
"rustc_data_structures",
43604359
"rustc_errors",
43614360
"rustc_feature",

compiler/rustc_ast_passes/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ rustc_errors = { path = "../rustc_errors" }
1515
rustc_feature = { path = "../rustc_feature" }
1616
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
1717
rustc_macros = { path = "../rustc_macros" }
18-
rustc_parse = { path = "../rustc_parse" }
1918
rustc_session = { path = "../rustc_session" }
2019
rustc_span = { path = "../rustc_span" }
2120
rustc_target = { path = "../rustc_target" }

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@ use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
2525
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
2626
use rustc_ast::*;
2727
use rustc_ast_pretty::pprust::{self, State};
28+
use rustc_attr_parsing::validate_attr;
2829
use rustc_data_structures::fx::FxIndexMap;
2930
use rustc_errors::DiagCtxtHandle;
3031
use rustc_feature::Features;
31-
use rustc_parse::validate_attr;
3232
use rustc_session::Session;
3333
use rustc_session::lint::builtin::{
3434
DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, MISSING_UNSAFE_ON_EXTERN,

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_fluent_macro = { path = "../rustc_fluent_macro" }
1414
rustc_hir = { path = "../rustc_hir" }
1515
rustc_lexer = { path = "../rustc_lexer" }
1616
rustc_macros = { path = "../rustc_macros" }
17+
rustc_parse = { path = "../rustc_parse" }
1718
rustc_session = { path = "../rustc_session" }
1819
rustc_span = { path = "../rustc_span" }
1920
thin-vec = "0.2.12"

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,22 @@ attr_parsing_unused_multiple =
170170
171171
-attr_parsing_previously_accepted =
172172
this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
173+
174+
attr_parsing_meta_bad_delim = wrong meta list delimiters
175+
attr_parsing_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
176+
177+
attr_parsing_unsafe_attr_outside_unsafe = unsafe attribute used without unsafe
178+
.label = usage of unsafe attribute
179+
attr_parsing_unsafe_attr_outside_unsafe_suggestion = wrap the attribute in `unsafe(...)`
180+
181+
attr_parsing_invalid_attr_unsafe = `{$name}` is not an unsafe attribute
182+
.label = this is not an unsafe attribute
183+
.suggestion = remove the `unsafe(...)`
184+
.note = extraneous unsafe is not allowed in attributes
185+
186+
attr_parsing_invalid_meta_item = expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found {$descr}
187+
.remove_neg_sugg = negative numbers are not literals, try removing the `-` sign
188+
.quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
189+
190+
attr_parsing_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
191+
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)

compiler/rustc_attr_parsing/src/interface.rs

Lines changed: 51 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::borrow::Cow;
2+
13
use rustc_ast as ast;
24
use rustc_ast::NodeId;
35
use rustc_errors::DiagCtxtHandle;
@@ -49,27 +51,44 @@ impl<'sess> AttributeParser<'sess, Early> {
4951
target_node_id: NodeId,
5052
features: Option<&'sess Features>,
5153
) -> Option<Attribute> {
52-
let mut p = Self {
53-
features,
54-
tools: Vec::new(),
55-
parse_only: Some(sym),
54+
let mut parsed = Self::parse_limited_all(
5655
sess,
57-
stage: Early { emit_errors: ShouldEmit::Nothing },
58-
};
59-
let mut parsed = p.parse_attribute_list(
6056
attrs,
57+
Some(sym),
58+
Target::Crate, // Does not matter, we're not going to emit errors anyways
6159
target_span,
6260
target_node_id,
63-
Target::Crate, // Does not matter, we're not going to emit errors anyways
61+
features,
62+
ShouldEmit::Nothing,
63+
);
64+
assert!(parsed.len() <= 1);
65+
parsed.pop()
66+
}
67+
68+
pub fn parse_limited_all(
69+
sess: &'sess Session,
70+
attrs: &[ast::Attribute],
71+
parse_only: Option<Symbol>,
72+
target: Target,
73+
target_span: Span,
74+
target_node_id: NodeId,
75+
features: Option<&'sess Features>,
76+
emit_errors: ShouldEmit,
77+
) -> Vec<Attribute> {
78+
let mut p =
79+
Self { features, tools: Vec::new(), parse_only, sess, stage: Early { emit_errors } };
80+
p.parse_attribute_list(
81+
attrs,
82+
target_span,
83+
target_node_id,
84+
target,
6485
OmitDoc::Skip,
6586
std::convert::identity,
6687
|_lint| {
67-
panic!("can't emit lints here for now (nothing uses this atm)");
88+
// FIXME: Can't emit lints here for now
89+
// This branch can be hit when an attribute produces a warning during early parsing (such as attributes on macro calls)
6890
},
69-
);
70-
assert!(parsed.len() <= 1);
71-
72-
parsed.pop()
91+
)
7392
}
7493

7594
pub fn parse_single<T>(
@@ -79,9 +98,9 @@ impl<'sess> AttributeParser<'sess, Early> {
7998
target_node_id: NodeId,
8099
features: Option<&'sess Features>,
81100
emit_errors: ShouldEmit,
82-
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> T,
101+
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser<'_>) -> Option<T>,
83102
template: &AttributeTemplate,
84-
) -> T {
103+
) -> Option<T> {
85104
let mut parser = Self {
86105
features,
87106
tools: Vec::new(),
@@ -92,7 +111,9 @@ impl<'sess> AttributeParser<'sess, Early> {
92111
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
93112
panic!("parse_single called on a doc attr")
94113
};
95-
let meta_parser = MetaItemParser::from_attr(normal_attr, parser.dcx());
114+
let parts =
115+
normal_attr.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
116+
let meta_parser = MetaItemParser::from_attr(normal_attr, &parts, &sess.psess, emit_errors)?;
96117
let path = meta_parser.path();
97118
let args = meta_parser.args();
98119
let mut cx: AcceptContext<'_, 'sess, Early> = AcceptContext {
@@ -199,14 +220,22 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
199220
// }))
200221
// }
201222
ast::AttrKind::Normal(n) => {
202-
attr_paths.push(PathParser::Ast(&n.item.path));
223+
attr_paths.push(PathParser(Cow::Borrowed(&n.item.path)));
203224

204-
let parser = MetaItemParser::from_attr(n, self.dcx());
205-
let path = parser.path();
206-
let args = parser.args();
207-
let path_parts = path.segments().map(|i| i.name).collect::<Vec<_>>();
225+
let parts =
226+
n.item.path.segments.iter().map(|seg| seg.ident.name).collect::<Vec<_>>();
208227

209-
if let Some(accepts) = S::parsers().accepters.get(path_parts.as_slice()) {
228+
if let Some(accepts) = S::parsers().accepters.get(parts.as_slice()) {
229+
let Some(parser) = MetaItemParser::from_attr(
230+
n,
231+
&parts,
232+
&self.sess.psess,
233+
self.stage.should_emit(),
234+
) else {
235+
continue;
236+
};
237+
let path = parser.path();
238+
let args = parser.args();
210239
for accept in accepts {
211240
let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext {
212241
shared: SharedContext {

compiler/rustc_attr_parsing/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ pub mod parser;
102102
mod lints;
103103
mod session_diagnostics;
104104
mod target_checking;
105+
pub mod validate_attr;
105106

106107
pub use attributes::cfg::{CFG_TEMPLATE, EvalConfigResult, eval_config_entry, parse_cfg_attr};
107108
pub use attributes::cfg_old::*;

0 commit comments

Comments
 (0)