about summary refs log tree commit diff
path: root/compiler/rustc_parse/src/parser/attr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_parse/src/parser/attr.rs')
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs159
1 files changed, 68 insertions, 91 deletions
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index 5fd69b15ecc..58be348883c 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,27 +1,26 @@
+use crate::errors::{InvalidMetaItem, SuffixedLiteralInAttribute};
+
 use super::{AttrWrapper, Capturing, FnParseMode, ForceCollect, Parser, PathStyle};
 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, 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,
@@ -40,17 +39,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 {
@@ -58,7 +55,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(
@@ -69,13 +66,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,
                         );
@@ -113,7 +107,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={:?}",
@@ -122,35 +116,22 @@ impl<'a> Parser<'a> {
         let lo = self.token.span;
         // Attributes can't have attributes of their own [Editor's note: not with that attitude]
         self.collect_tokens_no_attrs(|this| {
-            if this.eat(&token::Pound) {
-                let style = if this.eat(&token::Not) {
-                    ast::AttrStyle::Inner
-                } else {
-                    ast::AttrStyle::Outer
-                };
+            assert!(this.eat(&token::Pound), "parse_attribute called in non-attribute position");
 
-                this.expect(&token::OpenDelim(Delimiter::Bracket))?;
-                let item = this.parse_attr_item(false)?;
-                this.expect(&token::CloseDelim(Delimiter::Bracket))?;
-                let attr_sp = lo.to(this.prev_token.span);
+            let style =
+                if this.eat(&token::Not) { ast::AttrStyle::Inner } else { ast::AttrStyle::Outer };
 
-                // Emit error if inner attribute is encountered and forbidden.
-                if style == ast::AttrStyle::Inner {
-                    this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
-                }
+            this.expect(&token::OpenDelim(Delimiter::Bracket))?;
+            let item = this.parse_attr_item(false)?;
+            this.expect(&token::CloseDelim(Delimiter::Bracket))?;
+            let attr_sp = lo.to(this.prev_token.span);
 
-                Ok(attr::mk_attr_from_item(
-                    &self.sess.attr_id_generator,
-                    item,
-                    None,
-                    style,
-                    attr_sp,
-                ))
-            } else {
-                let token_str = pprust::token_to_string(&this.token);
-                let msg = &format!("expected `#`, found `{token_str}`");
-                Err(this.struct_span_err(this.token.span, msg))
+            // Emit error if inner attribute is encountered and forbidden.
+            if style == ast::AttrStyle::Inner {
+                this.error_on_forbidden_inner_attr(attr_sp, inner_parse_policy);
             }
+
+            Ok(attr::mk_attr_from_item(&self.sess.attr_id_generator, item, None, style, attr_sp))
         })
     }
 
@@ -190,21 +171,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 => "*",
@@ -222,22 +194,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" };
-
-            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,
@@ -246,7 +229,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();
         }
@@ -337,12 +320,7 @@ impl<'a> Parser<'a> {
         debug!("checking if {:?} is unusuffixed", lit);
 
         if !lit.kind.is_unsuffixed() {
-            self.struct_span_err(lit.span, "suffixed literals are not allowed in attributes")
-                .help(
-                    "instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), \
-                    use an unsuffixed version (`1`, `1.0`, etc.)",
-                )
-                .emit();
+            self.sess.emit_err(SuffixedLiteralInAttribute { span: lit.span });
         }
 
         Ok(lit)
@@ -435,9 +413,8 @@ impl<'a> Parser<'a> {
             Err(err) => err.cancel(),
         }
 
-        let found = pprust::token_to_string(&self.token);
-        let msg = format!("expected unsuffixed literal or identifier, found `{found}`");
-        Err(self.struct_span_err(self.token.span, &msg))
+        Err(InvalidMetaItem { span: self.token.span, token: self.token.clone() }
+            .into_diagnostic(&self.sess.span_diagnostic))
     }
 }