Skip to content

Commit 8b3f28c

Browse files
committed
Make more informative error on outer attr after inner
1 parent 09e3989 commit 8b3f28c

File tree

2 files changed

+37
-17
lines changed

2 files changed

+37
-17
lines changed

src/libsyntax/parse/attr.rs

+32-15
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ use crate::parse::{SeqSep, PResult};
44
use crate::parse::token::{self, Nonterminal, DelimToken};
55
use crate::parse::parser::{Parser, TokenType, PathStyle};
66
use crate::tokenstream::{TokenStream, TokenTree};
7+
use crate::source_map::Span;
78

89
use log::debug;
910
use smallvec::smallvec;
1011

1112
#[derive(Debug)]
1213
enum InnerAttributeParsePolicy<'a> {
1314
Permitted,
14-
NotPermitted { reason: &'a str },
15+
NotPermitted { reason: &'a str, prev_attr_sp: Option<Span> },
1516
}
1617

1718
const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
@@ -42,7 +43,8 @@ impl<'a> Parser<'a> {
4243
DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
4344
};
4445
let inner_parse_policy =
45-
InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason };
46+
InnerAttributeParsePolicy::NotPermitted { reason: inner_error_reason,
47+
prev_attr_sp: attrs.last().and_then(|a| Some(a.span)) };
4648
let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
4749
attrs.push(attr);
4850
just_parsed_doc_comment = false;
@@ -77,7 +79,7 @@ impl<'a> Parser<'a> {
7779
InnerAttributeParsePolicy::Permitted
7880
} else {
7981
InnerAttributeParsePolicy::NotPermitted
80-
{ reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG }
82+
{ reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG, prev_attr_sp: None }
8183
};
8284
self.parse_attribute_with_inner_parse_policy(inner_parse_policy)
8385
}
@@ -98,19 +100,9 @@ impl<'a> Parser<'a> {
98100
if let InnerAttributeParsePolicy::Permitted = inner_parse_policy {
99101
self.expected_tokens.push(TokenType::Token(token::Not));
100102
}
103+
101104
let style = if self.token == token::Not {
102105
self.bump();
103-
if let InnerAttributeParsePolicy::NotPermitted { reason } = inner_parse_policy
104-
{
105-
let span = self.token.span;
106-
self.diagnostic()
107-
.struct_span_err(span, reason)
108-
.note("inner attributes, like `#![no_std]`, annotate the item \
109-
enclosing them, and are usually found at the beginning of \
110-
source files. Outer attributes, like `#[test]`, annotate the \
111-
item following them.")
112-
.emit()
113-
}
114106
ast::AttrStyle::Inner
115107
} else {
116108
ast::AttrStyle::Outer
@@ -121,7 +113,32 @@ impl<'a> Parser<'a> {
121113
self.expect(&token::CloseDelim(token::Bracket))?;
122114
let hi = self.prev_span;
123115

124-
(lo.to(hi), path, tokens, style)
116+
let attr_sp = lo.to(hi);
117+
118+
// Emit error if inner attribute is encountered and not permitted
119+
if style == ast::AttrStyle::Inner {
120+
if let InnerAttributeParsePolicy::NotPermitted { reason, prev_attr_sp }
121+
= inner_parse_policy {
122+
let mut diagnostic = self
123+
.diagnostic()
124+
.struct_span_err(attr_sp, reason);
125+
126+
if let Some(prev_attr_sp) = prev_attr_sp {
127+
diagnostic
128+
.span_label(attr_sp, "not permitted following an outer attibute")
129+
.span_label(prev_attr_sp, "previous outer attribute");
130+
}
131+
132+
diagnostic
133+
.note("inner attributes, like `#![no_std]`, annotate the item \
134+
enclosing them, and are usually found at the beginning of \
135+
source files. Outer attributes, like `#[test]`, annotate the \
136+
item following them.")
137+
.emit()
138+
}
139+
}
140+
141+
(attr_sp, path, tokens, style)
125142
}
126143
_ => {
127144
let token_str = self.this_token_to_string();

src/test/ui/parser/inner-attr.stderr

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
error: an inner attribute is not permitted following an outer attribute
2-
--> $DIR/inner-attr.rs:3:3
2+
--> $DIR/inner-attr.rs:3:1
33
|
4+
LL | #[feature(lang_items)]
5+
| ---------------------- previous outer attribute
6+
LL |
47
LL | #![recursion_limit="100"]
5-
| ^
8+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attibute
69
|
710
= 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.
811

0 commit comments

Comments
 (0)