From 21b5194a3a0ff5179d4afb6886fc8816243574f0 Mon Sep 17 00:00:00 2001 From: Xiretza Date: Wed, 31 Aug 2022 13:20:59 +0200 Subject: [PATCH] Rework "inner attribute not permitted" errors --- .../locales/en-US/parser.ftl | 28 +++++ compiler/rustc_parse/src/parser/attr.rs | 107 +++++++++--------- compiler/rustc_parse/src/parser/stmt.rs | 9 +- .../inner-attr-after-doc-comment.stderr | 2 +- 4 files changed, 87 insertions(+), 59 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/parser.ftl b/compiler/rustc_error_messages/locales/en-US/parser.ftl index 36b03a2db77..9773cbe5517 100644 --- a/compiler/rustc_error_messages/locales/en-US/parser.ftl +++ b/compiler/rustc_error_messages/locales/en-US/parser.ftl @@ -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.) 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 diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs index 297f4964116..ee3f7dbbc39 100644 --- a/compiler/rustc_parse/src/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -5,25 +5,23 @@ 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 }, + Forbidden(Option), } -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 @@ pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> { 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 @@ pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> { 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 @@ pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> { 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 @@ pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, AttrWrapper> { // 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 @@ fn annotate_following_item_if_applicable( 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 @@ fn annotate_following_item_if_applicable( 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" }; - - 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); - } + 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) + } + }; - 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 @@ pub(super) fn error_on_forbidden_inner_attr(&self, attr_sp: Span, policy: InnerA ) .is_some() { - diag.note("outer attributes, like `#[test]`, annotate the item following them"); + diag.note(fluent::parser::outer_attr_explanation); }; diag.emit(); } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 155173f120c..a61e77b7c3b 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -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 @@ fn parse_initializer(&mut self, eq_optional: bool) -> PResult<'a, Option pub(super) fn parse_block(&mut self) -> PResult<'a, P> { 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) } diff --git a/src/test/ui/parser/inner-attr-after-doc-comment.stderr b/src/test/ui/parser/inner-attr-after-doc-comment.stderr index 2cfafac7794..3ec3ad8e977 100644 --- a/src/test/ui/parser/inner-attr-after-doc-comment.stderr +++ b/src/test/ui/parser/inner-attr-after-doc-comment.stderr @@ -7,7 +7,7 @@ LL | | */ | |___- previous doc comment LL | LL | #![recursion_limit="100"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer attribute + | ^^^^^^^^^^^^^^^^^^^^^^^^^ not permitted following an outer doc comment LL | LL | fn main() {} | ------------ the inner attribute doesn't annotate this function -- 2.44.0