From 8b3f28cf0f0cd30ddba884b10c395391ff22beb0 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 27 Jul 2019 16:45:45 +0700 Subject: [PATCH] Make more informative error on outer attr after inner --- src/libsyntax/parse/attr.rs | 47 +++++++++++++++++++--------- src/test/ui/parser/inner-attr.stderr | 7 +++-- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 1758d0b0bb94..810af9b92463 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 }, } 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(); diff --git a/src/test/ui/parser/inner-attr.stderr b/src/test/ui/parser/inner-attr.stderr index 11a37bc139b3..070d9f47d96f 100644 --- a/src/test/ui/parser/inner-attr.stderr +++ b/src/test/ui/parser/inner-attr.stderr @@ -1,8 +1,11 @@ error: an inner attribute is not permitted following an outer attribute - --> $DIR/inner-attr.rs:3:3 + --> $DIR/inner-attr.rs:3:1 | +LL | #[feature(lang_items)] + | ---------------------- previous outer attribute +LL | LL | #![recursion_limit="100"] - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attibute | = 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.