From 8b3f28cf0f0cd30ddba884b10c395391ff22beb0 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 27 Jul 2019 16:45:45 +0700 Subject: [PATCH 1/4] 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 1758d0b0bb947..810af9b924636 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 11a37bc139b3c..070d9f47d96f9 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. From fc9bfd68b583852758d0a0f8ea67d5d5802f14d2 Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 27 Jul 2019 18:24:17 +0700 Subject: [PATCH 2/4] Treat doc comments separately --- src/libsyntax/parse/attr.rs | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/libsyntax/parse/attr.rs b/src/libsyntax/parse/attr.rs index 810af9b924636..af484c886ab35 100644 --- a/src/libsyntax/parse/attr.rs +++ b/src/libsyntax/parse/attr.rs @@ -12,7 +12,7 @@ use smallvec::smallvec; #[derive(Debug)] enum InnerAttributeParsePolicy<'a> { Permitted, - NotPermitted { reason: &'a str, prev_attr_sp: Option }, + NotPermitted { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option }, } const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \ @@ -43,8 +43,11 @@ impl<'a> Parser<'a> { DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }; let inner_parse_policy = - InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason, - prev_attr_sp: attrs.last().and_then(|a| Some(a.span)) }; + InnerAttributeParsePolicy::NotPermitted { + reason: inner_error_reason, + saw_doc_comment: just_parsed_doc_comment, + 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; @@ -78,8 +81,11 @@ impl<'a> Parser<'a> { let inner_parse_policy = if permit_inner { InnerAttributeParsePolicy::Permitted } else { - InnerAttributeParsePolicy::NotPermitted - { reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, prev_attr_sp: None } + InnerAttributeParsePolicy::NotPermitted { + reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, + saw_doc_comment: false, + prev_attr_sp: None + } }; self.parse_attribute_with_inner_parse_policy(inner_parse_policy) } @@ -117,8 +123,14 @@ impl<'a> Parser<'a> { // 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 { + 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 .diagnostic() .struct_span_err(attr_sp, reason); @@ -126,7 +138,7 @@ impl<'a> Parser<'a> { 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"); + .span_label(prev_attr_sp, prev_attr_note); } diagnostic From 2787cb23f0f3178f5eae11d571ee5e026b79d7fb Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 27 Jul 2019 18:24:48 +0700 Subject: [PATCH 3/4] Fix failing UI tests --- src/test/ui/issues/issue-45296.stderr | 4 ++-- .../ui/parser/inner-attr-after-doc-comment.stderr | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/test/ui/issues/issue-45296.stderr b/src/test/ui/issues/issue-45296.stderr index bc14d20b62388..c0d4ce1243e01 100644 --- a/src/test/ui/issues/issue-45296.stderr +++ b/src/test/ui/issues/issue-45296.stderr @@ -1,8 +1,8 @@ error: an inner attribute is not permitted in this context - --> $DIR/issue-45296.rs:4:7 + --> $DIR/issue-45296.rs:4:5 | LL | #![allow(unused_variables)] - | ^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = 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. diff --git a/src/test/ui/parser/inner-attr-after-doc-comment.stderr b/src/test/ui/parser/inner-attr-after-doc-comment.stderr index 0dde49a2913f1..b012abc25e7f3 100644 --- a/src/test/ui/parser/inner-attr-after-doc-comment.stderr +++ b/src/test/ui/parser/inner-attr-after-doc-comment.stderr @@ -1,8 +1,13 @@ error: an inner attribute is not permitted following an outer doc comment - --> $DIR/inner-attr-after-doc-comment.rs:6:3 + --> $DIR/inner-attr-after-doc-comment.rs:6:1 | -LL | #![recursion_limit="100"] - | ^ +LL | / /** +LL | | * My module +LL | | */ + | |___- previous doc comment +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. From 693be441f4c2d74805b855612556c54438c3022c Mon Sep 17 00:00:00 2001 From: Evgenii P Date: Sat, 27 Jul 2019 19:35:55 +0700 Subject: [PATCH 4/4] Fix ui/parser/attr test --- src/test/ui/parser/attr.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/ui/parser/attr.stderr b/src/test/ui/parser/attr.stderr index 5111b40603c49..400a0276b3b60 100644 --- a/src/test/ui/parser/attr.stderr +++ b/src/test/ui/parser/attr.stderr @@ -1,8 +1,8 @@ error: an inner attribute is not permitted in this context - --> $DIR/attr.rs:5:3 + --> $DIR/attr.rs:5:1 | LL | #![lang = "foo"] - | ^ + | ^^^^^^^^^^^^^^^^ | = 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.