Skip to content

Commit 21b5194

Browse files
committed
Rework "inner attribute not permitted" errors
1 parent 4d0519a commit 21b5194

File tree

4 files changed

+87
-59
lines changed

4 files changed

+87
-59
lines changed

compiler/rustc_error_messages/locales/en-US/parser.ftl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,3 +262,31 @@ parser_suffixed_literal_in_attribute = suffixed literals are not allowed in attr
262262
.help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
263263
264264
parser_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
265+
266+
parser_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item}
267+
parser_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style
268+
269+
parser_inner_attr_not_permitted_after_outer_doc_comment = an inner attribute is not permitted following an outer doc comment
270+
.label_attr = not permitted following an outer doc comment
271+
.label_prev_doc_comment = previous doc comment
272+
.label_does_not_annotate_this = {parser_label_inner_attr_does_not_annotate_this}
273+
.sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
274+
275+
parser_inner_attr_not_permitted_after_outer_attr = an inner attribute is not permitted following an outer attribute
276+
.label_attr = not permitted following an outer attribute
277+
.label_prev_attr = previous outer attribute
278+
.label_does_not_annotate_this = {parser_label_inner_attr_does_not_annotate_this}
279+
.sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
280+
281+
parser_inner_attr_not_permitted = an inner attribute is not permitted in this context
282+
.label_does_not_annotate_this = {parser_label_inner_attr_does_not_annotate_this}
283+
.sugg_change_inner_to_outer = {parser_sugg_change_inner_attr_to_outer}
284+
285+
parser_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
286+
parser_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them
287+
288+
parser_inner_doc_comment_not_permitted = expected outer doc comment
289+
.note = inner doc comments like this (starting with `//!` or `/*!`) can only appear before items
290+
.suggestion = you might have meant to write a regular comment
291+
.label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item}
292+
.sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style

compiler/rustc_parse/src/parser/attr.rs

Lines changed: 51 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,23 @@ use rustc_ast as ast;
55
use rustc_ast::attr;
66
use rustc_ast::token::{self, Delimiter, Nonterminal};
77
use rustc_ast_pretty::pprust;
8-
use rustc_errors::{error_code, Diagnostic, IntoDiagnostic, PResult};
8+
use rustc_errors::{error_code, fluent, Diagnostic, IntoDiagnostic, PResult};
99
use rustc_span::{sym, BytePos, Span};
1010
use std::convert::TryInto;
1111

1212
// Public for rustfmt usage
1313
#[derive(Debug)]
14-
pub enum InnerAttrPolicy<'a> {
14+
pub enum InnerAttrPolicy {
1515
Permitted,
16-
Forbidden { reason: &'a str, saw_doc_comment: bool, prev_outer_attr_sp: Option<Span> },
16+
Forbidden(Option<InnerAttrForbiddenReason>),
1717
}
1818

19-
const DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG: &str = "an inner attribute is not \
20-
permitted in this context";
21-
22-
pub(super) const DEFAULT_INNER_ATTR_FORBIDDEN: InnerAttrPolicy<'_> = InnerAttrPolicy::Forbidden {
23-
reason: DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG,
24-
saw_doc_comment: false,
25-
prev_outer_attr_sp: None,
26-
};
19+
#[derive(Clone, Copy, Debug)]
20+
pub enum InnerAttrForbiddenReason {
21+
InCodeBlock,
22+
AfterOuterDocComment { prev_doc_comment_span: Span },
23+
AfterOuterAttribute { prev_outer_attr_sp: Span },
24+
}
2725

2826
enum OuterAttributeType {
2927
DocComment,
@@ -42,25 +40,23 @@ impl<'a> Parser<'a> {
4240
let prev_outer_attr_sp = outer_attrs.last().map(|attr| attr.span);
4341

4442
let inner_error_reason = if just_parsed_doc_comment {
45-
"an inner attribute is not permitted following an outer doc comment"
46-
} else if prev_outer_attr_sp.is_some() {
47-
"an inner attribute is not permitted following an outer attribute"
43+
Some(InnerAttrForbiddenReason::AfterOuterDocComment {
44+
prev_doc_comment_span: prev_outer_attr_sp.unwrap(),
45+
})
46+
} else if let Some(prev_outer_attr_sp) = prev_outer_attr_sp {
47+
Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp })
4848
} else {
49-
DEFAULT_UNEXPECTED_INNER_ATTR_ERR_MSG
50-
};
51-
let inner_parse_policy = InnerAttrPolicy::Forbidden {
52-
reason: inner_error_reason,
53-
saw_doc_comment: just_parsed_doc_comment,
54-
prev_outer_attr_sp,
49+
None
5550
};
51+
let inner_parse_policy = InnerAttrPolicy::Forbidden(inner_error_reason);
5652
just_parsed_doc_comment = false;
5753
Some(self.parse_attribute(inner_parse_policy)?)
5854
} else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
5955
if attr_style != ast::AttrStyle::Outer {
6056
let span = self.token.span;
6157
let mut err = self.sess.span_diagnostic.struct_span_err_with_code(
6258
span,
63-
"expected outer doc comment",
59+
fluent::parser::inner_doc_comment_not_permitted,
6460
error_code!(E0753),
6561
);
6662
if let Some(replacement_span) = self.annotate_following_item_if_applicable(
@@ -71,13 +67,10 @@ impl<'a> Parser<'a> {
7167
token::CommentKind::Block => OuterAttributeType::DocBlockComment,
7268
},
7369
) {
74-
err.note(
75-
"inner doc comments like this (starting with `//!` or `/*!`) can \
76-
only appear before items",
77-
);
70+
err.note(fluent::parser::note);
7871
err.span_suggestion_verbose(
7972
replacement_span,
80-
"you might have meant to write a regular comment",
73+
fluent::parser::suggestion,
8174
"",
8275
rustc_errors::Applicability::MachineApplicable,
8376
);
@@ -115,7 +108,7 @@ impl<'a> Parser<'a> {
115108
// Public for rustfmt usage.
116109
pub fn parse_attribute(
117110
&mut self,
118-
inner_parse_policy: InnerAttrPolicy<'_>,
111+
inner_parse_policy: InnerAttrPolicy,
119112
) -> PResult<'a, ast::Attribute> {
120113
debug!(
121114
"parse_attribute: inner_parse_policy={:?} self.token={:?}",
@@ -179,21 +172,12 @@ impl<'a> Parser<'a> {
179172
ForceCollect::No,
180173
) {
181174
Ok(Some(item)) => {
182-
let attr_name = match attr_type {
183-
OuterAttributeType::Attribute => "attribute",
184-
_ => "doc comment",
185-
};
186-
err.span_label(
187-
item.span,
188-
&format!("the inner {} doesn't annotate this {}", attr_name, item.kind.descr()),
189-
);
175+
// FIXME(#100717)
176+
err.set_arg("item", item.kind.descr());
177+
err.span_label(item.span, fluent::parser::label_does_not_annotate_this);
190178
err.span_suggestion_verbose(
191179
replacement_span,
192-
&format!(
193-
"to annotate the {}, change the {} from inner to outer style",
194-
item.kind.descr(),
195-
attr_name
196-
),
180+
fluent::parser::sugg_change_inner_to_outer,
197181
match attr_type {
198182
OuterAttributeType::Attribute => "",
199183
OuterAttributeType::DocBlockComment => "*",
@@ -211,22 +195,33 @@ impl<'a> Parser<'a> {
211195
Some(replacement_span)
212196
}
213197

214-
pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy<'_>) {
215-
if let InnerAttrPolicy::Forbidden { reason, saw_doc_comment, prev_outer_attr_sp } = policy {
216-
let prev_outer_attr_note =
217-
if saw_doc_comment { "previous doc comment" } else { "previous outer attribute" };
218-
219-
let mut diag = self.struct_span_err(attr_sp, reason);
220-
221-
if let Some(prev_outer_attr_sp) = prev_outer_attr_sp {
222-
diag.span_label(attr_sp, "not permitted following an outer attribute")
223-
.span_label(prev_outer_attr_sp, prev_outer_attr_note);
224-
}
198+
pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerAttrPolicy) {
199+
if let InnerAttrPolicy::Forbidden(reason) = policy {
200+
let mut diag = match reason.as_ref().copied() {
201+
Some(InnerAttrForbiddenReason::AfterOuterDocComment { prev_doc_comment_span }) => {
202+
let mut diag = self.struct_span_err(
203+
attr_sp,
204+
fluent::parser::inner_attr_not_permitted_after_outer_doc_comment,
205+
);
206+
diag.span_label(attr_sp, fluent::parser::label_attr)
207+
.span_label(prev_doc_comment_span, fluent::parser::label_prev_doc_comment);
208+
diag
209+
}
210+
Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => {
211+
let mut diag = self.struct_span_err(
212+
attr_sp,
213+
fluent::parser::inner_attr_not_permitted_after_outer_attr,
214+
);
215+
diag.span_label(attr_sp, fluent::parser::label_attr)
216+
.span_label(prev_outer_attr_sp, fluent::parser::label_prev_attr);
217+
diag
218+
}
219+
Some(InnerAttrForbiddenReason::InCodeBlock) | None => {
220+
self.struct_span_err(attr_sp, fluent::parser::inner_attr_not_permitted)
221+
}
222+
};
225223

226-
diag.note(
227-
"inner attributes, like `#![no_std]`, annotate the item enclosing them, and \
228-
are usually found at the beginning of source files",
229-
);
224+
diag.note(fluent::parser::inner_attr_explanation);
230225
if self
231226
.annotate_following_item_if_applicable(
232227
&mut diag,
@@ -235,7 +230,7 @@ impl<'a> Parser<'a> {
235230
)
236231
.is_some()
237232
{
238-
diag.note("outer attributes, like `#[test]`, annotate the item following them");
233+
diag.note(fluent::parser::outer_attr_explanation);
239234
};
240235
diag.emit();
241236
}

compiler/rustc_parse/src/parser/stmt.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::attr::DEFAULT_INNER_ATTR_FORBIDDEN;
1+
use super::attr::InnerAttrForbiddenReason;
22
use super::diagnostics::AttemptLocalParseRecovery;
33
use super::expr::LhsExpr;
44
use super::pat::RecoverComma;
@@ -399,7 +399,12 @@ impl<'a> Parser<'a> {
399399
pub(super) fn parse_block(&mut self) -> PResult<'a, P<Block>> {
400400
let (attrs, block) = self.parse_inner_attrs_and_block()?;
401401
if let [.., last] = &*attrs {
402-
self.error_on_forbidden_inner_attr(last.span, DEFAULT_INNER_ATTR_FORBIDDEN);
402+
self.error_on_forbidden_inner_attr(
403+
last.span,
404+
super::attr::InnerAttrPolicy::Forbidden(Some(
405+
InnerAttrForbiddenReason::InCodeBlock,
406+
)),
407+
);
403408
}
404409
Ok(block)
405410
}

src/test/ui/parser/inner-attr-after-doc-comment.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ LL | | */
77
| |___- previous doc comment
88
LL |
99
LL | #![recursion_limit="100"]
10-
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attribute
10+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer doc comment
1111
LL |
1212
LL | fn main() {}
1313
| ------------ the inner attribute doesn't annotate this function

0 commit comments

Comments
 (0)