about summary refs log tree commit diff
diff options
context:
space:
mode:
authorHampus Lidin <hampuslidin@gmail.com>2022-08-21 08:46:05 +0200
committerHampus Lidin <hampuslidin@gmail.com>2022-08-22 20:19:15 +0200
commit0005f628f068a766647bb0b159dac2c6cefcefa1 (patch)
tree214a5c91f7a6bb23dcd1b2d2ace4b7a9b038e660
parente0dc8d78019ca924203fe153ff0af7f64f68cb5d (diff)
downloadrust-0005f628f068a766647bb0b159dac2c6cefcefa1.tar.gz
rust-0005f628f068a766647bb0b159dac2c6cefcefa1.zip
Refactor diagnostics in `handle_errors` function
-rw-r--r--compiler/rustc_attr/src/builtin.rs58
-rw-r--r--compiler/rustc_attr/src/lib.rs1
-rw-r--r--compiler/rustc_attr/src/session_diagnostics.rs196
-rw-r--r--compiler/rustc_error_messages/locales/en-US/attr.ftl29
-rw-r--r--compiler/rustc_error_messages/src/lib.rs1
5 files changed, 254 insertions, 31 deletions
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 62ccd734fe7..b43551db43d 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -14,6 +14,8 @@ use rustc_span::hygiene::Transparency;
 use rustc_span::{symbol::sym, symbol::Symbol, Span};
 use std::num::NonZeroU32;
 
+use crate::session_diagnostics;
+
 pub fn is_builtin_attr(attr: &Attribute) -> bool {
     attr.is_doc_comment() || attr.ident().filter(|ident| is_builtin_attr_name(ident.name)).is_some()
 }
@@ -25,46 +27,38 @@ enum AttrError {
     NonIdentFeature,
     MissingFeature,
     MultipleStabilityLevels,
-    UnsupportedLiteral(&'static str, /* is_bytestr */ bool),
+    UnsupportedLiteral(UnsupportedLiteralReason, /* is_bytestr */ bool),
+}
+
+pub(crate) enum UnsupportedLiteralReason {
+    Generic,
+    CfgString,
+    DeprecatedString,
+    DeprecatedKvPair,
 }
 
 fn handle_errors(sess: &ParseSess, span: Span, error: AttrError) {
-    let diag = &sess.span_diagnostic;
     match error {
         AttrError::MultipleItem(item) => {
-            struct_span_err!(diag, span, E0538, "multiple '{}' items", item).emit();
+            sess.emit_err(session_diagnostics::MultipleItem { span, item });
         }
         AttrError::UnknownMetaItem(item, expected) => {
-            let expected = expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
-            struct_span_err!(diag, span, E0541, "unknown meta item '{}'", item)
-                .span_label(span, format!("expected one of {}", expected.join(", ")))
-                .emit();
+            sess.emit_err(session_diagnostics::UnknownMetaItem { span, item, expected });
         }
         AttrError::MissingSince => {
-            struct_span_err!(diag, span, E0542, "missing 'since'").emit();
+            sess.emit_err(session_diagnostics::MissingSince { span });
         }
         AttrError::NonIdentFeature => {
-            struct_span_err!(diag, span, E0546, "'feature' is not an identifier").emit();
+            sess.emit_err(session_diagnostics::NonIdentFeature { span });
         }
         AttrError::MissingFeature => {
-            struct_span_err!(diag, span, E0546, "missing 'feature'").emit();
+            sess.emit_err(session_diagnostics::MissingFeature { span });
         }
         AttrError::MultipleStabilityLevels => {
-            struct_span_err!(diag, span, E0544, "multiple stability levels").emit();
+            sess.emit_err(session_diagnostics::MultipleStabilityLevels { span });
         }
-        AttrError::UnsupportedLiteral(msg, is_bytestr) => {
-            let mut err = struct_span_err!(diag, span, E0565, "{}", msg);
-            if is_bytestr {
-                if let Ok(lint_str) = sess.source_map().span_to_snippet(span) {
-                    err.span_suggestion(
-                        span,
-                        "consider removing the prefix",
-                        &lint_str[1..],
-                        Applicability::MaybeIncorrect,
-                    );
-                }
-            }
-            err.emit();
+        AttrError::UnsupportedLiteral(reason, is_bytestr) => {
+            sess.emit_err(session_diagnostics::UnsupportedLiteral { span, reason, is_bytestr });
         }
     }
 }
@@ -326,7 +320,7 @@ where
                             handle_errors(
                                 &sess.parse_sess,
                                 meta.span(),
-                                AttrError::UnsupportedLiteral("unsupported literal", false),
+                                AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
                             );
                             continue 'outer;
                         };
@@ -494,7 +488,10 @@ where
                                 handle_errors(
                                     &sess.parse_sess,
                                     lit.span,
-                                    AttrError::UnsupportedLiteral("unsupported literal", false),
+                                    AttrError::UnsupportedLiteral(
+                                        UnsupportedLiteralReason::Generic,
+                                        false,
+                                    ),
                                 );
                                 continue 'outer;
                             }
@@ -711,7 +708,7 @@ pub fn eval_condition(
                     handle_errors(
                         sess,
                         mi.span(),
-                        AttrError::UnsupportedLiteral("unsupported literal", false),
+                        AttrError::UnsupportedLiteral(UnsupportedLiteralReason::Generic, false),
                     );
                     return false;
                 }
@@ -790,7 +787,7 @@ pub fn eval_condition(
                 sess,
                 lit.span,
                 AttrError::UnsupportedLiteral(
-                    "literal in `cfg` predicate value must be a string",
+                    UnsupportedLiteralReason::CfgString,
                     lit.kind.is_bytestr(),
                 ),
             );
@@ -870,8 +867,7 @@ where
                                 &sess.parse_sess,
                                 lit.span,
                                 AttrError::UnsupportedLiteral(
-                                    "literal in `deprecated` \
-                                    value must be a string",
+                                    UnsupportedLiteralReason::DeprecatedString,
                                     lit.kind.is_bytestr(),
                                 ),
                             );
@@ -934,7 +930,7 @@ where
                                 &sess.parse_sess,
                                 lit.span,
                                 AttrError::UnsupportedLiteral(
-                                    "item in `deprecated` must be a key/value pair",
+                                    UnsupportedLiteralReason::DeprecatedKvPair,
                                     false,
                                 ),
                             );
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index c95c1c40a34..36a3620b6b9 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -10,6 +10,7 @@
 extern crate rustc_macros;
 
 mod builtin;
+mod session_diagnostics;
 
 pub use builtin::*;
 pub use IntType::*;
diff --git a/compiler/rustc_attr/src/session_diagnostics.rs b/compiler/rustc_attr/src/session_diagnostics.rs
new file mode 100644
index 00000000000..92ce9336edc
--- /dev/null
+++ b/compiler/rustc_attr/src/session_diagnostics.rs
@@ -0,0 +1,196 @@
+use std::num::IntErrorKind;
+
+use rustc_errors::{error_code, fluent, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_macros::SessionDiagnostic;
+use rustc_session::{parse::ParseSess, SessionDiagnostic};
+use rustc_span::Span;
+
+use crate::UnsupportedLiteralReason;
+
+#[derive(SessionDiagnostic)]
+#[error(attr::multiple_item, code = "E0538")]
+pub(crate) struct MultipleItem {
+    #[primary_span]
+    pub span: Span,
+
+    pub item: String,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(attr::missing_since, code = "E0542")]
+pub(crate) struct MissingSince {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(attr::non_ident_feature, code = "E0546")]
+pub(crate) struct NonIdentFeature {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(attr::missing_feature, code = "E0546")]
+pub(crate) struct MissingFeature {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(attr::multiple_stability_levels, code = "E0544")]
+pub(crate) struct MultipleStabilityLevels {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(attr::invalid_meta_item, code = "E0539")]
+pub(crate) struct InvalidMetaItem {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(attr::missing_issue, code = "E0547")]
+pub(crate) struct MissingIssue {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(attr::rustc_promotable_pairing, code = "E0717")]
+pub(crate) struct RustcPromotablePairing {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(attr::rustc_allowed_unstable_pairing, code = "E0789")]
+pub(crate) struct RustcAllowedUnstablePairing {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(attr::soft_no_args)]
+pub(crate) struct SoftNoArgs {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(SessionDiagnostic)]
+#[error(attr::invalid_issue_string, code = "E0545")]
+pub(crate) struct InvalidIssueString {
+    #[primary_span]
+    pub span: Span,
+
+    #[subdiagnostic]
+    pub cause: Option<InvalidIssueStringCause>,
+}
+
+// The error kinds of `IntErrorKind` are duplicated here in order to allow the messages to be
+// translatable.
+#[derive(SessionSubdiagnostic)]
+pub(crate) enum InvalidIssueStringCause {
+    #[label(attr::must_not_be_zero)]
+    MustNotBeZero {
+        #[primary_span]
+        span: Span,
+    },
+
+    #[label(attr::empty)]
+    Empty {
+        #[primary_span]
+        span: Span,
+    },
+
+    #[label(attr::invalid_digit)]
+    InvalidDigit {
+        #[primary_span]
+        span: Span,
+    },
+
+    #[label(attr::pos_overflow)]
+    PosOverflow {
+        #[primary_span]
+        span: Span,
+    },
+
+    #[label(attr::neg_overflow)]
+    NegOverflow {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+impl InvalidIssueStringCause {
+    pub fn from_int_error_kind(span: Span, kind: &IntErrorKind) -> Option<Self> {
+        match kind {
+            IntErrorKind::Empty => Some(Self::Empty { span }),
+            IntErrorKind::InvalidDigit => Some(Self::InvalidDigit { span }),
+            IntErrorKind::PosOverflow => Some(Self::PosOverflow { span }),
+            IntErrorKind::NegOverflow => Some(Self::NegOverflow { span }),
+            IntErrorKind::Zero => Some(Self::MustNotBeZero { span }),
+            _ => None,
+        }
+    }
+}
+
+pub(crate) struct UnknownMetaItem<'a> {
+    pub span: Span,
+    pub item: String,
+    pub expected: &'a [&'a str],
+}
+
+// Manual implementation to be able to format `expected` items correctly.
+impl<'a> SessionDiagnostic<'a> for UnknownMetaItem<'_> {
+    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        let expected = self.expected.iter().map(|name| format!("`{}`", name)).collect::<Vec<_>>();
+        let mut diag = sess.span_diagnostic.struct_span_err_with_code(
+            self.span,
+            fluent::attr::unknown_meta_item,
+            error_code!(E0541),
+        );
+        diag.set_arg("item", self.item);
+        diag.set_arg("expected", expected.join(", "));
+        diag.span_label(self.span, fluent::attr::label);
+        diag
+    }
+}
+
+pub(crate) struct UnsupportedLiteral {
+    pub span: Span,
+    pub reason: UnsupportedLiteralReason,
+    pub is_bytestr: bool,
+}
+
+impl<'a> SessionDiagnostic<'a> for UnsupportedLiteral {
+    fn into_diagnostic(self, sess: &'a ParseSess) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
+        let mut diag = sess.span_diagnostic.struct_span_err_with_code(
+            self.span,
+            match self.reason {
+                UnsupportedLiteralReason::Generic => fluent::attr::unsupported_literal_generic,
+                UnsupportedLiteralReason::CfgString => fluent::attr::unsupported_literal_cfg_string,
+                UnsupportedLiteralReason::DeprecatedString => {
+                    fluent::attr::unsupported_literal_deprecated_string
+                }
+                UnsupportedLiteralReason::DeprecatedKvPair => {
+                    fluent::attr::unsupported_literal_deprecated_kv_pair
+                }
+            },
+            error_code!(E0565),
+        );
+        if self.is_bytestr {
+            if let Ok(lint_str) = sess.source_map().span_to_snippet(self.span) {
+                diag.span_suggestion(
+                    self.span,
+                    fluent::attr::unsupported_literal_suggestion,
+                    &lint_str[1..],
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+        diag
+    }
+}
diff --git a/compiler/rustc_error_messages/locales/en-US/attr.ftl b/compiler/rustc_error_messages/locales/en-US/attr.ftl
new file mode 100644
index 00000000000..a8207b1f7bc
--- /dev/null
+++ b/compiler/rustc_error_messages/locales/en-US/attr.ftl
@@ -0,0 +1,29 @@
+attr_multiple_item =
+    multiple '{$item}' items
+
+attr_unknown_meta_item =
+    unknown meta item '{$item}'
+    .label = expected one of {$expected}
+
+attr_missing_since =
+    missing 'since'
+
+attr_non_ident_feature =
+    'feature' is not an identifier
+
+attr_missing_feature =
+    missing 'feature'
+
+attr_multiple_stability_levels =
+    multiple stability levels
+
+attr_unsupported_literal_generic =
+    unsupported literal
+attr_unsupported_literal_cfg_string =
+    literal in `cfg` predicate value must be a string
+attr_unsupported_literal_deprecated_string =
+    literal in `deprecated` value must be a string
+attr_unsupported_literal_deprecated_kv_pair =
+    item in `deprecated` must be a key/value pair
+attr_unsupported_literal_suggestion =
+    consider removing the prefix
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 3569c7f0630..ab09a902b0a 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -33,6 +33,7 @@ pub use unic_langid::{langid, LanguageIdentifier};
 // Generates `DEFAULT_LOCALE_RESOURCES` static and `fluent_generated` module.
 fluent_messages! {
     ast_passes => "../locales/en-US/ast_passes.ftl",
+    attr => "../locales/en-US/attr.ftl",
     borrowck => "../locales/en-US/borrowck.ftl",
     builtin_macros => "../locales/en-US/builtin_macros.ftl",
     const_eval => "../locales/en-US/const_eval.ftl",