Rework "inner attribute not permitted" errors
This commit is contained in:
parent
4d0519a4e7
commit
21b5194a3a
4 changed files with 87 additions and 59 deletions
|
@ -5,25 +5,23 @@ use rustc_ast as ast;
|
|||
use rustc_ast::attr;
|
||||
use rustc_ast::token::{self, Delimiter, Nonterminal};
|
||||
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 std::convert::TryInto;
|
||||
|
||||
// Public for rustfmt usage
|
||||
#[derive(Debug)]
|
||||
pub enum InnerAttrPolicy<'a> {
|
||||
pub enum InnerAttrPolicy {
|
||||
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 \
|
||||
permitted in this context";
|
||||
|
||||
pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden {
|
||||
reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
|
||||
saw_doc_comment: false,
|
||||
prev_outer_attr_sp: None,
|
||||
};
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum InnerAttrForbiddenReason {
|
||||
InCodeBlock,
|
||||
AfterOuterDocComment { prev_doc_comment_span: Span },
|
||||
AfterOuterAttribute { prev_outer_attr_sp: Span },
|
||||
}
|
||||
|
||||
enum OuterAttributeType {
|
||||
DocComment,
|
||||
|
@ -42,17 +40,15 @@ impl<'a> Parser<'a> {
|
|||
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 prev_outer_attr_sp.is_some() {
|
||||
"an inner attribute is not permitted following an outer attribute"
|
||||
Some(InnerAttrForbiddenReason::AfterOuterDocComment {
|
||||
prev_doc_comment_span: prev_outer_attr_sp.unwrap(),
|
||||
})
|
||||
} else if let Some(prev_outer_attr_sp) = prev_outer_attr_sp {
|
||||
Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp })
|
||||
} else {
|
||||
DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
|
||||
};
|
||||
let inner_parse_policy = InnerAttrPolicy::Forbidden {
|
||||
reason: inner_error_reason,
|
||||
saw_doc_comment: just_parsed_doc_comment,
|
||||
prev_outer_attr_sp,
|
||||
None
|
||||
};
|
||||
let inner_parse_policy = InnerAttrPolicy::Forbidden(inner_error_reason);
|
||||
just_parsed_doc_comment = false;
|
||||
Some(self.parse_attribute(inner_parse_policy)?)
|
||||
} 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 mut err = self.sess.span_diagnostic.struct_span_err_with_code(
|
||||
span,
|
||||
"expected outer doc comment",
|
||||
fluent::parser::inner_doc_comment_not_permitted,
|
||||
error_code!(E0753),
|
||||
);
|
||||
if let Some(replacement_span) = self.annotate_following_item_if_applicable(
|
||||
|
@ -71,13 +67,10 @@ impl<'a> Parser<'a> {
|
|||
token::CommentKind::Block => OuterAttributeType::DocBlockComment,
|
||||
},
|
||||
) {
|
||||
err.note(
|
||||
"inner doc comments like this (starting with `//!` or `/*!`) can \
|
||||
only appear before items",
|
||||
);
|
||||
err.note(fluent::parser::note);
|
||||
err.span_suggestion_verbose(
|
||||
replacement_span,
|
||||
"you might have meant to write a regular comment",
|
||||
fluent::parser::suggestion,
|
||||
"",
|
||||
rustc_errors::Applicability::MachineApplicable,
|
||||
);
|
||||
|
@ -115,7 +108,7 @@ impl<'a> Parser<'a> {
|
|||
// Public for rustfmt usage.
|
||||
pub fn parse_attribute(
|
||||
&mut self,
|
||||
inner_parse_policy: InnerAttrPolicy<'_>,
|
||||
inner_parse_policy: InnerAttrPolicy,
|
||||
) -> PResult<'a, ast::Attribute> {
|
||||
debug!(
|
||||
"parse_attribute: inner_parse_policy={:?} self.token={:?}",
|
||||
|
@ -179,21 +172,12 @@ impl<'a> Parser<'a> {
|
|||
ForceCollect::No,
|
||||
) {
|
||||
Ok(Some(item)) => {
|
||||
let attr_name = match attr_type {
|
||||
OuterAttributeType::Attribute => "attribute",
|
||||
_ => "doc comment",
|
||||
};
|
||||
err.span_label(
|
||||
item.span,
|
||||
&format!("the inner {} doesn't annotate this {}", attr_name, item.kind.descr()),
|
||||
);
|
||||
// FIXME(#100717)
|
||||
err.set_arg("item", item.kind.descr());
|
||||
err.span_label(item.span, fluent::parser::label_does_not_annotate_this);
|
||||
err.span_suggestion_verbose(
|
||||
replacement_span,
|
||||
&format!(
|
||||
"to annotate the {}, change the {} from inner to outer style",
|
||||
item.kind.descr(),
|
||||
attr_name
|
||||
),
|
||||
fluent::parser::sugg_change_inner_to_outer,
|
||||
match attr_type {
|
||||
OuterAttributeType::Attribute => "",
|
||||
OuterAttributeType::DocBlockComment => "*",
|
||||
|
@ -211,22 +195,33 @@ impl<'a> Parser<'a> {
|
|||
Some(replacement_span)
|
||||
}
|
||||
|
||||
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 {
|
||||
let prev_outer_attr_note =
|
||||
if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" };
|
||||
pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy) {
|
||||
if let InnerAttrPolicy::Forbidden(reason) = policy {
|
||||
let mut diag = match reason.as_ref().copied() {
|
||||
Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => {
|
||||
let mut diag = self.struct_span_err(
|
||||
attr_sp,
|
||||
fluent::parser::inner_attr_not_permitted_after_outer_doc_comment,
|
||||
);
|
||||
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)
|
||||
}
|
||||
};
|
||||
|
||||
let mut diag = self.struct_span_err(attr_sp, reason);
|
||||
|
||||
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.note(fluent::parser::inner_attr_explanation);
|
||||
if self
|
||||
.annotate_following_item_if_applicable(
|
||||
&mut diag,
|
||||
|
@ -235,7 +230,7 @@ impl<'a> Parser<'a> {
|
|||
)
|
||||
.is_some()
|
||||
{
|
||||
diag.note("outer attributes, like `#[test]`, annotate the item following them");
|
||||
diag.note(fluent::parser::outer_attr_explanation);
|
||||
};
|
||||
diag.emit();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN;
|
||||
use super::attr::InnerAttrForbiddenReason;
|
||||
use super::diagnostics::AttemptLocalParseRecovery;
|
||||
use super::expr::LhsExpr;
|
||||
use super::pat::RecoverComma;
|
||||
|
@ -399,7 +399,12 @@ impl<'a> Parser<'a> {
|
|||
pub(super) fn parse_block(&mut self) -> PResult<'a, P<Block>> {
|
||||
let (attrs, block) = self.parse_inner_attrs_and_block()?;
|
||||
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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue