Rework "inner attribute not permitted" errors

This commit is contained in:
Xiretza 2022-08-31 13:20:59 +02:00
parent 4d0519a4e7
commit 21b5194a3a
4 changed files with 87 additions and 59 deletions

View file

@ -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();
}

View file

@ -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)
}