about summary refs log tree commit diff
path: root/src/libsyntax/parse
diff options
context:
space:
mode:
authorEvgenii P <eupn@protonmail.com>2019-07-27 16:45:45 +0700
committerEvgenii P <eupn@protonmail.com>2019-07-27 16:45:45 +0700
commit8b3f28cf0f0cd30ddba884b10c395391ff22beb0 (patch)
treec8de41030f1589d084cd3deeaa1aebddb5a2bf6c /src/libsyntax/parse
parent09e39897587dca70f0b15093d425a682c392349c (diff)
downloadrust-8b3f28cf0f0cd30ddba884b10c395391ff22beb0.tar.gz
rust-8b3f28cf0f0cd30ddba884b10c395391ff22beb0.zip
Make more informative error on outer attr after inner
Diffstat (limited to 'src/libsyntax/parse')
-rw-r--r--src/libsyntax/parse/attr.rs47
1 files changed, 32 insertions, 15 deletions
diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs
index 1758d0b0bb9..810af9b9246 100644
--- a/src/libsyntax/parse/attr.rs
+++ b/src/libsyntax/parse/attr.rs
@@ -4,6 +4,7 @@ use crate::parse::{SeqSep, PResult};
 use crate::parse::token::{self, Nonterminal, DelimToken};
 use crate::parse::parser::{Parser, TokenType, PathStyle};
 use crate::tokenstream::{TokenStream, TokenTree};
+use crate::source_map::Span;
 
 use log::debug;
 use smallvec::smallvec;
@@ -11,7 +12,7 @@ use smallvec::smallvec;
 #[derive(Debug)]
 enum InnerAttributeParsePolicy<'a> {
     Permitted,
-    NotPermitted { reason: &'a str },
+    NotPermitted { reason: &'a str, prev_attr_sp: Option<Span> },
 }
 
 const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
@@ -42,7 +43,8 @@ impl<'a> Parser<'a> {
                         DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
                     };
                     let inner_parse_policy =
-                        InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason };
+                        InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason,
+                            prev_attr_sp: attrs.last().and_then(|a| Some(a.span)) };
                     let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
                     attrs.push(attr);
                     just_parsed_doc_comment = false;
@@ -77,7 +79,7 @@ impl<'a> Parser<'a> {
             InnerAttributeParsePolicy::Permitted
         } else {
             InnerAttributeParsePolicy::NotPermitted
-                { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }
+                { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, prev_attr_sp: None }
         };
         self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
     }
@@ -98,19 +100,9 @@ impl<'a> Parser<'a> {
                 if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
                     self.expected_tokens.push(TokenType::Token(token::Not));
                 }
+
                 let style = if self.token == token::Not {
                     self.bump();
-                    if let InnerAttributeParsePolicy::NotPermitted { reason } = inner_parse_policy
-                    {
-                        let span = self.token.span;
-                        self.diagnostic()
-                            .struct_span_err(span, reason)
-                            .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()
-                    }
                     ast::AttrStyle::Inner
                 } else {
                     ast::AttrStyle::Outer
@@ -121,7 +113,32 @@ impl<'a> Parser<'a> {
                 self.expect(&token::CloseDelim(token::Bracket))?;
                 let hi = self.prev_span;
 
-                (lo.to(hi), path, tokens, style)
+                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, prev_attr_sp }
+                            = inner_parse_policy {
+                        let mut diagnostic = self
+                            .diagnostic()
+                            .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 attibute")
+                                .span_label(prev_attr_sp, "previous outer attribute");
+                        }
+
+                        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()
+                    }
+                }
+
+                (attr_sp, path, tokens, style)
             }
             _ => {
                 let token_str = self.this_token_to_string();