diff options
| author | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-03-05 11:42:56 +0100 |
|---|---|---|
| committer | Mazdak Farrokhzad <twingoow@gmail.com> | 2020-03-10 08:35:23 +0100 |
| commit | addbc5b9df3fca76e7c271a78a0568144b9634f9 (patch) | |
| tree | 37cdc0d9a0c2335decc19820245ed2769592bea7 /src/librustc_parse/parser | |
| parent | be86b2d37be1631798688afbd45aa0d517135ad1 (diff) | |
| download | rust-addbc5b9df3fca76e7c271a78a0568144b9634f9.tar.gz rust-addbc5b9df3fca76e7c271a78a0568144b9634f9.zip | |
unify/improve/simplify attribute parsing
Diffstat (limited to 'src/librustc_parse/parser')
| -rw-r--r-- | src/librustc_parse/parser/attr.rs | 223 | ||||
| -rw-r--r-- | src/librustc_parse/parser/stmt.rs | 11 |
2 files changed, 102 insertions, 132 deletions
diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index 1e7f5b662f3..b5af124fd42 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -1,4 +1,4 @@ -use super::{Parser, PathStyle, TokenType}; +use super::{Parser, PathStyle}; use rustc_ast::ast; use rustc_ast::attr; use rustc_ast::token::{self, Nonterminal}; @@ -10,14 +10,20 @@ use rustc_span::{Span, Symbol}; use log::debug; #[derive(Debug)] -enum InnerAttributeParsePolicy<'a> { +pub(super) enum InnerAttrPolicy<'a> { Permitted, - NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> }, + Forbidden { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> }, } const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ permitted in this context"; +pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden { + reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, + saw_doc_comment: false, + prev_attr_sp: None, +}; + impl<'a> Parser<'a> { /// Parses attributes that appear before an item. pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> { @@ -25,48 +31,44 @@ impl<'a> Parser<'a> { let mut just_parsed_doc_comment = false; loop { debug!("parse_outer_attributes: self.token={:?}", self.token); - match self.token.kind { - token::Pound => { - let inner_error_reason = if just_parsed_doc_comment { - "an inner attribute is not permitted following an outer doc comment" - } else if !attrs.is_empty() { - "an inner attribute is not permitted following an outer attribute" - } else { - DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG - }; - let inner_parse_policy = InnerAttributeParsePolicy::NotPermitted { - reason: inner_error_reason, - saw_doc_comment: just_parsed_doc_comment, - prev_attr_sp: attrs.last().map(|a| a.span), - }; - let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; - attrs.push(attr); - just_parsed_doc_comment = false; - } - token::DocComment(s) => { - let attr = self.mk_doc_comment(s); - if attr.style != ast::AttrStyle::Outer { - let span = self.token.span; - let mut err = self.struct_span_err(span, "expected outer doc comment"); - err.note( + if self.check(&token::Pound) { + let inner_error_reason = if just_parsed_doc_comment { + "an inner attribute is not permitted following an outer doc comment" + } else if !attrs.is_empty() { + "an inner attribute is not permitted following an outer attribute" + } else { + DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG + }; + let inner_parse_policy = InnerAttrPolicy::Forbidden { + reason: inner_error_reason, + saw_doc_comment: just_parsed_doc_comment, + prev_attr_sp: attrs.last().map(|a| a.span), + }; + let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?; + attrs.push(attr); + just_parsed_doc_comment = false; + } else if let token::DocComment(s) = self.token.kind { + let attr = self.mk_doc_comment(s); + if attr.style != ast::AttrStyle::Outer { + self.struct_span_err(self.token.span, "expected outer doc comment") + .note( "inner doc comments like this (starting with \ - `//!` or `/*!`) can only appear before items", - ); - return Err(err); - } - attrs.push(attr); - self.bump(); - just_parsed_doc_comment = true; + `//!` or `/*!`) can only appear before items", + ) + .emit(); } - _ => break, + attrs.push(attr); + self.bump(); + just_parsed_doc_comment = true; + } else { + break; } } Ok(attrs) } fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute { - let style = comments::doc_comment_style(&s.as_str()); - attr::mk_doc_comment(style, s, self.token.span) + attr::mk_doc_comment(comments::doc_comment_style(&s.as_str()), s, self.token.span) } /// Matches `attribute = # ! [ meta_item ]`. @@ -75,96 +77,68 @@ impl<'a> Parser<'a> { /// attribute. pub fn parse_attribute(&mut self, permit_inner: bool) -> PResult<'a, ast::Attribute> { debug!("parse_attribute: permit_inner={:?} self.token={:?}", permit_inner, self.token); - let inner_parse_policy = if permit_inner { - InnerAttributeParsePolicy::Permitted - } else { - InnerAttributeParsePolicy::NotPermitted { - reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, - saw_doc_comment: false, - prev_attr_sp: None, - } - }; + let inner_parse_policy = + if permit_inner { InnerAttrPolicy::Permitted } else { DEFAULT_INNER_ATTR_FORBIDDEN }; self.parse_attribute_with_inner_parse_policy(inner_parse_policy) } - /// The same as `parse_attribute`, except it takes in an `InnerAttributeParsePolicy` + /// The same as `parse_attribute`, except it takes in an `InnerAttrPolicy` /// that prescribes how to handle inner attributes. fn parse_attribute_with_inner_parse_policy( &mut self, - inner_parse_policy: InnerAttributeParsePolicy<'_>, + inner_parse_policy: InnerAttrPolicy<'_>, ) -> PResult<'a, ast::Attribute> { debug!( "parse_attribute_with_inner_parse_policy: inner_parse_policy={:?} self.token={:?}", inner_parse_policy, self.token ); - let (span, item, style) = match self.token.kind { - token::Pound => { - let lo = self.token.span; - self.bump(); - - if let InnerAttributeParsePolicy::Permitted = inner_parse_policy { - self.expected_tokens.push(TokenType::Token(token::Not)); - } - - let style = if self.token == token::Not { - self.bump(); - ast::AttrStyle::Inner - } else { - ast::AttrStyle::Outer - }; + let lo = self.token.span; + let (span, item, style) = if self.eat(&token::Pound) { + let style = + if self.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer }; - self.expect(&token::OpenDelim(token::Bracket))?; - let item = self.parse_attr_item()?; - self.expect(&token::CloseDelim(token::Bracket))?; - let hi = self.prev_token.span; - - let attr_sp = lo.to(hi); - - // Emit error if inner attribute is encountered and not permitted - if style == ast::AttrStyle::Inner { - if let InnerAttributeParsePolicy::NotPermitted { - reason, - saw_doc_comment, - prev_attr_sp, - } = inner_parse_policy - { - let prev_attr_note = if saw_doc_comment { - "previous doc comment" - } else { - "previous outer attribute" - }; - - let mut diagnostic = self.struct_span_err(attr_sp, reason); - - if let Some(prev_attr_sp) = prev_attr_sp { - diagnostic - .span_label(attr_sp, "not permitted following an outer attribute") - .span_label(prev_attr_sp, prev_attr_note); - } - - diagnostic - .note( - "inner attributes, like `#![no_std]`, annotate the item \ - enclosing them, and are usually found at the beginning of \ - source files. Outer attributes, like `#[test]`, annotate the \ - item following them.", - ) - .emit(); - } - } + self.expect(&token::OpenDelim(token::Bracket))?; + let item = self.parse_attr_item()?; + self.expect(&token::CloseDelim(token::Bracket))?; + let attr_sp = lo.to(self.prev_token.span); - (attr_sp, item, style) - } - _ => { - let token_str = pprust::token_to_string(&self.token); - let msg = &format!("expected `#`, found `{}`", token_str); - return Err(self.struct_span_err(self.token.span, msg)); + // Emit error if inner attribute is encountered and forbidden. + if style == ast::AttrStyle::Inner { + self.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy); } + + (attr_sp, item, style) + } else { + let token_str = pprust::token_to_string(&self.token); + let msg = &format!("expected `#`, found `{}`", token_str); + return Err(self.struct_span_err(self.token.span, msg)); }; Ok(attr::mk_attr_from_item(style, item, span)) } + pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) { + if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy { + let prev_attr_note = + if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" }; + + let mut diag = self.struct_span_err(attr_sp, reason); + + if let Some(prev_attr_sp) = prev_attr_sp { + diag.span_label(attr_sp, "not permitted following an outer attribute") + .span_label(prev_attr_sp, prev_attr_note); + } + + diag.note( + "inner attributes, like `#![no_std]`, annotate the item \ + enclosing them, and are usually found at the beginning of \ + source files. Outer attributes, like `#[test]`, annotate the \ + item following them.", + ) + .emit(); + } + } + /// Parses an inner part of an attribute (the path and following tokens). /// The tokens must be either a delimited token stream, or empty token stream, /// or the "legacy" key-value form. @@ -200,24 +174,22 @@ impl<'a> Parser<'a> { crate fn parse_inner_attributes(&mut self) -> PResult<'a, Vec<ast::Attribute>> { let mut attrs: Vec<ast::Attribute> = vec![]; loop { - match self.token.kind { - // Only try to parse if it is an inner attribute (has `!`). - token::Pound if self.look_ahead(1, |t| t == &token::Not) => { - let attr = self.parse_attribute(true)?; - assert_eq!(attr.style, ast::AttrStyle::Inner); + // Only try to parse if it is an inner attribute (has `!`). + if self.check(&token::Pound) && self.look_ahead(1, |t| t == &token::Not) { + let attr = self.parse_attribute(true)?; + assert_eq!(attr.style, ast::AttrStyle::Inner); + attrs.push(attr); + } else if let token::DocComment(s) = self.token.kind { + // We need to get the position of this token before we bump. + let attr = self.mk_doc_comment(s); + if attr.style == ast::AttrStyle::Inner { attrs.push(attr); + self.bump(); + } else { + break; } - token::DocComment(s) => { - // We need to get the position of this token before we bump. - let attr = self.mk_doc_comment(s); - if attr.style == ast::AttrStyle::Inner { - attrs.push(attr); - self.bump(); - } else { - break; - } - } - _ => break, + } else { + break; } } Ok(attrs) @@ -228,8 +200,7 @@ impl<'a> Parser<'a> { debug!("checking if {:?} is unusuffixed", lit); if !lit.kind.is_unsuffixed() { - let msg = "suffixed literals are not allowed in attributes"; - self.struct_span_err(lit.span, msg) + self.struct_span_err(lit.span, "suffixed literals are not allowed in attributes") .help( "instead of using a suffixed literal \ (`1u8`, `1.0f32`, etc.), use an unsuffixed version \ diff --git a/src/librustc_parse/parser/stmt.rs b/src/librustc_parse/parser/stmt.rs index f05b08c5b55..036e8a5d258 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/src/librustc_parse/parser/stmt.rs @@ -1,3 +1,4 @@ +use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN; use super::diagnostics::Error; use super::expr::LhsExpr; use super::pat::GateOr; @@ -238,13 +239,11 @@ impl<'a> Parser<'a> { /// Parses a block. No inner attributes are allowed. pub fn parse_block(&mut self) -> PResult<'a, P<Block>> { - maybe_whole!(self, NtBlock, |x| x); - - if !self.eat(&token::OpenDelim(token::Brace)) { - return self.error_block_no_opening_brace(); + let (attrs, block) = self.parse_inner_attrs_and_block()?; + if let [.., last] = &*attrs { + self.error_on_forbidden_inner_attr(last.span, DEFAULT_INNER_ATTR_FORBIDDEN); } - - self.parse_block_tail(self.prev_token.span, BlockCheckMode::Default) + Ok(block) } fn error_block_no_opening_brace<T>(&mut self) -> PResult<'a, T> { |
