Skip to content

Commit

Permalink
Rollup merge of rust-lang#63038 - eupn:outer-attribute-diag, r=estebank
Browse files Browse the repository at this point in the history
Make more informative error on outer attribute after inner

Fixes rust-lang#61218.

?r @estebank
  • Loading branch information
Centril committed Jul 28, 2019
2 parents c3c0309 + 693be44 commit 5c70085
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 25 deletions.
61 changes: 45 additions & 16 deletions src/libsyntax/parse/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ 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;

#[derive(Debug)]
enum InnerAttributeParsePolicy<'a> {
Permitted,
NotPermitted { reason: &'a str },
NotPermitted { 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 \
Expand Down Expand Up @@ -42,7 +43,11 @@ 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,
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;
Expand Down Expand Up @@ -76,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 }
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)
}
Expand All @@ -98,19 +106,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
Expand All @@ -121,7 +119,38 @@ 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,
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);

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, 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()
}
}

(attr_sp, path, tokens, style)
}
_ => {
let token_str = self.this_token_to_string();
Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/issues/issue-45296.stderr
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
4 changes: 2 additions & 2 deletions src/test/ui/parser/attr.stderr
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
11 changes: 8 additions & 3 deletions src/test/ui/parser/inner-attr-after-doc-comment.stderr
Original file line number Diff line number Diff line change
@@ -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.

Expand Down
7 changes: 5 additions & 2 deletions src/test/ui/parser/inner-attr.stderr
Original file line number Diff line number Diff line change
@@ -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.

Expand Down

0 comments on commit 5c70085

Please sign in to comment.