Skip to content

Commit 99191c2

Browse files
committed
parse_meta: ditch parse_in_attr
1 parent cbc9f68 commit 99191c2

File tree

9 files changed

+99
-48
lines changed

9 files changed

+99
-48
lines changed

src/librustc_parse/config.rs

+4-21
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use syntax::ast::{self, Attribute, AttrItem, MetaItem};
1818
use syntax::edition::Edition;
1919
use syntax::mut_visit::*;
2020
use syntax::ptr::P;
21-
use syntax::tokenstream::DelimSpan;
2221
use syntax::sess::ParseSess;
2322
use syntax::util::map_in_place::MapInPlace;
2423
use syntax_pos::Span;
@@ -139,11 +138,10 @@ impl<'a> StripUnconfigured<'a> {
139138
}
140139

141140
fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
142-
match &attr.get_normal_item().args {
143-
ast::MacArgs::Delimited(dspan, delim, tts) if !tts.is_empty() => {
144-
if let ast::MacDelimiter::Brace | ast::MacDelimiter::Bracket = delim {
145-
self.error_malformed_cfg_attr_wrong_delim(*dspan);
146-
}
141+
match attr.get_normal_item().args {
142+
ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => {
143+
let msg = "wrong `cfg_attr` delimiters";
144+
validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg);
147145
match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
148146
Ok(r) => return Some(r),
149147
Err(mut e) => e
@@ -157,21 +155,6 @@ impl<'a> StripUnconfigured<'a> {
157155
None
158156
}
159157

160-
fn error_malformed_cfg_attr_wrong_delim(&self, dspan: DelimSpan) {
161-
self.sess
162-
.span_diagnostic
163-
.struct_span_err(dspan.entire(), "wrong `cfg_attr` delimiters")
164-
.multipart_suggestion(
165-
"the delimiters should be `(` and `)`",
166-
vec![
167-
(dspan.open, "(".to_string()),
168-
(dspan.close, ")".to_string()),
169-
],
170-
Applicability::MachineApplicable,
171-
)
172-
.emit();
173-
}
174-
175158
fn error_malformed_cfg_attr_missing(&self, span: Span) {
176159
self.sess
177160
.span_diagnostic

src/librustc_parse/lib.rs

-11
Original file line numberDiff line numberDiff line change
@@ -284,17 +284,6 @@ pub fn parse_in<'a, T>(
284284
Ok(result)
285285
}
286286

287-
/// Runs the given subparser `f` on the tokens of the given `attr`'s item.
288-
fn parse_in_attr<'a, T>(
289-
sess: &'a ParseSess,
290-
attr: &ast::Attribute,
291-
f: impl FnMut(&mut Parser<'a>) -> PResult<'a, T>,
292-
) -> PResult<'a, T> {
293-
// FIXME(#66940, Centril | petrochenkov): refactor this function so it doesn't
294-
// require reconstructing and immediately re-parsing delimiters.
295-
parse_in(sess, attr.get_normal_item().args.outer_tokens(), "attribute", f)
296-
}
297-
298287
// NOTE(Centril): The following probably shouldn't be here but it acknowledges the
299288
// fact that architecturally, we are using parsing (read on below to understand why).
300289

src/librustc_parse/parser/attr.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ impl<'a> Parser<'a> {
220220
Ok(attrs)
221221
}
222222

223-
pub(super) fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
223+
crate fn parse_unsuffixed_lit(&mut self) -> PResult<'a, ast::Lit> {
224224
let lit = self.parse_lit()?;
225225
debug!("checking if {:?} is unusuffixed", lit);
226226

@@ -247,12 +247,27 @@ impl<'a> Parser<'a> {
247247
let lo = self.token.span;
248248
let item = self.parse_attr_item()?;
249249
expanded_attrs.push((item, lo.to(self.prev_span)));
250-
self.eat(&token::Comma);
250+
if !self.eat(&token::Comma) {
251+
break;
252+
}
251253
}
252254

253255
Ok((cfg_predicate, expanded_attrs))
254256
}
255257

258+
/// Matches `COMMASEP(meta_item_inner)`.
259+
crate fn parse_meta_seq_top(&mut self) -> PResult<'a, Vec<ast::NestedMetaItem>> {
260+
// Presumably, the majority of the time there will only be one attr.
261+
let mut nmis = Vec::with_capacity(1);
262+
while self.token.kind != token::Eof {
263+
nmis.push(self.parse_meta_item_inner()?);
264+
if !self.eat(&token::Comma) {
265+
break;
266+
}
267+
}
268+
Ok(nmis)
269+
}
270+
256271
/// Matches the following grammar (per RFC 1559).
257272
///
258273
/// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;

src/librustc_parse/validate_attr.rs

+35-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
//! Meta-syntax validation logic of attributes for post-expansion.
22
3+
use crate::parse_in;
4+
35
use rustc_errors::{PResult, Applicability};
46
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
5-
use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MetaItem, MetaItemKind};
7+
use syntax::ast::{self, Attribute, AttrKind, Ident, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
68
use syntax::attr::mk_name_value_item_str;
79
use syntax::early_buffered_lints::ILL_FORMED_ATTRIBUTE_INPUT;
10+
use syntax::tokenstream::DelimSpan;
811
use syntax::sess::ParseSess;
912
use syntax_pos::{Symbol, sym};
1013

@@ -27,16 +30,45 @@ pub fn check_meta(sess: &ParseSess, attr: &Attribute) {
2730
pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, MetaItem> {
2831
Ok(match attr.kind {
2932
AttrKind::Normal(ref item) => MetaItem {
30-
path: item.path.clone(),
31-
kind: super::parse_in_attr(sess, attr, |p| p.parse_meta_item_kind())?,
3233
span: attr.span,
34+
path: item.path.clone(),
35+
kind: match &attr.get_normal_item().args {
36+
MacArgs::Empty => MetaItemKind::Word,
37+
MacArgs::Eq(_, t) => {
38+
let v = parse_in(sess, t.clone(), "name value", |p| p.parse_unsuffixed_lit())?;
39+
MetaItemKind::NameValue(v)
40+
}
41+
MacArgs::Delimited(dspan, delim, t) => {
42+
check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters");
43+
let nmis = parse_in(sess, t.clone(), "meta list", |p| p.parse_meta_seq_top())?;
44+
MetaItemKind::List(nmis)
45+
}
46+
}
3347
},
3448
AttrKind::DocComment(comment) => {
3549
mk_name_value_item_str(Ident::new(sym::doc, attr.span), comment, attr.span)
3650
}
3751
})
3852
}
3953

54+
crate fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) {
55+
if let ast::MacDelimiter::Parenthesis = delim {
56+
return;
57+
}
58+
59+
sess.span_diagnostic
60+
.struct_span_err(span.entire(), msg)
61+
.multipart_suggestion(
62+
"the delimiters should be `(` and `)`",
63+
vec![
64+
(span.open, "(".to_string()),
65+
(span.close, ")".to_string()),
66+
],
67+
Applicability::MachineApplicable,
68+
)
69+
.emit();
70+
}
71+
4072
/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
4173
fn is_attr_template_compatible(template: &AttributeTemplate, meta: &ast::MetaItemKind) -> bool {
4274
match meta {

src/libsyntax_expand/proc_macro.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,14 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>)
188188
Some(x) => x,
189189
};
190190

191-
let mut retain_in_fm = true;
192-
let mut retain_in_map = true;
191+
let mut error_reported_filter_map = false;
192+
let mut error_reported_map = false;
193193
let traits = nmis
194194
.into_iter()
195195
// 2) Moreover, let's ensure we have a path and not `#[derive("foo")]`.
196196
.filter_map(|nmi| match nmi {
197197
NestedMetaItem::Literal(lit) => {
198-
retain_in_fm = false;
198+
error_reported_filter_map = true;
199199
cx.struct_span_err(lit.span, "expected path to a trait, found literal")
200200
.help("for example, write `#[derive(Debug)]` for `Debug`")
201201
.emit();
@@ -209,7 +209,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>)
209209
// wanted this trait to be derived, so let's keep it.
210210
.map(|mi| {
211211
let mut traits_dont_accept = |title, action| {
212-
retain_in_map = false;
212+
error_reported_map = true;
213213
let sp = mi.span.with_lo(mi.path.span.hi());
214214
cx.struct_span_err(sp, title)
215215
.span_suggestion(
@@ -235,7 +235,7 @@ crate fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec<ast::Attribute>)
235235
});
236236

237237
result.extend(traits);
238-
retain_in_fm && retain_in_map
238+
!error_reported_filter_map && !error_reported_map
239239
});
240240
result
241241
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
fn main() {}
2+
3+
#[allow { foo_lint } ]
4+
//~^ ERROR wrong meta list delimiters
5+
//~| HELP the delimiters should be `(` and `)`
6+
fn delim_brace() {}
7+
8+
#[allow [ foo_lint ] ]
9+
//~^ ERROR wrong meta list delimiters
10+
//~| HELP the delimiters should be `(` and `)`
11+
fn delim_bracket() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
error: wrong meta list delimiters
2+
--> $DIR/malformed-meta-delim.rs:3:9
3+
|
4+
LL | #[allow { foo_lint } ]
5+
| ^^^^^^^^^^^^
6+
|
7+
help: the delimiters should be `(` and `)`
8+
|
9+
LL | #[allow ( foo_lint ) ]
10+
| ^ ^
11+
12+
error: wrong meta list delimiters
13+
--> $DIR/malformed-meta-delim.rs:8:9
14+
|
15+
LL | #[allow [ foo_lint ] ]
16+
| ^^^^^^^^^^^^
17+
|
18+
help: the delimiters should be `(` and `)`
19+
|
20+
LL | #[allow ( foo_lint ) ]
21+
| ^ ^
22+
23+
error: aborting due to 2 previous errors
24+

src/test/ui/on-unimplemented/expected-comma-found-token.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
#[rustc_on_unimplemented(
88
message="the message"
9-
label="the label" //~ ERROR expected one of `)` or `,`, found `label`
9+
label="the label" //~ ERROR expected `,`, found `label`
1010
)]
1111
trait T {}
1212

src/test/ui/on-unimplemented/expected-comma-found-token.stderr

+2-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
1-
error: expected one of `)` or `,`, found `label`
1+
error: expected `,`, found `label`
22
--> $DIR/expected-comma-found-token.rs:9:5
33
|
44
LL | message="the message"
5-
| -
6-
| |
7-
| expected one of `)` or `,`
8-
| help: missing `,`
5+
| - expected `,`
96
LL | label="the label"
107
| ^^^^^ unexpected token
118

0 commit comments

Comments
 (0)