From 3eba6c18d435fbbdbb46ebd1b2f9bd565daa190c Mon Sep 17 00:00:00 2001 From: Mazdak Farrokhzad Date: Sun, 29 Sep 2019 06:21:20 +0200 Subject: syntax: recover trailing `|` in or-patterns. --- src/libsyntax/parse/parser/pat.rs | 105 ++++++++++++++++++++++++++++---------- 1 file changed, 79 insertions(+), 26 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/parser/pat.rs b/src/libsyntax/parse/parser/pat.rs index de72f1c4d49..7eb2a73a11a 100644 --- a/src/libsyntax/parse/parser/pat.rs +++ b/src/libsyntax/parse/parser/pat.rs @@ -18,6 +18,8 @@ type Expected = Option<&'static str>; /// `Expected` for function and lambda parameter patterns. pub(super) const PARAM_EXPECTED: Expected = Some("parameter name"); +const WHILE_PARSING_OR_MSG: &str = "while parsing this or-pattern starting here"; + /// Whether or not an or-pattern should be gated when occurring in the current context. #[derive(PartialEq)] pub enum GateOr { Yes, No } @@ -40,7 +42,7 @@ impl<'a> Parser<'a> { /// Corresponds to `top_pat` in RFC 2535 and allows or-pattern at the top level. pub(super) fn parse_top_pat(&mut self, gate_or: GateOr) -> PResult<'a, P> { // Allow a '|' before the pats (RFCs 1925, 2530, and 2535). - let gated_leading_vert = self.eat_or_separator() && gate_or == GateOr::Yes; + let gated_leading_vert = self.eat_or_separator(None) && gate_or == GateOr::Yes; let leading_vert_span = self.prev_span; // Parse the possibly-or-pattern. @@ -63,7 +65,7 @@ impl<'a> Parser<'a> { /// Parse the pattern for a function or function pointer parameter. /// Special recovery is provided for or-patterns and leading `|`. pub(super) fn parse_fn_param_pat(&mut self) -> PResult<'a, P> { - self.recover_leading_vert("not allowed in a parameter pattern"); + self.recover_leading_vert(None, "not allowed in a parameter pattern"); let pat = self.parse_pat_with_or(PARAM_EXPECTED, GateOr::No, RecoverComma::No)?; if let PatKind::Or(..) = &pat.kind { @@ -90,7 +92,7 @@ impl<'a> Parser<'a> { gate_or: GateOr, rc: RecoverComma, ) -> PResult<'a, P> { - // Parse the first pattern. + // Parse the first pattern (`p_0`). let first_pat = self.parse_pat(expected)?; self.maybe_recover_unexpected_comma(first_pat.span, rc)?; @@ -100,11 +102,12 @@ impl<'a> Parser<'a> { return Ok(first_pat) } + // Parse the patterns `p_1 | ... | p_n` where `n > 0`. let lo = first_pat.span; let mut pats = vec![first_pat]; - while self.eat_or_separator() { + while self.eat_or_separator(Some(lo)) { let pat = self.parse_pat(expected).map_err(|mut err| { - err.span_label(lo, "while parsing this or-pattern starting here"); + err.span_label(lo, WHILE_PARSING_OR_MSG); err })?; self.maybe_recover_unexpected_comma(pat.span, rc)?; @@ -122,11 +125,15 @@ impl<'a> Parser<'a> { /// Eat the or-pattern `|` separator. /// If instead a `||` token is encountered, recover and pretend we parsed `|`. - fn eat_or_separator(&mut self) -> bool { + fn eat_or_separator(&mut self, lo: Option) -> bool { + if self.recover_trailing_vert(lo) { + return false; + } + match self.token.kind { token::OrOr => { // Found `||`; Recover and pretend we parsed `|`. - self.ban_unexpected_or_or(); + self.ban_unexpected_or_or(lo); self.bump(); true } @@ -134,16 +141,49 @@ impl<'a> Parser<'a> { } } + /// Recover if `|` or `||` is the current token and we have one of the + /// tokens `=>`, `if`, `=`, `:`, `;`, `,`, `]`, `)`, or `}` ahead of us. + /// + /// These tokens all indicate that we reached the end of the or-pattern + /// list and can now reliably say that the `|` was an illegal trailing vert. + /// Note that there are more tokens such as `@` for which we know that the `|` + /// is an illegal parse. However, the user's intent is less clear in that case. + fn recover_trailing_vert(&mut self, lo: Option) -> bool { + let is_end_ahead = self.look_ahead(1, |token| match &token.kind { + token::FatArrow // e.g. `a | => 0,`. + | token::Ident(kw::If, false) // e.g. `a | if expr`. + | token::Eq // e.g. `let a | = 0`. + | token::Semi // e.g. `let a |;`. + | token::Colon // e.g. `let a | :`. + | token::Comma // e.g. `let (a |,)`. + | token::CloseDelim(token::Bracket) // e.g. `let [a | ]`. + | token::CloseDelim(token::Paren) // e.g. `let (a | )`. + | token::CloseDelim(token::Brace) => true, // e.g. `let A { f: a | }`. + _ => false, + }); + match (is_end_ahead, &self.token.kind) { + (true, token::BinOp(token::Or)) | (true, token::OrOr) => { + self.ban_illegal_vert(lo, "trailing", "not allowed in an or-pattern"); + self.bump(); + true + } + _ => false, + } + } + /// We have parsed `||` instead of `|`. Error and suggest `|` instead. - fn ban_unexpected_or_or(&mut self) { - self.struct_span_err(self.token.span, "unexpected token `||` after pattern") - .span_suggestion( - self.token.span, - "use a single `|` to separate multiple alternative patterns", - "|".to_owned(), - Applicability::MachineApplicable - ) - .emit(); + fn ban_unexpected_or_or(&mut self, lo: Option) { + let mut err = self.struct_span_err(self.token.span, "unexpected token `||` after pattern"); + err.span_suggestion( + self.token.span, + "use a single `|` to separate multiple alternative patterns", + "|".to_owned(), + Applicability::MachineApplicable + ); + if let Some(lo) = lo { + err.span_label(lo, WHILE_PARSING_OR_MSG); + } + err.emit(); } /// Some special error handling for the "top-level" patterns in a match arm, @@ -198,25 +238,38 @@ impl<'a> Parser<'a> { /// Recursive possibly-or-pattern parser with recovery for an erroneous leading `|`. /// See `parse_pat_with_or` for details on parsing or-patterns. fn parse_pat_with_or_inner(&mut self) -> PResult<'a, P> { - self.recover_leading_vert("only allowed in a top-level pattern"); + self.recover_leading_vert(None, "only allowed in a top-level pattern"); self.parse_pat_with_or(None, GateOr::Yes, RecoverComma::No) } /// Recover if `|` or `||` is here. /// The user is thinking that a leading `|` is allowed in this position. - fn recover_leading_vert(&mut self, ctx: &str) { + fn recover_leading_vert(&mut self, lo: Option, ctx: &str) { if let token::BinOp(token::Or) | token::OrOr = self.token.kind { - let span = self.token.span; - let rm_msg = format!("remove the `{}`", pprust::token_to_string(&self.token)); - - self.struct_span_err(span, &format!("a leading `|` is {}", ctx)) - .span_suggestion(span, &rm_msg, String::new(), Applicability::MachineApplicable) - .emit(); - + self.ban_illegal_vert(lo, "leading", ctx); self.bump(); } } + /// A `|` or possibly `||` token shouldn't be here. Ban it. + fn ban_illegal_vert(&mut self, lo: Option, pos: &str, ctx: &str) { + let span = self.token.span; + let mut err = self.struct_span_err(span, &format!("a {} `|` is {}", pos, ctx)); + err.span_suggestion( + span, + &format!("remove the `{}`", pprust::token_to_string(&self.token)), + String::new(), + Applicability::MachineApplicable, + ); + if let Some(lo) = lo { + err.span_label(lo, WHILE_PARSING_OR_MSG); + } + if let token::OrOr = self.token.kind { + err.note("alternatives in or-patterns are separated with `|`, not `||`"); + } + err.emit(); + } + /// Parses a pattern, with a setting whether modern range patterns (e.g., `a..=b`, `a..b` are /// allowed). fn parse_pat_with_range_pat( @@ -259,7 +312,7 @@ impl<'a> Parser<'a> { self.bump(); self.parse_pat_range_to(RangeEnd::Included(RangeSyntax::DotDotDot), "...")? } - // At this point, token != &, &&, (, [ + // At this point, token != `&`, `&&`, `(`, `[`, `..`, `..=`, or `...`. _ => if self.eat_keyword(kw::Underscore) { // Parse _ PatKind::Wild -- cgit 1.4.1-3-g733a5 From fdd1a62a453dd41b75bc1b3a992c35292b853877 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Mon, 30 Sep 2019 01:05:00 +0100 Subject: Added backticks for one diagnostic message. --- src/libsyntax/parse/lexer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 66add869359..ac3feadce3a 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -47,7 +47,7 @@ impl<'a> StringReader<'a> { source_file: Lrc, override_span: Option) -> Self { if source_file.src.is_none() { - sess.span_diagnostic.bug(&format!("Cannot lex source_file without source: {}", + sess.span_diagnostic.bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); } -- cgit 1.4.1-3-g733a5 From 535d4743a4bc4807446cefbc2413e02d53aa0a85 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 17 Aug 2019 23:55:41 +0300 Subject: syntax: Split `ast::Attribute` into container and inner parts --- src/librustc/hir/lowering.rs | 6 ++++-- src/librustc/ich/impls_syntax.rs | 13 +++++++------ src/libsyntax/ast.rs | 14 ++++++++++++-- src/libsyntax/attr/mod.rs | 14 +++++++------- src/libsyntax/config.rs | 3 +-- src/libsyntax/ext/expand.rs | 10 +++++----- src/libsyntax/mut_visit.rs | 3 ++- src/libsyntax/parse/attr.rs | 3 +-- 8 files changed, 39 insertions(+), 27 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 4310bafd781..2238a56b29d 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -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, } diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index bdcf9e42ac2..23a2f115e05 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -196,6 +196,11 @@ impl<'a> HashStable> for ast::Path { } } +impl_stable_hash_for!(struct ::syntax::ast::AttrItem { + path, + tokens, +}); + impl<'a> HashStable> for ast::Attribute { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { // Make sure that these have been filtered out. @@ -203,19 +208,15 @@ impl<'a> HashStable> for ast::Attribute { 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); } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7a5c92167bc..e2c8e37e11c 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2139,18 +2139,28 @@ 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, } +impl std::ops::Deref for Attribute { + 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 diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 122cb7fb12b..009259352ba 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -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; @@ -333,10 +333,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, }) @@ -384,10 +383,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, } @@ -408,10 +406,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, } diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index 990358c674f..a9a5c3efd06 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -151,10 +151,9 @@ impl<'a> StripUnconfigured<'a> { // `#[cfg_attr(false, cfg_attr(true, some_attr))]`. expanded_attrs.into_iter() .flat_map(|(path, tokens, span)| self.process_cfg_attr(ast::Attribute { + item: ast::AttrItem { path, tokens }, id: attr::mk_attr_id(), style: attr.style, - path, - tokens, is_sugared_doc: false, span, })) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 02e7c6775a4..2b0fc5d3677 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -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; @@ -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 } @@ -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 { diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 80dfe9e5be0..4b78282b787 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -550,7 +550,8 @@ pub fn noop_visit_local(local: &mut P, vis: &mut T) { } pub fn noop_visit_attribute(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); diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 44688bd36b5..707f903916c 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -151,10 +151,9 @@ impl<'a> Parser<'a> { }; Ok(ast::Attribute { + item: ast::AttrItem { path, tokens }, id: attr::mk_attr_id(), style, - path, - tokens, is_sugared_doc: false, span, }) -- cgit 1.4.1-3-g733a5 From 957986d05620238799ae7053d505f742a0c7d640 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 18 Aug 2019 01:10:56 +0300 Subject: syntax: Support modern attribute syntax in the `meta` matcher --- src/libsyntax/attr/mod.rs | 16 +++++++++----- src/libsyntax/config.rs | 8 +++---- src/libsyntax/ext/mbe/macro_parser.rs | 2 +- src/libsyntax/mut_visit.rs | 5 ++++- src/libsyntax/parse/attr.rs | 31 +++++++++++++++------------ src/libsyntax/parse/parser/path.rs | 6 +++--- src/libsyntax/parse/token.rs | 2 +- src/libsyntax/print/pprust.rs | 40 +++++++++++++++++++---------------- src/libsyntax_ext/cmdline_attrs.rs | 4 ++-- src/test/ui/cfg/cfg_stmt_expr.rs | 4 ++-- src/test/ui/macros/macro-first-set.rs | 6 ------ 11 files changed, 68 insertions(+), 56 deletions(-) (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/attr/mod.rs b/src/libsyntax/attr/mod.rs index 009259352ba..7bef693a5be 100644 --- a/src/libsyntax/attr/mod.rs +++ b/src/libsyntax/attr/mod.rs @@ -255,9 +255,8 @@ impl MetaItem { } } -impl Attribute { - /// Extracts the `MetaItem` from inside this `Attribute`. - pub fn meta(&self) -> Option { +impl AttrItem { + crate fn meta(&self, span: Span) -> Option { let mut tokens = self.tokens.trees().peekable(); Some(MetaItem { path: self.path.clone(), @@ -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 { + 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>, @@ -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, }, diff --git a/src/libsyntax/config.rs b/src/libsyntax/config.rs index a9a5c3efd06..2923cc86ba0 100644 --- a/src/libsyntax/config.rs +++ b/src/libsyntax/config.rs @@ -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)])?; } @@ -150,8 +150,8 @@ 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 { - item: ast::AttrItem { path, tokens }, + .flat_map(|(item, span)| self.process_cfg_attr(ast::Attribute { + item, id: attr::mk_attr_id(), style: attr.style, is_sugared_doc: false, diff --git a/src/libsyntax/ext/mbe/macro_parser.rs b/src/libsyntax/ext/mbe/macro_parser.rs index 8f49ba9572d..d1c50fd8594 100644 --- a/src/libsyntax/ext/mbe/macro_parser.rs +++ b/src/libsyntax/ext/mbe/macro_parser.rs @@ -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) diff --git a/src/libsyntax/mut_visit.rs b/src/libsyntax/mut_visit.rs index 4b78282b787..3923b9f297b 100644 --- a/src/libsyntax/mut_visit.rs +++ b/src/libsyntax/mut_visit.rs @@ -682,7 +682,10 @@ pub fn noop_visit_interpolated(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) => diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 707f903916c..f3298b6a65d 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -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(); @@ -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; @@ -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(); @@ -151,7 +151,7 @@ impl<'a> Parser<'a> { }; Ok(ast::Attribute { - item: ast::AttrItem { path, tokens }, + item, id: attr::mk_attr_id(), style, is_sugared_doc: false, @@ -168,17 +168,17 @@ impl<'a> Parser<'a> { /// PATH /// PATH `=` TOKEN_TREE /// 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)) || @@ -205,7 +205,7 @@ impl<'a> Parser<'a> { } else { TokenStream::empty() }; - (path, tokens) + ast::AttrItem { path, tokens } }) } @@ -273,9 +273,14 @@ impl<'a> Parser<'a> { _ => None, }; - 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; diff --git a/src/libsyntax/parse/parser/path.rs b/src/libsyntax/parse/parser/path.rs index 463ae9124ca..ca823991a2e 100644 --- a/src/libsyntax/parse/parser/path.rs +++ b/src/libsyntax/parse/parser/path.rs @@ -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, }, diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index fe3b51aa246..fd78a2bd534 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -687,7 +687,7 @@ pub enum Nonterminal { NtLifetime(ast::Ident), NtLiteral(P), /// Stuff inside brackets for attributes - NtMeta(ast::MetaItem), + NtMeta(ast::AttrItem), NtPath(ast::Path), NtVis(ast::Visibility), NtTT(TokenTree), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 4b9c2d13f26..7d4ffe493d7 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -324,7 +324,7 @@ fn token_to_string_ext(token: &Token, convert_dollar_crate: bool) -> String { crate fn nonterminal_to_string(nt: &Nonterminal) -> String { match *nt { token::NtExpr(ref e) => expr_to_string(e), - token::NtMeta(ref e) => meta_item_to_string(e), + token::NtMeta(ref e) => attr_item_to_string(e), token::NtTy(ref e) => ty_to_string(e), token::NtPath(ref e) => path_to_string(e), token::NtItem(ref e) => item_to_string(e), @@ -412,8 +412,8 @@ pub fn meta_list_item_to_string(li: &ast::NestedMetaItem) -> String { to_string(|s| s.print_meta_list_item(li)) } -pub fn meta_item_to_string(mi: &ast::MetaItem) -> String { - to_string(|s| s.print_meta_item(mi)) +fn attr_item_to_string(ai: &ast::AttrItem) -> String { + to_string(|s| s.print_attr_item(ai, ai.path.span)) } pub fn attribute_to_string(attr: &ast::Attribute) -> String { @@ -629,24 +629,28 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere ast::AttrStyle::Inner => self.word("#!["), ast::AttrStyle::Outer => self.word("#["), } - self.ibox(0); - match attr.tokens.trees().next() { - Some(TokenTree::Delimited(_, delim, tts)) => { - self.print_mac_common( - Some(MacHeader::Path(&attr.path)), false, None, delim, tts, true, attr.span - ); - } - tree => { - self.print_path(&attr.path, false, 0); - if tree.is_some() { - self.space(); - self.print_tts(attr.tokens.clone(), true); - } + self.print_attr_item(&attr.item, attr.span); + self.word("]"); + } + } + + fn print_attr_item(&mut self, item: &ast::AttrItem, span: Span) { + self.ibox(0); + match item.tokens.trees().next() { + Some(TokenTree::Delimited(_, delim, tts)) => { + self.print_mac_common( + Some(MacHeader::Path(&item.path)), false, None, delim, tts, true, span + ); + } + tree => { + self.print_path(&item.path, false, 0); + if tree.is_some() { + self.space(); + self.print_tts(item.tokens.clone(), true); } } - self.end(); - self.word("]"); } + self.end(); } fn print_meta_list_item(&mut self, item: &ast::NestedMetaItem) { diff --git a/src/libsyntax_ext/cmdline_attrs.rs b/src/libsyntax_ext/cmdline_attrs.rs index bb8e3df3db9..203c4a83489 100644 --- a/src/libsyntax_ext/cmdline_attrs.rs +++ b/src/libsyntax_ext/cmdline_attrs.rs @@ -1,6 +1,6 @@ //! Attributes injected into the crate root from command line using `-Z crate-attr`. -use syntax::ast::{self, AttrStyle}; +use syntax::ast::{self, AttrItem, AttrStyle}; use syntax::attr::mk_attr; use syntax::panictry; use syntax::parse::{self, token, ParseSess}; @@ -15,7 +15,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - ); let start_span = parser.token.span; - let (path, tokens) = panictry!(parser.parse_meta_item_unrestricted()); + let AttrItem { path, tokens } = panictry!(parser.parse_attr_item()); let end_span = parser.token.span; if parser.token != token::Eof { parse_sess.span_diagnostic diff --git a/src/test/ui/cfg/cfg_stmt_expr.rs b/src/test/ui/cfg/cfg_stmt_expr.rs index e466ad69f72..6381bb2d588 100644 --- a/src/test/ui/cfg/cfg_stmt_expr.rs +++ b/src/test/ui/cfg/cfg_stmt_expr.rs @@ -57,7 +57,7 @@ fn main() { // check that macro expanded code works macro_rules! if_cfg { - ($cfg:meta $ib:block else $eb:block) => { + ($cfg:meta? $ib:block else $eb:block) => { { let r; #[cfg($cfg)] @@ -69,7 +69,7 @@ fn main() { } } - let n = if_cfg!(unset { + let n = if_cfg!(unset? { 413 } else { 612 diff --git a/src/test/ui/macros/macro-first-set.rs b/src/test/ui/macros/macro-first-set.rs index 34529cdaa64..eb2504d4bfd 100644 --- a/src/test/ui/macros/macro-first-set.rs +++ b/src/test/ui/macros/macro-first-set.rs @@ -252,12 +252,6 @@ test_path!(::std); test_path!(std::u8,); test_path!(any, super, super::super::self::path, X::Z<'a, T=U>); -macro_rules! test_meta_block { - ($($m:meta)* $b:block) => {}; -} - -test_meta_block!(windows {}); - macro_rules! test_lifetime { (1. $($l:lifetime)* $($b:block)*) => {}; (2. $($b:block)* $($l:lifetime)*) => {}; -- cgit 1.4.1-3-g733a5 From 6ea4a52f47f3f66f9db9004d8ed55a819dd81523 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 1 Oct 2019 00:58:30 +0300 Subject: Address review comments --- src/libsyntax/ast.rs | 1 + src/libsyntax/parse/attr.rs | 4 ++-- src/test/ui/macros/macro-meta-items-modern.rs | 11 +++++++++++ 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 src/test/ui/macros/macro-meta-items-modern.rs (limited to 'src/libsyntax/parse') diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index e2c8e37e11c..023952042e6 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -2156,6 +2156,7 @@ pub struct Attribute { pub span: Span, } +// Compatibility impl to avoid churn, consider removing. impl std::ops::Deref for Attribute { type Target = AttrItem; fn deref(&self) -> &Self::Target { &self.item } diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index f3298b6a65d..e74f3045db8 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -166,7 +166,7 @@ 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_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { let item = match self.token.kind { @@ -262,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 { diff --git a/src/test/ui/macros/macro-meta-items-modern.rs b/src/test/ui/macros/macro-meta-items-modern.rs new file mode 100644 index 00000000000..bc6938d4a6c --- /dev/null +++ b/src/test/ui/macros/macro-meta-items-modern.rs @@ -0,0 +1,11 @@ +// check-pass + +macro_rules! check { ($meta:meta) => () } + +check!(meta(a b c d)); +check!(meta[a b c d]); +check!(meta { a b c d }); +check!(meta); +check!(meta = 0); + +fn main() {} -- cgit 1.4.1-3-g733a5