Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

syntax: Support modern attribute syntax in the meta matcher #63674

Merged
merged 3 commits into from
Oct 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -988,10 +988,12 @@ impl<'a> LoweringContext<'a> {
// lower attributes (we use the AST version) there is nowhere to keep
// the `HirId`s. We don't actually need HIR version of attributes anyway.
Attribute {
item: AttrItem {
path: attr.path.clone(),
tokens: self.lower_token_stream(attr.tokens.clone()),
},
id: attr.id,
style: attr.style,
path: attr.path.clone(),
tokens: self.lower_token_stream(attr.tokens.clone()),
is_sugared_doc: attr.is_sugared_doc,
span: attr.span,
}
Expand Down
13 changes: 7 additions & 6 deletions src/librustc/ich/impls_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,26 +196,27 @@ impl<'a> HashStable<StableHashingContext<'a>> for ast::Path {
}
}

impl_stable_hash_for!(struct ::syntax::ast::AttrItem {
path,
tokens,
});

impl<'a> HashStable<StableHashingContext<'a>> for ast::Attribute {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
// Make sure that these have been filtered out.
debug_assert!(!self.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name)));
debug_assert!(!self.is_sugared_doc);

let ast::Attribute {
ref item,
id: _,
style,
ref path,
ref tokens,
is_sugared_doc: _,
span,
} = *self;

item.hash_stable(hcx, hasher);
style.hash_stable(hcx, hasher);
path.hash_stable(hcx, hasher);
for tt in tokens.trees() {
tt.hash_stable(hcx, hasher);
}
span.hash_stable(hcx, hasher);
}
}
Expand Down
15 changes: 13 additions & 2 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2139,18 +2139,29 @@ impl rustc_serialize::Decodable for AttrId {
}
}

#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct AttrItem {
pub path: Path,
pub tokens: TokenStream,
}

/// Metadata associated with an item.
/// Doc-comments are promoted to attributes that have `is_sugared_doc = true`.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Attribute {
pub item: AttrItem,
pub id: AttrId,
pub style: AttrStyle,
pub path: Path,
pub tokens: TokenStream,
pub is_sugared_doc: bool,
pub span: Span,
}

// Compatibility impl to avoid churn, consider removing.
impl std::ops::Deref for Attribute {
petrochenkov marked this conversation as resolved.
Show resolved Hide resolved
type Target = AttrItem;
fn deref(&self) -> &Self::Target { &self.item }
}

/// `TraitRef`s appear in impls.
///
/// Resolution maps each `TraitRef`'s `ref_id` to its defining trait; that's all
Expand Down
30 changes: 18 additions & 12 deletions src/libsyntax/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ pub use StabilityLevel::*;
pub use crate::ast::Attribute;

use crate::ast;
use crate::ast::{AttrId, AttrStyle, Name, Ident, Path, PathSegment};
use crate::ast::{AttrItem, AttrId, AttrStyle, Name, Ident, Path, PathSegment};
use crate::ast::{MetaItem, MetaItemKind, NestedMetaItem};
use crate::ast::{Lit, LitKind, Expr, Item, Local, Stmt, StmtKind, GenericParam};
use crate::mut_visit::visit_clobber;
Expand Down Expand Up @@ -255,9 +255,8 @@ impl MetaItem {
}
}

impl Attribute {
/// Extracts the `MetaItem` from inside this `Attribute`.
pub fn meta(&self) -> Option<MetaItem> {
impl AttrItem {
crate fn meta(&self, span: Span) -> Option<MetaItem> {
let mut tokens = self.tokens.trees().peekable();
Some(MetaItem {
path: self.path.clone(),
Expand All @@ -269,9 +268,16 @@ impl Attribute {
} else {
return None;
},
span: self.span,
span,
})
}
}

impl Attribute {
/// Extracts the MetaItem from inside this Attribute.
pub fn meta(&self) -> Option<MetaItem> {
self.item.meta(self.span)
}

pub fn parse<'a, T, F>(&self, sess: &'a ParseSess, mut f: F) -> PResult<'a, T>
where F: FnMut(&mut Parser<'a>) -> PResult<'a, T>,
Expand Down Expand Up @@ -333,10 +339,9 @@ impl Attribute {
DUMMY_SP,
);
f(&Attribute {
item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
id: self.id,
style: self.style,
path: meta.path,
tokens: meta.kind.tokens(meta.span),
is_sugared_doc: true,
span: self.span,
})
Expand Down Expand Up @@ -384,10 +389,9 @@ crate fn mk_attr_id() -> AttrId {

pub fn mk_attr(style: AttrStyle, path: Path, tokens: TokenStream, span: Span) -> Attribute {
Attribute {
item: AttrItem { path, tokens },
id: mk_attr_id(),
style,
path,
tokens,
is_sugared_doc: false,
span,
}
Expand All @@ -408,10 +412,12 @@ pub fn mk_sugared_doc_attr(text: Symbol, span: Span) -> Attribute {
let lit_kind = LitKind::Str(text, ast::StrStyle::Cooked);
let lit = Lit::from_lit_kind(lit_kind, span);
Attribute {
item: AttrItem {
path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)),
tokens: MetaItemKind::NameValue(lit).tokens(span),
},
id: mk_attr_id(),
style,
path: Path::from_ident(Ident::with_dummy_span(sym::doc).with_span_pos(span)),
tokens: MetaItemKind::NameValue(lit).tokens(span),
is_sugared_doc: true,
span,
}
Expand Down Expand Up @@ -524,7 +530,7 @@ impl MetaItem {
}
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
token::Nonterminal::NtIdent(ident, _) => Path::from_ident(ident),
token::Nonterminal::NtMeta(ref meta) => return Some(meta.clone()),
token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
token::Nonterminal::NtPath(ref path) => path.clone(),
_ => return None,
},
Expand Down
9 changes: 4 additions & 5 deletions src/libsyntax/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ impl<'a> StripUnconfigured<'a> {

while !parser.check(&token::CloseDelim(token::Paren)) {
let lo = parser.token.span.lo();
let (path, tokens) = parser.parse_meta_item_unrestricted()?;
expanded_attrs.push((path, tokens, parser.prev_span.with_lo(lo)));
let item = parser.parse_attr_item()?;
expanded_attrs.push((item, parser.prev_span.with_lo(lo)));
parser.expect_one_of(&[token::Comma], &[token::CloseDelim(token::Paren)])?;
}

Expand All @@ -150,11 +150,10 @@ impl<'a> StripUnconfigured<'a> {
// `cfg_attr` inside of another `cfg_attr`. E.g.
// `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
expanded_attrs.into_iter()
.flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute {
.flat_map(|(item, span)| self.process_cfg_attr(ast::Attribute {
item,
id: attr::mk_attr_id(),
style: attr.style,
path,
tokens,
is_sugared_doc: false,
span,
}))
Expand Down
10 changes: 5 additions & 5 deletions src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::ast::{self, Block, Ident, LitKind, NodeId, PatKind, Path};
use crate::ast::{self, AttrItem, Block, Ident, LitKind, NodeId, PatKind, Path};
use crate::ast::{MacStmtStyle, StmtKind, ItemKind};
use crate::attr::{self, HasAttrs};
use crate::source_map::respan;
Expand Down Expand Up @@ -625,9 +625,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
| Annotatable::Variant(..)
=> panic!("unexpected annotatable"),
})), DUMMY_SP).into();
let input = self.extract_proc_macro_attr_input(attr.tokens, span);
let input = self.extract_proc_macro_attr_input(attr.item.tokens, span);
let tok_result = expander.expand(self.cx, span, input, item_tok);
let res = self.parse_ast_fragment(tok_result, fragment_kind, &attr.path, span);
let res =
self.parse_ast_fragment(tok_result, fragment_kind, &attr.item.path, span);
self.gate_proc_macro_expansion(span, &res);
res
}
Expand Down Expand Up @@ -1530,11 +1531,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {

let meta = attr::mk_list_item(Ident::with_dummy_span(sym::doc), items);
*at = attr::Attribute {
item: AttrItem { path: meta.path, tokens: meta.kind.tokens(meta.span) },
span: at.span,
id: at.id,
style: at.style,
path: meta.path,
tokens: meta.kind.tokens(meta.span),
is_sugared_doc: false,
};
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/mbe/macro_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,7 @@ fn parse_nt(p: &mut Parser<'_>, sp: Span, name: Symbol) -> Nonterminal {
FatalError.raise()
}
sym::path => token::NtPath(panictry!(p.parse_path(PathStyle::Type))),
sym::meta => token::NtMeta(panictry!(p.parse_meta_item())),
sym::meta => token::NtMeta(panictry!(p.parse_attr_item())),
sym::vis => token::NtVis(panictry!(p.parse_visibility(true))),
sym::lifetime => if p.check_lifetime() {
token::NtLifetime(p.expect_lifetime().ident)
Expand Down
8 changes: 6 additions & 2 deletions src/libsyntax/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,8 @@ pub fn noop_visit_local<T: MutVisitor>(local: &mut P<Local>, vis: &mut T) {
}

pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
let Attribute { id: _, style: _, path, tokens, is_sugared_doc: _, span } = attr;
let Attribute { item: AttrItem { path, tokens }, id: _, style: _, is_sugared_doc: _, span }
= attr;
vis.visit_path(path);
vis.visit_tts(tokens);
vis.visit_span(span);
Expand Down Expand Up @@ -681,7 +682,10 @@ pub fn noop_visit_interpolated<T: MutVisitor>(nt: &mut token::Nonterminal, vis:
token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
token::NtLifetime(ident) => vis.visit_ident(ident),
token::NtLiteral(expr) => vis.visit_expr(expr),
token::NtMeta(meta) => vis.visit_meta_item(meta),
token::NtMeta(AttrItem { path, tokens }) => {
vis.visit_path(path);
vis.visit_tts(tokens);
}
token::NtPath(path) => vis.visit_path(path),
token::NtTT(tt) => vis.visit_tt(tt),
token::NtImplItem(item) =>
Expand Down
36 changes: 20 additions & 16 deletions src/libsyntax/parse/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ impl<'a> Parser<'a> {
debug!("parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}",
inner_parse_policy,
self.token);
let (span, path, tokens, style) = match self.token.kind {
let (span, item, style) = match self.token.kind {
token::Pound => {
let lo = self.token.span;
self.bump();
Expand All @@ -107,7 +107,7 @@ impl<'a> Parser<'a> {
};

self.expect(&token::OpenDelim(token::Bracket))?;
let (path, tokens) = self.parse_meta_item_unrestricted()?;
let item = self.parse_attr_item()?;
self.expect(&token::CloseDelim(token::Bracket))?;
let hi = self.prev_span;

Expand Down Expand Up @@ -142,7 +142,7 @@ impl<'a> Parser<'a> {
}
}

(attr_sp, path, tokens, style)
(attr_sp, item, style)
}
_ => {
let token_str = self.this_token_to_string();
Expand All @@ -151,10 +151,9 @@ impl<'a> Parser<'a> {
};

Ok(ast::Attribute {
item,
id: attr::mk_attr_id(),
style,
path,
tokens,
is_sugared_doc: false,
span,
})
Expand All @@ -167,19 +166,19 @@ impl<'a> Parser<'a> {
/// PATH `[` TOKEN_STREAM `]`
/// PATH `{` TOKEN_STREAM `}`
/// PATH
/// PATH `=` TOKEN_TREE
/// PATH `=` UNSUFFIXED_LIT
/// The delimiters or `=` are still put into the resulting token stream.
pub fn parse_meta_item_unrestricted(&mut self) -> PResult<'a, (ast::Path, TokenStream)> {
let meta = match self.token.kind {
pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> {
let item = match self.token.kind {
token::Interpolated(ref nt) => match **nt {
Nonterminal::NtMeta(ref meta) => Some(meta.clone()),
Nonterminal::NtMeta(ref item) => Some(item.clone()),
_ => None,
},
_ => None,
};
Ok(if let Some(meta) = meta {
Ok(if let Some(item) = item {
self.bump();
(meta.path, meta.kind.tokens(meta.span))
item
} else {
let path = self.parse_path(PathStyle::Mod)?;
let tokens = if self.check(&token::OpenDelim(DelimToken::Paren)) ||
Expand All @@ -206,7 +205,7 @@ impl<'a> Parser<'a> {
} else {
TokenStream::empty()
};
(path, tokens)
ast::AttrItem { path, tokens }
})
}

Expand Down Expand Up @@ -263,7 +262,7 @@ impl<'a> Parser<'a> {

/// Matches the following grammar (per RFC 1559).
///
/// meta_item : IDENT ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
/// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
/// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
let nt_meta = match self.token.kind {
Expand All @@ -274,9 +273,14 @@ impl<'a> Parser<'a> {
_ => None,
petrochenkov marked this conversation as resolved.
Show resolved Hide resolved
};

if let Some(meta) = nt_meta {
self.bump();
return Ok(meta);
if let Some(item) = nt_meta {
return match item.meta(item.path.span) {
Some(meta) => {
self.bump();
Ok(meta)
}
None => self.unexpected(),
}
}

let lo = self.token.span;
Expand Down
6 changes: 3 additions & 3 deletions src/libsyntax/parse/parser/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,9 @@ impl<'a> Parser<'a> {
pub fn parse_path_allowing_meta(&mut self, style: PathStyle) -> PResult<'a, Path> {
let meta_ident = match self.token.kind {
token::Interpolated(ref nt) => match **nt {
token::NtMeta(ref meta) => match meta.kind {
ast::MetaItemKind::Word => Some(meta.path.clone()),
_ => None,
token::NtMeta(ref item) => match item.tokens.is_empty() {
true => Some(item.path.clone()),
false => None,
},
_ => None,
},
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/parse/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ pub enum Nonterminal {
NtLifetime(ast::Ident),
NtLiteral(P<ast::Expr>),
/// Stuff inside brackets for attributes
NtMeta(ast::MetaItem),
NtMeta(ast::AttrItem),
NtPath(ast::Path),
NtVis(ast::Visibility),
NtTT(TokenTree),
Expand Down
Loading