diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_macros/src/diagnostics/diagnostic.rs | 243 |
1 files changed, 84 insertions, 159 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index 6b5b8b593..ef1985b96 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -2,123 +2,77 @@ use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind}; use crate::diagnostics::error::{span_err, DiagnosticDeriveError}; -use crate::diagnostics::utils::{build_field_mapping, SetOnce}; +use crate::diagnostics::utils::SetOnce; use proc_macro2::TokenStream; use quote::quote; -use syn::spanned::Spanned; use synstructure::Structure; /// The central struct for constructing the `into_diagnostic` method from an annotated struct. -pub(crate) struct SessionDiagnosticDerive<'a> { +pub(crate) struct DiagnosticDerive<'a> { structure: Structure<'a>, - sess: syn::Ident, builder: DiagnosticDeriveBuilder, } -impl<'a> SessionDiagnosticDerive<'a> { - pub(crate) fn new(diag: syn::Ident, sess: syn::Ident, structure: Structure<'a>) -> Self { +impl<'a> DiagnosticDerive<'a> { + pub(crate) fn new(diag: syn::Ident, handler: syn::Ident, structure: Structure<'a>) -> Self { Self { builder: DiagnosticDeriveBuilder { diag, - fields: build_field_mapping(&structure), - kind: None, - code: None, - slug: None, + kind: DiagnosticDeriveKind::Diagnostic { handler }, }, - sess, structure, } } pub(crate) fn into_tokens(self) -> TokenStream { - let SessionDiagnosticDerive { mut structure, sess, mut builder } = self; - - let ast = structure.ast(); - let (implementation, param_ty) = { - 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) => { - 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() - )) - .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)) => { - quote! { - let mut #diag = #sess.struct_warn(rustc_errors::fluent::#slug); - } - } - }; - - let implementation = quote! { - #init - #preamble - match self { - #attrs - } - match self { - #args - } - #diag - }; - let param_ty = match builder.kind { - Some((DiagnosticDeriveKind::Error, _)) => { - quote! { rustc_errors::ErrorGuaranteed } - } - Some((DiagnosticDeriveKind::Lint | DiagnosticDeriveKind::Warn, _)) => { - quote! { () } + let DiagnosticDerive { mut structure, mut builder } = self; + + let implementation = builder.each_variant(&mut structure, |mut builder, variant| { + let preamble = builder.preamble(&variant); + let body = builder.body(&variant); + + let diag = &builder.parent.diag; + let DiagnosticDeriveKind::Diagnostic { handler } = &builder.parent.kind else { + unreachable!() + }; + let init = match builder.slug.value_ref() { + None => { + span_err(builder.span, "diagnostic slug not specified") + .help(&format!( + "specify the slug as the first argument to the `#[diag(...)]` \ + attribute, such as `#[diag(hir_analysis_example_error)]`", + )) + .emit(); + return DiagnosticDeriveError::ErrorHandled.to_compile_error(); + } + Some(slug) => { + quote! { + let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug); } - _ => unreachable!(), - }; - - (implementation, param_ty) - } else { - span_err( - ast.span().unwrap(), - "`#[derive(SessionDiagnostic)]` can only be used on structs", - ) - .emit(); - - let implementation = DiagnosticDeriveError::ErrorHandled.to_compile_error(); - let param_ty = quote! { rustc_errors::ErrorGuaranteed }; - (implementation, param_ty) + } + }; + + let formatting_init = &builder.formatting_init; + quote! { + #init + #formatting_init + #preamble + #body + #diag } - }; + }); + let DiagnosticDeriveKind::Diagnostic { handler } = &builder.kind else { unreachable!() }; structure.gen_impl(quote! { - gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess, #param_ty> + gen impl<'__diagnostic_handler_sess, G> + rustc_errors::IntoDiagnostic<'__diagnostic_handler_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> { + #handler: &'__diagnostic_handler_sess rustc_errors::Handler + ) -> rustc_errors::DiagnosticBuilder<'__diagnostic_handler_sess, G> { use rustc_errors::IntoDiagnosticArg; #implementation } @@ -136,13 +90,7 @@ pub(crate) struct LintDiagnosticDerive<'a> { impl<'a> LintDiagnosticDerive<'a> { pub(crate) fn new(diag: syn::Ident, structure: Structure<'a>) -> Self { Self { - builder: DiagnosticDeriveBuilder { - diag, - fields: build_field_mapping(&structure), - kind: None, - code: None, - slug: None, - }, + builder: DiagnosticDeriveBuilder { diag, kind: DiagnosticDeriveKind::LintDiagnostic }, structure, } } @@ -150,75 +98,52 @@ impl<'a> LintDiagnosticDerive<'a> { pub(crate) fn into_tokens(self) -> TokenStream { let LintDiagnosticDerive { mut structure, mut builder } = self; - let ast = structure.ast(); - let implementation = { - if let syn::Data::Struct(..) = ast.data { - let preamble = builder.preamble(&structure); - let (attrs, args) = builder.body(&mut structure); - - 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) => { - 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() - )) - .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)) => { - quote! { - let mut #diag = #diag.build(rustc_errors::fluent::#slug); - } - } - }; - - let implementation = quote! { - #init - #preamble - match self { - #attrs - } - match self { - #args - } - #diag.emit(); - }; - - implementation - } else { - span_err( - ast.span().unwrap(), - "`#[derive(LintDiagnostic)]` can only be used on structs", - ) - .emit(); - - DiagnosticDeriveError::ErrorHandled.to_compile_error() + let implementation = builder.each_variant(&mut structure, |mut builder, variant| { + let preamble = builder.preamble(&variant); + let body = builder.body(&variant); + + let diag = &builder.parent.diag; + let formatting_init = &builder.formatting_init; + quote! { + #preamble + #formatting_init + #body + #diag + } + }); + + let msg = builder.each_variant(&mut structure, |mut builder, variant| { + // Collect the slug by generating the preamble. + let _ = builder.preamble(&variant); + + match builder.slug.value_ref() { + None => { + span_err(builder.span, "diagnostic slug not specified") + .help(&format!( + "specify the slug as the first argument to the attribute, such as \ + `#[diag(compiletest_example)]`", + )) + .emit(); + return DiagnosticDeriveError::ErrorHandled.to_compile_error(); + } + Some(slug) => quote! { rustc_errors::fluent::#slug.into() }, } - }; + }); let diag = &builder.diag; structure.gen_impl(quote! { gen impl<'__a> rustc_errors::DecorateLint<'__a, ()> for @Self { - fn decorate_lint(self, #diag: rustc_errors::LintDiagnosticBuilder<'__a, ()>) { + fn decorate_lint<'__b>( + self, + #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> + ) -> &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> { use rustc_errors::IntoDiagnosticArg; #implementation } + + fn msg(&self) -> rustc_errors::DiagnosticMessage { + #msg + } } }) } |