about summary refs log tree commit diff
path: root/compiler/rustc_macros/src
diff options
context:
space:
mode:
authorXiretza <xiretza@xiretza.xyz>2022-08-19 15:02:10 +0200
committerXiretza <xiretza@xiretza.xyz>2022-08-21 09:17:43 +0200
commita960f8304cee9af374aae7bade15554734f37480 (patch)
treeebeae37fbf28a5735cb96eca6c9eedc0c9e83f74 /compiler/rustc_macros/src
parent91ad4e38f53ce1ef8783233bde36a81cd8177981 (diff)
downloadrust-a960f8304cee9af374aae7bade15554734f37480.tar.gz
rust-a960f8304cee9af374aae7bade15554734f37480.zip
Make derived SessionDiagnostics generic on diagnostic level
Deriving SessionDiagnostic on a type no longer forces that diagnostic to
be one of warning, error, or fatal. The level is instead decided when
the struct is passed to the respective Handler::emit_*() method.
Diffstat (limited to 'compiler/rustc_macros/src')
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic.rs82
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs81
-rw-r--r--compiler/rustc_macros/src/lib.rs2
3 files changed, 60 insertions, 105 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
index 6b5b8b59320..244edec2841 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs
@@ -21,7 +21,7 @@ impl<'a> SessionDiagnosticDerive<'a> {
             builder: DiagnosticDeriveBuilder {
                 diag,
                 fields: build_field_mapping(&structure),
-                kind: None,
+                kind: DiagnosticDeriveKind::SessionDiagnostic,
                 code: None,
                 slug: None,
             },
@@ -34,49 +34,31 @@ impl<'a> SessionDiagnosticDerive<'a> {
         let SessionDiagnosticDerive { mut structure, sess, mut builder } = self;
 
         let ast = structure.ast();
-        let (implementation, param_ty) = {
+        let implementation = {
             if let syn::Data::Struct(..) = ast.data {
                 let preamble = builder.preamble(&structure);
                 let (attrs, args) = builder.body(&mut structure);
 
                 let span = ast.span().unwrap();
                 let diag = &builder.diag;
-                let init = match (builder.kind.value(), builder.slug.value()) {
-                    (None, _) => {
-                        span_err(span, "diagnostic kind not specified")
-                            .help("use the `#[error(...)]` attribute to create an error")
-                            .emit();
-                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    (Some(kind), None) => {
+                let init = match builder.slug.value() {
+                    None => {
                         span_err(span, "diagnostic slug not specified")
                             .help(&format!(
-                                "specify the slug as the first argument to the attribute, such as \
-                                 `#[{}(typeck::example_error)]`",
-                                kind.descr()
+                                "specify the slug as the first argument to the `#[diag(...)]` attribute, \
+                                such as `#[diag(typeck::example_error)]`",
                             ))
                             .emit();
                         return DiagnosticDeriveError::ErrorHandled.to_compile_error();
                     }
-                    (Some(DiagnosticDeriveKind::Lint), _) => {
-                        span_err(span, "only `#[error(..)]` and `#[warning(..)]` are supported")
-                            .help("use the `#[error(...)]` attribute to create a error")
-                            .emit();
-                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    (Some(DiagnosticDeriveKind::Error), Some(slug)) => {
-                        quote! {
-                            let mut #diag = #sess.struct_err(rustc_errors::fluent::#slug);
-                        }
-                    }
-                    (Some(DiagnosticDeriveKind::Warn), Some(slug)) => {
+                    Some(slug) => {
                         quote! {
-                            let mut #diag = #sess.struct_warn(rustc_errors::fluent::#slug);
+                            let mut #diag = #sess.struct_diagnostic(rustc_errors::fluent::#slug);
                         }
                     }
                 };
 
-                let implementation = quote! {
+                quote! {
                     #init
                     #preamble
                     match self {
@@ -86,18 +68,7 @@ impl<'a> SessionDiagnosticDerive<'a> {
                         #args
                     }
                     #diag
-                };
-                let param_ty = match builder.kind {
-                    Some((DiagnosticDeriveKind::Error, _)) => {
-                        quote! { rustc_errors::ErrorGuaranteed }
-                    }
-                    Some((DiagnosticDeriveKind::Lint | DiagnosticDeriveKind::Warn, _)) => {
-                        quote! { () }
-                    }
-                    _ => unreachable!(),
-                };
-
-                (implementation, param_ty)
+                }
             } else {
                 span_err(
                     ast.span().unwrap(),
@@ -105,20 +76,20 @@ impl<'a> SessionDiagnosticDerive<'a> {
                 )
                 .emit();
 
-                let implementation = DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                let param_ty = quote! { rustc_errors::ErrorGuaranteed };
-                (implementation, param_ty)
+                DiagnosticDeriveError::ErrorHandled.to_compile_error()
             }
         };
 
         structure.gen_impl(quote! {
-            gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess, #param_ty>
+            gen impl<'__session_diagnostic_sess, G>
+                    rustc_session::SessionDiagnostic<'__session_diagnostic_sess, G>
                     for @Self
+                where G: rustc_errors::EmissionGuarantee
             {
                 fn into_diagnostic(
                     self,
                     #sess: &'__session_diagnostic_sess rustc_session::parse::ParseSess
-                ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, #param_ty> {
+                ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, G> {
                     use rustc_errors::IntoDiagnosticArg;
                     #implementation
                 }
@@ -139,7 +110,7 @@ impl<'a> LintDiagnosticDerive<'a> {
             builder: DiagnosticDeriveBuilder {
                 diag,
                 fields: build_field_mapping(&structure),
-                kind: None,
+                kind: DiagnosticDeriveKind::LintDiagnostic,
                 code: None,
                 slug: None,
             },
@@ -158,30 +129,17 @@ impl<'a> LintDiagnosticDerive<'a> {
 
                 let diag = &builder.diag;
                 let span = ast.span().unwrap();
-                let init = match (builder.kind.value(), builder.slug.value()) {
-                    (None, _) => {
-                        span_err(span, "diagnostic kind not specified")
-                            .help("use the `#[error(...)]` attribute to create an error")
-                            .emit();
-                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    (Some(kind), None) => {
+                let init = match builder.slug.value() {
+                    None => {
                         span_err(span, "diagnostic slug not specified")
                             .help(&format!(
                                 "specify the slug as the first argument to the attribute, such as \
-                                 `#[{}(typeck::example_error)]`",
-                                kind.descr()
+                                 `#[diag(typeck::example_error)]`",
                             ))
                             .emit();
                         return DiagnosticDeriveError::ErrorHandled.to_compile_error();
                     }
-                    (Some(DiagnosticDeriveKind::Error | DiagnosticDeriveKind::Warn), _) => {
-                        span_err(span, "only `#[lint(..)]` is supported")
-                            .help("use the `#[lint(...)]` attribute to create a lint")
-                            .emit();
-                        return DiagnosticDeriveError::ErrorHandled.to_compile_error();
-                    }
-                    (Some(DiagnosticDeriveKind::Lint), Some(slug)) => {
+                    Some(slug) => {
                         quote! {
                             let mut #diag = #diag.build(rustc_errors::fluent::#slug);
                         }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 6c9561925fe..6a5997512bd 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -18,30 +18,15 @@ use syn::{
 };
 use synstructure::{BindingInfo, Structure};
 
-/// What kind of diagnostic is being derived - an error, a warning or a lint?
-#[derive(Copy, Clone)]
+/// What kind of diagnostic is being derived - a fatal/error/warning or a lint?
+#[derive(Copy, Clone, PartialEq, Eq)]
 pub(crate) enum DiagnosticDeriveKind {
-    /// `#[error(..)]`
-    Error,
-    /// `#[warn(..)]`
-    Warn,
-    /// `#[lint(..)]`
-    Lint,
-}
-
-impl DiagnosticDeriveKind {
-    /// Returns human-readable string corresponding to the kind.
-    pub fn descr(&self) -> &'static str {
-        match self {
-            DiagnosticDeriveKind::Error => "error",
-            DiagnosticDeriveKind::Warn => "warning",
-            DiagnosticDeriveKind::Lint => "lint",
-        }
-    }
+    SessionDiagnostic,
+    LintDiagnostic,
 }
 
 /// Tracks persistent information required for building up individual calls to diagnostic methods
-/// for generated diagnostic derives - both `SessionDiagnostic` for errors/warnings and
+/// for generated diagnostic derives - both `SessionDiagnostic` for fatal/errors/warnings and
 /// `LintDiagnostic` for lints.
 pub(crate) struct DiagnosticDeriveBuilder {
     /// The identifier to use for the generated `DiagnosticBuilder` instance.
@@ -51,8 +36,8 @@ pub(crate) struct DiagnosticDeriveBuilder {
     /// derive builder.
     pub fields: HashMap<String, TokenStream>,
 
-    /// Kind of diagnostic requested via the struct attribute.
-    pub kind: Option<(DiagnosticDeriveKind, proc_macro::Span)>,
+    /// Kind of diagnostic that should be derived.
+    pub kind: DiagnosticDeriveKind,
     /// Slug is a mandatory part of the struct attribute as corresponds to the Fluent message that
     /// has the actual diagnostic message.
     pub slug: Option<(Path, proc_macro::Span)>,
@@ -143,7 +128,7 @@ impl DiagnosticDeriveBuilder {
     }
 
     /// Establishes state in the `DiagnosticDeriveBuilder` resulting from the struct
-    /// attributes like `#[error(..)`, such as the diagnostic kind and slug. Generates
+    /// attributes like `#[diag(..)]`, such as the slug and error code. Generates
     /// diagnostic builder calls for setting error code and creating note/help messages.
     fn generate_structure_code_for_attr(
         &mut self,
@@ -156,15 +141,15 @@ impl DiagnosticDeriveBuilder {
         let name = name.as_str();
         let meta = attr.parse_meta()?;
 
-        let is_help_note_or_warn = matches!(name, "help" | "note" | "warn_");
+        let is_diag = matches!(name, "error" | "warning" | "lint" | "diag");
 
         let nested = match meta {
-            // Most attributes are lists, like `#[error(..)]`/`#[warning(..)]` for most cases or
+            // Most attributes are lists, like `#[diag(..)]` for most cases or
             // `#[help(..)]`/`#[note(..)]` when the user is specifying a alternative slug.
             Meta::List(MetaList { ref nested, .. }) => nested,
             // Subdiagnostics without spans can be applied to the type too, and these are just
-            // paths: `#[help]` and `#[note]`
-            Meta::Path(_) if is_help_note_or_warn => {
+            // paths: `#[help]`, `#[note]` and `#[warn_]`
+            Meta::Path(_) if !is_diag => {
                 let fn_name = if name == "warn_" {
                     Ident::new("warn", attr.span())
                 } else {
@@ -178,23 +163,32 @@ impl DiagnosticDeriveBuilder {
         // Check the kind before doing any further processing so that there aren't misleading
         // "no kind specified" errors if there are failures later.
         match name {
-            "error" => self.kind.set_once((DiagnosticDeriveKind::Error, span)),
-            "warning" => self.kind.set_once((DiagnosticDeriveKind::Warn, span)),
-            "lint" => self.kind.set_once((DiagnosticDeriveKind::Lint, span)),
-            "help" | "note" | "warn_" => (),
+            "error" | "warning" => {
+                if self.kind == DiagnosticDeriveKind::LintDiagnostic {
+                    span_err(span, "only `#[lint(..)]` is supported")
+                        .help("use the `#[lint(...)]` attribute to create a lint")
+                        .emit();
+                }
+            }
+            "lint" => {
+                if self.kind == DiagnosticDeriveKind::SessionDiagnostic {
+                    span_err(span, "only `#[error(..)]` and `#[warning(..)]` are supported")
+                        .help("use the `#[error(...)]` attribute to create a error")
+                        .emit();
+                }
+            }
+            "diag" | "help" | "note" | "warn_" => (),
             _ => throw_invalid_attr!(attr, &meta, |diag| {
-                diag.help(
-                    "only `error`, `warning`, `help`, `note` and `warn_` are valid attributes",
-                )
+                diag.help("only `diag`, `help`, `note` and `warn_` are valid attributes")
             }),
         }
 
-        // First nested element should always be the path, e.g. `#[error(typeck::invalid)]` or
+        // First nested element should always be the path, e.g. `#[diag(typeck::invalid)]` or
         // `#[help(typeck::another_help)]`.
         let mut nested_iter = nested.into_iter();
         if let Some(nested_attr) = nested_iter.next() {
             // Report an error if there are any other list items after the path.
-            if is_help_note_or_warn && nested_iter.next().is_some() {
+            if !is_diag && nested_iter.next().is_some() {
                 throw_invalid_nested_attr!(attr, &nested_attr, |diag| {
                     diag.help(
                         "`help`, `note` and `warn_` struct attributes can only have one argument",
@@ -203,16 +197,16 @@ impl DiagnosticDeriveBuilder {
             }
 
             match nested_attr {
-                NestedMeta::Meta(Meta::Path(path)) if is_help_note_or_warn => {
-                    let fn_name = proc_macro2::Ident::new(name, attr.span());
-                    return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); });
-                }
                 NestedMeta::Meta(Meta::Path(path)) => {
-                    self.slug.set_once((path.clone(), span));
+                    if is_diag {
+                        self.slug.set_once((path.clone(), span));
+                    } else {
+                        let fn_name = proc_macro2::Ident::new(name, attr.span());
+                        return Ok(quote! { #diag.#fn_name(rustc_errors::fluent::#path); });
+                    }
                 }
                 NestedMeta::Meta(meta @ Meta::NameValue(_))
-                    if !is_help_note_or_warn
-                        && meta.path().segments.last().unwrap().ident == "code" =>
+                    if is_diag && meta.path().segments.last().unwrap().ident == "code" =>
                 {
                     // don't error for valid follow-up attributes
                 }
@@ -347,6 +341,7 @@ impl DiagnosticDeriveBuilder {
             }
             "primary_span" => {
                 report_error_if_not_applied_to_span(attr, &info)?;
+
                 Ok(quote! {
                     #diag.set_span(#binding);
                 })
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index e01d035767b..fe4ff2fb6aa 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -132,6 +132,7 @@ decl_derive!(
         warning,
         error,
         lint,
+        diag,
         help,
         note,
         warn_,
@@ -151,6 +152,7 @@ decl_derive!(
         warning,
         error,
         lint,
+        diag,
         help,
         note,
         warn_,