Skip to content

Commit 64130fd

Browse files
authored
Rollup merge of rust-lang#63674 - petrochenkov:meta2, r=Centril
syntax: Support modern attribute syntax in the `meta` matcher Where "modern" means rust-lang#57367: ``` PATH PATH `(` TOKEN_STREAM `)` PATH `[` TOKEN_STREAM `]` PATH `{` TOKEN_STREAM `}` ``` Unfortunately, `meta` wasn't future-proofed using the `FOLLOW` token set like other matchers (rust-lang#34011), so code like `$meta:meta {` or `$meta:meta [` may break, and we need a crater run to find out how often this happens in practice. Closes rust-lang#49629 (by fully supporting `meta` rather than removing it.)
2 parents 42ec683 + 6ea4a52 commit 64130fd

16 files changed

+119
-83
lines changed

src/librustc/hir/lowering.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -988,10 +988,12 @@ impl<'a> LoweringContext<'a> {
988988
// lower attributes (we use the AST version) there is nowhere to keep
989989
// the `HirId`s. We don't actually need HIR version of attributes anyway.
990990
Attribute {
991+
item: AttrItem {
992+
path: attr.path.clone(),
993+
tokens: self.lower_token_stream(attr.tokens.clone()),
994+
},
991995
id: attr.id,
992996
style: attr.style,
993-
path: attr.path.clone(),
994-
tokens: self.lower_token_stream(attr.tokens.clone()),
995997
is_sugared_doc: attr.is_sugared_doc,
996998
span: attr.span,
997999
}

src/librustc/ich/impls_syntax.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -196,26 +196,27 @@ impl<'a> HashStable<StableHashingContext<'a>> for ast::Path {
196196
}
197197
}
198198

199+
impl_stable_hash_for!(struct ::syntax::ast::AttrItem {
200+
path,
201+
tokens,
202+
});
203+
199204
impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute {
200205
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
201206
// Make sure that these have been filtered out.
202207
debug_assert!(!self.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)));
203208
debug_assert!(!self.is_sugared_doc);
204209

205210
let ast::Attribute {
211+
ref item,
206212
id: _,
207213
style,
208-
ref path,
209-
ref tokens,
210214
is_sugared_doc: _,
211215
span,
212216
} = *self;
213217

218+
item.hash_stable(hcx, hasher);
214219
style.hash_stable(hcx, hasher);
215-
path.hash_stable(hcx, hasher);
216-
for tt in tokens.trees() {
217-
tt.hash_stable(hcx, hasher);
218-
}
219220
span.hash_stable(hcx, hasher);
220221
}
221222
}

src/libsyntax/ast.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -2139,18 +2139,29 @@ impl rustc_serialize::Decodable for AttrId {
21392139
}
21402140
}
21412141

2142+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
2143+
pub struct AttrItem {
2144+
pub path: Path,
2145+
pub tokens: TokenStream,
2146+
}
2147+
21422148
/// Metadata associated with an item.
21432149
/// Doc-comments are promoted to attributes that have `is_sugared_doc = true`.
21442150
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
21452151
pub struct Attribute {
2152+
pub item: AttrItem,
21462153
pub id: AttrId,
21472154
pub style: AttrStyle,
2148-
pub path: Path,
2149-
pub tokens: TokenStream,
21502155
pub is_sugared_doc: bool,
21512156
pub span: Span,
21522157
}
21532158

2159+
// Compatibility impl to avoid churn, consider removing.
2160+
impl std::ops::Deref for Attribute {
2161+
type Target = AttrItem;
2162+
fn deref(&self) -> &Self::Target { &self.item }
2163+
}
2164+
21542165
/// `TraitRef`s appear in impls.
21552166
///
21562167
/// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all

src/libsyntax/attr/mod.rs

+18-12
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub use StabilityLevel::*;
99
pub use crate::ast::Attribute;
1010

1111
use crate::ast;
12-
use crate::ast::{AttrId, AttrStyle, Name, Ident, Path, PathSegment};
12+
use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment};
1313
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
1414
use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
1515
use crate::mut_visit::visit_clobber;
@@ -255,9 +255,8 @@ impl MetaItem {
255255
}
256256
}
257257

258-
impl Attribute {
259-
/// Extracts the `MetaItem` from inside this `Attribute`.
260-
pub fn meta(&self) -> Option<MetaItem> {
258+
impl AttrItem {
259+
crate fn meta(&self, span: Span) -> Option<MetaItem> {
261260
let mut tokens = self.tokens.trees().peekable();
262261
Some(MetaItem {
263262
path: self.path.clone(),
@@ -269,9 +268,16 @@ impl Attribute {
269268
} else {
270269
return None;
271270
},
272-
span: self.span,
271+
span,
273272
})
274273
}
274+
}
275+
276+
impl Attribute {
277+
/// Extracts the MetaItem from inside this Attribute.
278+
pub fn meta(&self) -> Option<MetaItem> {
279+
self.item.meta(self.span)
280+
}
275281

276282
pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
277283
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
@@ -333,10 +339,9 @@ impl Attribute {
333339
DUMMY_SP,
334340
);
335341
f(&Attribute {
342+
item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
336343
id: self.id,
337344
style: self.style,
338-
path: meta.path,
339-
tokens: meta.kind.tokens(meta.span),
340345
is_sugared_doc: true,
341346
span: self.span,
342347
})
@@ -384,10 +389,9 @@ crate fn mk_attr_id() -> AttrId {
384389

385390
pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute {
386391
Attribute {
392+
item: AttrItem { path, tokens },
387393
id: mk_attr_id(),
388394
style,
389-
path,
390-
tokens,
391395
is_sugared_doc: false,
392396
span,
393397
}
@@ -408,10 +412,12 @@ pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute {
408412
let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked);
409413
let lit = Lit::from_lit_kind(lit_kind, span);
410414
Attribute {
415+
item: AttrItem {
416+
path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)),
417+
tokens: MetaItemKind::NameValue(lit).tokens(span),
418+
},
411419
id: mk_attr_id(),
412420
style,
413-
path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)),
414-
tokens: MetaItemKind::NameValue(lit).tokens(span),
415421
is_sugared_doc: true,
416422
span,
417423
}
@@ -524,7 +530,7 @@ impl MetaItem {
524530
}
525531
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
526532
token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident),
527-
token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()),
533+
token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
528534
token::Nonterminal::NtPath(ref path) => path.clone(),
529535
_ => return None,
530536
},

src/libsyntax/config.rs

+4-5
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,8 @@ impl<'a> StripUnconfigured<'a> {
122122

123123
while !parser.check(&token::CloseDelim(token::Paren)) {
124124
let lo = parser.token.span.lo();
125-
let (path, tokens) = parser.parse_meta_item_unrestricted()?;
126-
expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo)));
125+
let item = parser.parse_attr_item()?;
126+
expanded_attrs.push((item, parser.prev_span.with_lo(lo)));
127127
parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
128128
}
129129

@@ -150,11 +150,10 @@ impl<'a> StripUnconfigured<'a> {
150150
// `cfg_attr` inside of another `cfg_attr`. E.g.
151151
// `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
152152
expanded_attrs.into_iter()
153-
.flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute {
153+
.flat_map(|(item, span)| self.process_cfg_attr(ast::Attribute {
154+
item,
154155
id: attr::mk_attr_id(),
155156
style: attr.style,
156-
path,
157-
tokens,
158157
is_sugared_doc: false,
159158
span,
160159
}))

src/libsyntax/ext/expand.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path};
1+
use crate::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path};
22
use crate::ast::{MacStmtStyle, StmtKind, ItemKind};
33
use crate::attr::{self, HasAttrs};
44
use crate::source_map::respan;
@@ -625,9 +625,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
625625
| Annotatable::Variant(..)
626626
=> panic!("unexpected annotatable"),
627627
})), DUMMY_SP).into();
628-
let input = self.extract_proc_macro_attr_input(attr.tokens, span);
628+
let input = self.extract_proc_macro_attr_input(attr.item.tokens, span);
629629
let tok_result = expander.expand(self.cx, span, input, item_tok);
630-
let res = self.parse_ast_fragment(tok_result, fragment_kind, &attr.path, span);
630+
let res =
631+
self.parse_ast_fragment(tok_result, fragment_kind, &attr.item.path, span);
631632
self.gate_proc_macro_expansion(span, &res);
632633
res
633634
}
@@ -1530,11 +1531,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
15301531

15311532
let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items);
15321533
*at = attr::Attribute {
1534+
item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
15331535
span: at.span,
15341536
id: at.id,
15351537
style: at.style,
1536-
path: meta.path,
1537-
tokens: meta.kind.tokens(meta.span),
15381538
is_sugared_doc: false,
15391539
};
15401540
} else {

src/libsyntax/ext/mbe/macro_parser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -924,7 +924,7 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal {
924924
FatalError.raise()
925925
}
926926
sym::path => token::NtPath(panictry!(p.parse_path(PathStyle::Type))),
927-
sym::meta => token::NtMeta(panictry!(p.parse_meta_item())),
927+
sym::meta => token::NtMeta(panictry!(p.parse_attr_item())),
928928
sym::vis => token::NtVis(panictry!(p.parse_visibility(true))),
929929
sym::lifetime => if p.check_lifetime() {
930930
token::NtLifetime(p.expect_lifetime().ident)

src/libsyntax/mut_visit.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -550,7 +550,8 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
550550
}
551551

552552
pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
553-
let Attribute { id: _, style: _, path, tokens, is_sugared_doc: _, span } = attr;
553+
let Attribute { item: AttrItem { path, tokens }, id: _, style: _, is_sugared_doc: _, span }
554+
= attr;
554555
vis.visit_path(path);
555556
vis.visit_tts(tokens);
556557
vis.visit_span(span);
@@ -681,7 +682,10 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis:
681682
token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
682683
token::NtLifetime(ident) => vis.visit_ident(ident),
683684
token::NtLiteral(expr) => vis.visit_expr(expr),
684-
token::NtMeta(meta) => vis.visit_meta_item(meta),
685+
token::NtMeta(AttrItem { path, tokens }) => {
686+
vis.visit_path(path);
687+
vis.visit_tts(tokens);
688+
}
685689
token::NtPath(path) => vis.visit_path(path),
686690
token::NtTT(tt) => vis.visit_tt(tt),
687691
token::NtImplItem(item) =>

src/libsyntax/parse/attr.rs

+20-16
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ impl<'a> Parser<'a> {
9090
debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
9191
inner_parse_policy,
9292
self.token);
93-
let (span, path, tokens, style) = match self.token.kind {
93+
let (span, item, style) = match self.token.kind {
9494
token::Pound => {
9595
let lo = self.token.span;
9696
self.bump();
@@ -107,7 +107,7 @@ impl<'a> Parser<'a> {
107107
};
108108

109109
self.expect(&token::OpenDelim(token::Bracket))?;
110-
let (path, tokens) = self.parse_meta_item_unrestricted()?;
110+
let item = self.parse_attr_item()?;
111111
self.expect(&token::CloseDelim(token::Bracket))?;
112112
let hi = self.prev_span;
113113

@@ -142,7 +142,7 @@ impl<'a> Parser<'a> {
142142
}
143143
}
144144

145-
(attr_sp, path, tokens, style)
145+
(attr_sp, item, style)
146146
}
147147
_ => {
148148
let token_str = self.this_token_to_string();
@@ -151,10 +151,9 @@ impl<'a> Parser<'a> {
151151
};
152152

153153
Ok(ast::Attribute {
154+
item,
154155
id: attr::mk_attr_id(),
155156
style,
156-
path,
157-
tokens,
158157
is_sugared_doc: false,
159158
span,
160159
})
@@ -167,19 +166,19 @@ impl<'a> Parser<'a> {
167166
/// PATH `[` TOKEN_STREAM `]`
168167
/// PATH `{` TOKEN_STREAM `}`
169168
/// PATH
170-
/// PATH `=` TOKEN_TREE
169+
/// PATH `=` UNSUFFIXED_LIT
171170
/// The delimiters or `=` are still put into the resulting token stream.
172-
pub fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
173-
let meta = match self.token.kind {
171+
pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
172+
let item = match self.token.kind {
174173
token::Interpolated(ref nt) => match **nt {
175-
Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
174+
Nonterminal::NtMeta(ref item) => Some(item.clone()),
176175
_ => None,
177176
},
178177
_ => None,
179178
};
180-
Ok(if let Some(meta) = meta {
179+
Ok(if let Some(item) = item {
181180
self.bump();
182-
(meta.path, meta.kind.tokens(meta.span))
181+
item
183182
} else {
184183
let path = self.parse_path(PathStyle::Mod)?;
185184
let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) ||
@@ -206,7 +205,7 @@ impl<'a> Parser<'a> {
206205
} else {
207206
TokenStream::empty()
208207
};
209-
(path, tokens)
208+
ast::AttrItem { path, tokens }
210209
})
211210
}
212211

@@ -263,7 +262,7 @@ impl<'a> Parser<'a> {
263262

264263
/// Matches the following grammar (per RFC 1559).
265264
///
266-
/// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
265+
/// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
267266
/// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
268267
pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
269268
let nt_meta = match self.token.kind {
@@ -274,9 +273,14 @@ impl<'a> Parser<'a> {
274273
_ => None,
275274
};
276275

277-
if let Some(meta) = nt_meta {
278-
self.bump();
279-
return Ok(meta);
276+
if let Some(item) = nt_meta {
277+
return match item.meta(item.path.span) {
278+
Some(meta) => {
279+
self.bump();
280+
Ok(meta)
281+
}
282+
None => self.unexpected(),
283+
}
280284
}
281285

282286
let lo = self.token.span;

src/libsyntax/parse/parser/path.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,9 @@ impl<'a> Parser<'a> {
114114
pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> {
115115
let meta_ident = match self.token.kind {
116116
token::Interpolated(ref nt) => match **nt {
117-
token::NtMeta(ref meta) => match meta.kind {
118-
ast::MetaItemKind::Word => Some(meta.path.clone()),
119-
_ => None,
117+
token::NtMeta(ref item) => match item.tokens.is_empty() {
118+
true => Some(item.path.clone()),
119+
false => None,
120120
},
121121
_ => None,
122122
},

src/libsyntax/parse/token.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,7 @@ pub enum Nonterminal {
687687
NtLifetime(ast::Ident),
688688
NtLiteral(P<ast::Expr>),
689689
/// Stuff inside brackets for attributes
690-
NtMeta(ast::MetaItem),
690+
NtMeta(ast::AttrItem),
691691
NtPath(ast::Path),
692692
NtVis(ast::Visibility),
693693
NtTT(TokenTree),

0 commit comments

Comments
 (0)