Rework "inner attribute not permitted" errors
This commit is contained in:
parent
4d0519a4e7
commit
21b5194a3a
4 changed files with 87 additions and 59 deletions
|
@ -262,3 +262,31 @@ parser_suffixed_literal_in_attribute = suffixed literals are not allowed in attr
|
||||||
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
|
||||||
|
|
||||||
parser_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
|
parser_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
|
||||||
|
|
||||||
|
parser_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item}
|
||||||
|
parser_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style
|
||||||
|
|
||||||
|
parser_inner_attr_not_permitted_after_outer_doc_comment = an inner attribute is not permitted following an outer doc comment
|
||||||
|
.label_attr = not permitted following an outer doc comment
|
||||||
|
.label_prev_doc_comment = previous doc comment
|
||||||
|
.label_does_not_annotate_this = {parser_label_inner_attr_does_not_annotate_this}
|
||||||
|
.sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
|
||||||
|
|
||||||
|
parser_inner_attr_not_permitted_after_outer_attr = an inner attribute is not permitted following an outer attribute
|
||||||
|
.label_attr = not permitted following an outer attribute
|
||||||
|
.label_prev_attr = previous outer attribute
|
||||||
|
.label_does_not_annotate_this = {parser_label_inner_attr_does_not_annotate_this}
|
||||||
|
.sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
|
||||||
|
|
||||||
|
parser_inner_attr_not_permitted = an inner attribute is not permitted in this context
|
||||||
|
.label_does_not_annotate_this = {parser_label_inner_attr_does_not_annotate_this}
|
||||||
|
.sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
|
||||||
|
|
||||||
|
parser_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
|
||||||
|
parser_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them
|
||||||
|
|
||||||
|
parser_inner_doc_comment_not_permitted = expected outer doc comment
|
||||||
|
.note = inner doc comments like this (starting with `//!` or `/*!`) can only appear before items
|
||||||
|
.suggestion = you might have meant to write a regular comment
|
||||||
|
.label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item}
|
||||||
|
.sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style
|
||||||
|
|
|
@ -5,25 +5,23 @@ use rustc_ast as ast;
|
||||||
use rustc_ast::attr;
|
use rustc_ast::attr;
|
||||||
use rustc_ast::token::{self, Delimiter, Nonterminal};
|
use rustc_ast::token::{self, Delimiter, Nonterminal};
|
||||||
use rustc_ast_pretty::pprust;
|
use rustc_ast_pretty::pprust;
|
||||||
use rustc_errors::{error_code, Diagnostic, IntoDiagnostic, PResult};
|
use rustc_errors::{error_code, fluent, Diagnostic, IntoDiagnostic, PResult};
|
||||||
use rustc_span::{sym, BytePos, Span};
|
use rustc_span::{sym, BytePos, Span};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
// Public for rustfmt usage
|
// Public for rustfmt usage
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum InnerAttrPolicy<'a> {
|
pub enum InnerAttrPolicy {
|
||||||
Permitted,
|
Permitted,
|
||||||
Forbidden { reason: &'a str, saw_doc_comment: bool, prev_outer_attr_sp: Option<Span> },
|
Forbidden(Option<InnerAttrForbiddenReason>),
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
|
#[derive(Clone, Copy, Debug)]
|
||||||
permitted in this context";
|
pub enum InnerAttrForbiddenReason {
|
||||||
|
InCodeBlock,
|
||||||
pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden {
|
AfterOuterDocComment { prev_doc_comment_span: Span },
|
||||||
reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
|
AfterOuterAttribute { prev_outer_attr_sp: Span },
|
||||||
saw_doc_comment: false,
|
}
|
||||||
prev_outer_attr_sp: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum OuterAttributeType {
|
enum OuterAttributeType {
|
||||||
DocComment,
|
DocComment,
|
||||||
|
@ -42,17 +40,15 @@ impl<'a> Parser<'a> {
|
||||||
let prev_outer_attr_sp = outer_attrs.last().map(|attr| attr.span);
|
let prev_outer_attr_sp = outer_attrs.last().map(|attr| attr.span);
|
||||||
|
|
||||||
let inner_error_reason = if just_parsed_doc_comment {
|
let inner_error_reason = if just_parsed_doc_comment {
|
||||||
"an inner attribute is not permitted following an outer doc comment"
|
Some(InnerAttrForbiddenReason::AfterOuterDocComment {
|
||||||
} else if prev_outer_attr_sp.is_some() {
|
prev_doc_comment_span: prev_outer_attr_sp.unwrap(),
|
||||||
"an inner attribute is not permitted following an outer attribute"
|
})
|
||||||
|
} else if let Some(prev_outer_attr_sp) = prev_outer_attr_sp {
|
||||||
|
Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp })
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
|
None
|
||||||
};
|
|
||||||
let inner_parse_policy = InnerAttrPolicy::Forbidden {
|
|
||||||
reason: inner_error_reason,
|
|
||||||
saw_doc_comment: just_parsed_doc_comment,
|
|
||||||
prev_outer_attr_sp,
|
|
||||||
};
|
};
|
||||||
|
let inner_parse_policy = InnerAttrPolicy::Forbidden(inner_error_reason);
|
||||||
just_parsed_doc_comment = false;
|
just_parsed_doc_comment = false;
|
||||||
Some(self.parse_attribute(inner_parse_policy)?)
|
Some(self.parse_attribute(inner_parse_policy)?)
|
||||||
} else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
|
} else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
|
||||||
|
@ -60,7 +56,7 @@ impl<'a> Parser<'a> {
|
||||||
let span = self.token.span;
|
let span = self.token.span;
|
||||||
let mut err = self.sess.span_diagnostic.struct_span_err_with_code(
|
let mut err = self.sess.span_diagnostic.struct_span_err_with_code(
|
||||||
span,
|
span,
|
||||||
"expected outer doc comment",
|
fluent::parser::inner_doc_comment_not_permitted,
|
||||||
error_code!(E0753),
|
error_code!(E0753),
|
||||||
);
|
);
|
||||||
if let Some(replacement_span) = self.annotate_following_item_if_applicable(
|
if let Some(replacement_span) = self.annotate_following_item_if_applicable(
|
||||||
|
@ -71,13 +67,10 @@ impl<'a> Parser<'a> {
|
||||||
token::CommentKind::Block => OuterAttributeType::DocBlockComment,
|
token::CommentKind::Block => OuterAttributeType::DocBlockComment,
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
err.note(
|
err.note(fluent::parser::note);
|
||||||
"inner doc comments like this (starting with `//!` or `/*!`) can \
|
|
||||||
only appear before items",
|
|
||||||
);
|
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
replacement_span,
|
replacement_span,
|
||||||
"you might have meant to write a regular comment",
|
fluent::parser::suggestion,
|
||||||
"",
|
"",
|
||||||
rustc_errors::Applicability::MachineApplicable,
|
rustc_errors::Applicability::MachineApplicable,
|
||||||
);
|
);
|
||||||
|
@ -115,7 +108,7 @@ impl<'a> Parser<'a> {
|
||||||
// Public for rustfmt usage.
|
// Public for rustfmt usage.
|
||||||
pub fn parse_attribute(
|
pub fn parse_attribute(
|
||||||
&mut self,
|
&mut self,
|
||||||
inner_parse_policy: InnerAttrPolicy<'_>,
|
inner_parse_policy: InnerAttrPolicy,
|
||||||
) -> PResult<'a, ast::Attribute> {
|
) -> PResult<'a, ast::Attribute> {
|
||||||
debug!(
|
debug!(
|
||||||
"parse_attribute: inner_parse_policy={:?} self.token={:?}",
|
"parse_attribute: inner_parse_policy={:?} self.token={:?}",
|
||||||
|
@ -179,21 +172,12 @@ impl<'a> Parser<'a> {
|
||||||
ForceCollect::No,
|
ForceCollect::No,
|
||||||
) {
|
) {
|
||||||
Ok(Some(item)) => {
|
Ok(Some(item)) => {
|
||||||
let attr_name = match attr_type {
|
// FIXME(#100717)
|
||||||
OuterAttributeType::Attribute => "attribute",
|
err.set_arg("item", item.kind.descr());
|
||||||
_ => "doc comment",
|
err.span_label(item.span, fluent::parser::label_does_not_annotate_this);
|
||||||
};
|
|
||||||
err.span_label(
|
|
||||||
item.span,
|
|
||||||
&format!("the inner {} doesn't annotate this {}", attr_name, item.kind.descr()),
|
|
||||||
);
|
|
||||||
err.span_suggestion_verbose(
|
err.span_suggestion_verbose(
|
||||||
replacement_span,
|
replacement_span,
|
||||||
&format!(
|
fluent::parser::sugg_change_inner_to_outer,
|
||||||
"to annotate the {}, change the {} from inner to outer style",
|
|
||||||
item.kind.descr(),
|
|
||||||
attr_name
|
|
||||||
),
|
|
||||||
match attr_type {
|
match attr_type {
|
||||||
OuterAttributeType::Attribute => "",
|
OuterAttributeType::Attribute => "",
|
||||||
OuterAttributeType::DocBlockComment => "*",
|
OuterAttributeType::DocBlockComment => "*",
|
||||||
|
@ -211,22 +195,33 @@ impl<'a> Parser<'a> {
|
||||||
Some(replacement_span)
|
Some(replacement_span)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
|
pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy) {
|
||||||
if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_outer_attr_sp } = policy {
|
if let InnerAttrPolicy::Forbidden(reason) = policy {
|
||||||
let prev_outer_attr_note =
|
let mut diag = match reason.as_ref().copied() {
|
||||||
if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" };
|
Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => {
|
||||||
|
let mut diag = self.struct_span_err(
|
||||||
let mut diag = self.struct_span_err(attr_sp, reason);
|
attr_sp,
|
||||||
|
fluent::parser::inner_attr_not_permitted_after_outer_doc_comment,
|
||||||
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_outer_attr_sp, prev_outer_attr_note);
|
|
||||||
}
|
|
||||||
|
|
||||||
diag.note(
|
|
||||||
"inner attributes, like `#![no_std]`, annotate the item enclosing them, and \
|
|
||||||
are usually found at the beginning of source files",
|
|
||||||
);
|
);
|
||||||
|
diag.span_label(attr_sp, fluent::parser::label_attr)
|
||||||
|
.span_label(prev_doc_comment_span, fluent::parser::label_prev_doc_comment);
|
||||||
|
diag
|
||||||
|
}
|
||||||
|
Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => {
|
||||||
|
let mut diag = self.struct_span_err(
|
||||||
|
attr_sp,
|
||||||
|
fluent::parser::inner_attr_not_permitted_after_outer_attr,
|
||||||
|
);
|
||||||
|
diag.span_label(attr_sp, fluent::parser::label_attr)
|
||||||
|
.span_label(prev_outer_attr_sp, fluent::parser::label_prev_attr);
|
||||||
|
diag
|
||||||
|
}
|
||||||
|
Some(InnerAttrForbiddenReason::InCodeBlock) | None => {
|
||||||
|
self.struct_span_err(attr_sp, fluent::parser::inner_attr_not_permitted)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
diag.note(fluent::parser::inner_attr_explanation);
|
||||||
if self
|
if self
|
||||||
.annotate_following_item_if_applicable(
|
.annotate_following_item_if_applicable(
|
||||||
&mut diag,
|
&mut diag,
|
||||||
|
@ -235,7 +230,7 @@ impl<'a> Parser<'a> {
|
||||||
)
|
)
|
||||||
.is_some()
|
.is_some()
|
||||||
{
|
{
|
||||||
diag.note("outer attributes, like `#[test]`, annotate the item following them");
|
diag.note(fluent::parser::outer_attr_explanation);
|
||||||
};
|
};
|
||||||
diag.emit();
|
diag.emit();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN;
|
use super::attr::InnerAttrForbiddenReason;
|
||||||
use super::diagnostics::AttemptLocalParseRecovery;
|
use super::diagnostics::AttemptLocalParseRecovery;
|
||||||
use super::expr::LhsExpr;
|
use super::expr::LhsExpr;
|
||||||
use super::pat::RecoverComma;
|
use super::pat::RecoverComma;
|
||||||
|
@ -399,7 +399,12 @@ impl<'a> Parser<'a> {
|
||||||
pub(super) fn parse_block(&mut self) -> PResult<'a, P<Block>> {
|
pub(super) fn parse_block(&mut self) -> PResult<'a, P<Block>> {
|
||||||
let (attrs, block) = self.parse_inner_attrs_and_block()?;
|
let (attrs, block) = self.parse_inner_attrs_and_block()?;
|
||||||
if let [.., last] = &*attrs {
|
if let [.., last] = &*attrs {
|
||||||
self.error_on_forbidden_inner_attr(last.span, DEFAULT_INNER_ATTR_FORBIDDEN);
|
self.error_on_forbidden_inner_attr(
|
||||||
|
last.span,
|
||||||
|
super::attr::InnerAttrPolicy::Forbidden(Some(
|
||||||
|
InnerAttrForbiddenReason::InCodeBlock,
|
||||||
|
)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Ok(block)
|
Ok(block)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ LL | | */
|
||||||
| |___- previous doc comment
|
| |___- previous doc comment
|
||||||
LL |
|
LL |
|
||||||
LL | #![recursion_limit="100"]
|
LL | #![recursion_limit="100"]
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attribute
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer doc comment
|
||||||
LL |
|
LL |
|
||||||
LL | fn main() {}
|
LL | fn main() {}
|
||||||
| ------------ the inner attribute doesn't annotate this function
|
| ------------ the inner attribute doesn't annotate this function
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue