about summary refs log tree commit diff
path: root/src/librustc_parse
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2020-03-05 11:42:56 +0100
committerMazdak Farrokhzad <twingoow@gmail.com>2020-03-10 08:35:23 +0100
commitaddbc5b9df3fca76e7c271a78a0568144b9634f9 (patch)
tree37cdc0d9a0c2335decc19820245ed2769592bea7 /src/librustc_parse
parentbe86b2d37be1631798688afbd45aa0d517135ad1 (diff)
downloadrust-addbc5b9df3fca76e7c271a78a0568144b9634f9.tar.gz
rust-addbc5b9df3fca76e7c271a78a0568144b9634f9.zip
unify/improve/simplify attribute parsing
Diffstat (limited to 'src/librustc_parse')
-rw-r--r--src/librustc_parse/parser/attr.rs223
-rw-r--r--src/librustc_parse/parser/stmt.rs11
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> {