Stop flagging certain inner attrs as outer ones
This commit is contained in:
parent
201cf3dba3
commit
5ab0548500
@ -141,7 +141,7 @@ fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
|
||||
|
||||
fn make_items(mut self: Box<ExpandResult<'a>>) -> Option<SmallVec<[P<ast::Item>; 1]>> {
|
||||
let mut ret = SmallVec::new();
|
||||
while self.p.token != token::Eof {
|
||||
loop {
|
||||
match self.p.parse_item(ForceCollect::No) {
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
@ -149,9 +149,12 @@ fn make_expr(mut self: Box<ExpandResult<'a>>) -> Option<P<ast::Expr>> {
|
||||
}
|
||||
Ok(Some(item)) => ret.push(item),
|
||||
Ok(None) => {
|
||||
if self.p.token != token::Eof {
|
||||
let token = pprust::token_to_string(&self.p.token);
|
||||
let msg = format!("expected item, found `{}`", token);
|
||||
self.p.struct_span_err(self.p.token.span, &msg).emit();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@
|
||||
#[derive(Debug)]
|
||||
pub enum InnerAttrPolicy<'a> {
|
||||
Permitted,
|
||||
Forbidden { reason: &'a str, saw_doc_comment: bool, prev_attr_sp: Option<Span> },
|
||||
Forbidden { reason: &'a str, saw_doc_comment: bool, prev_outer_attr_sp: Option<Span> },
|
||||
}
|
||||
|
||||
const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
|
||||
@ -22,7 +22,7 @@ pub enum InnerAttrPolicy<'a> {
|
||||
pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden {
|
||||
reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
|
||||
saw_doc_comment: false,
|
||||
prev_attr_sp: None,
|
||||
prev_outer_attr_sp: None,
|
||||
};
|
||||
|
||||
enum OuterAttributeType {
|
||||
@ -34,14 +34,16 @@ enum OuterAttributeType {
|
||||
impl<'a> Parser<'a> {
|
||||
/// Parses attributes that appear before an item.
|
||||
pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
|
||||
let mut attrs: Vec<ast::Attribute> = Vec::new();
|
||||
let mut outer_attrs: Vec<ast::Attribute> = Vec::new();
|
||||
let mut just_parsed_doc_comment = false;
|
||||
let start_pos = self.token_cursor.num_next_calls;
|
||||
loop {
|
||||
let attr = if self.check(&token::Pound) {
|
||||
let prev_outer_attr_sp = outer_attrs.last().map(|attr| attr.span);
|
||||
|
||||
let inner_error_reason = if just_parsed_doc_comment {
|
||||
"an inner attribute is not permitted following an outer doc comment"
|
||||
} else if !attrs.is_empty() {
|
||||
} else if prev_outer_attr_sp.is_some() {
|
||||
"an inner attribute is not permitted following an outer attribute"
|
||||
} else {
|
||||
DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
|
||||
@ -49,7 +51,7 @@ pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
|
||||
let inner_parse_policy = InnerAttrPolicy::Forbidden {
|
||||
reason: inner_error_reason,
|
||||
saw_doc_comment: just_parsed_doc_comment,
|
||||
prev_attr_sp: attrs.last().map(|a| a.span),
|
||||
prev_outer_attr_sp,
|
||||
};
|
||||
just_parsed_doc_comment = false;
|
||||
Some(self.parse_attribute(inner_parse_policy)?)
|
||||
@ -97,12 +99,14 @@ pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> {
|
||||
};
|
||||
|
||||
if let Some(attr) = attr {
|
||||
attrs.push(attr);
|
||||
if attr.style == ast::AttrStyle::Outer {
|
||||
outer_attrs.push(attr);
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(AttrWrapper::new(attrs.into(), start_pos))
|
||||
Ok(AttrWrapper::new(outer_attrs.into(), start_pos))
|
||||
}
|
||||
|
||||
/// Matches `attribute = # ! [ meta_item ]`.
|
||||
@ -215,15 +219,15 @@ fn annotate_following_item_if_applicable(
|
||||
}
|
||||
|
||||
pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
|
||||
if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_attr_sp } = policy {
|
||||
let prev_attr_note =
|
||||
if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_outer_attr_sp } = policy {
|
||||
let prev_outer_attr_note =
|
||||
if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" };
|
||||
|
||||
let mut diag = self.struct_span_err(attr_sp, reason);
|
||||
|
||||
if let Some(prev_attr_sp) = prev_attr_sp {
|
||||
if let Some(prev_outer_attr_sp) = prev_outer_attr_sp {
|
||||
diag.span_label(attr_sp, "not permitted following an outer attribute")
|
||||
.span_label(prev_attr_sp, prev_attr_note);
|
||||
.span_label(prev_outer_attr_sp, prev_outer_attr_note);
|
||||
}
|
||||
|
||||
diag.note(
|
||||
|
@ -3,5 +3,4 @@
|
||||
fn main() {}
|
||||
|
||||
#![lang = "foo"] //~ ERROR an inner attribute is not permitted in this context
|
||||
//~| ERROR definition of an unknown language item: `foo`
|
||||
fn foo() {}
|
||||
|
@ -3,7 +3,6 @@ error: an inner attribute is not permitted in this context
|
||||
|
|
||||
LL | #![lang = "foo"]
|
||||
| ^^^^^^^^^^^^^^^^
|
||||
LL |
|
||||
LL | fn foo() {}
|
||||
| ----------- the inner attribute doesn't annotate this function
|
||||
|
|
||||
@ -14,12 +13,5 @@ LL - #![lang = "foo"]
|
||||
LL + #[lang = "foo"]
|
||||
|
|
||||
|
||||
error[E0522]: definition of an unknown language item: `foo`
|
||||
--> $DIR/attr.rs:5:1
|
||||
|
|
||||
LL | #![lang = "foo"]
|
||||
| ^^^^^^^^^^^^^^^^ definition of unknown language item `foo`
|
||||
error: aborting due to previous error
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0522`.
|
||||
|
3
src/test/ui/parser/issues/auxiliary/issue-94340-inc.rs
Normal file
3
src/test/ui/parser/issues/auxiliary/issue-94340-inc.rs
Normal file
@ -0,0 +1,3 @@
|
||||
// include file for issue-94340.rs
|
||||
#![deny(rust_2018_idioms)]
|
||||
#![deny(unused_must_use)]
|
8
src/test/ui/parser/issues/issue-94340.rs
Normal file
8
src/test/ui/parser/issues/issue-94340.rs
Normal file
@ -0,0 +1,8 @@
|
||||
// Make sure that unexpected inner attributes are not labeled as outer ones in diagnostics when
|
||||
// trying to parse an item and that they are subsequently ignored not triggering confusing extra
|
||||
// diagnostics like "expected item after attributes" which is not true for `include!` which can
|
||||
// include empty files.
|
||||
|
||||
include!("auxiliary/issue-94340-inc.rs");
|
||||
|
||||
fn main() {}
|
20
src/test/ui/parser/issues/issue-94340.stderr
Normal file
20
src/test/ui/parser/issues/issue-94340.stderr
Normal file
@ -0,0 +1,20 @@
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/auxiliary/issue-94340-inc.rs:2:1
|
||||
|
|
||||
LL | #![deny(rust_2018_idioms)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
|
||||
= note: outer attributes, like `#[test]`, annotate the item following them
|
||||
|
||||
error: an inner attribute is not permitted in this context
|
||||
--> $DIR/auxiliary/issue-94340-inc.rs:3:1
|
||||
|
|
||||
LL | #![deny(unused_must_use)]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
|
||||
= note: outer attributes, like `#[test]`, annotate the item following them
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
Loading…
Reference in New Issue
Block a user