From 698f8c2f01ea549d77d7dc3338a12e04c11057b9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:02:58 +0200 Subject: Adding upstream version 1.64.0+dfsg1. Signed-off-by: Daniel Baumann --- .../rustc_macros/src/diagnostics/diagnostic.rs | 225 +++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 compiler/rustc_macros/src/diagnostics/diagnostic.rs (limited to 'compiler/rustc_macros/src/diagnostics/diagnostic.rs') diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs new file mode 100644 index 000000000..6b5b8b593 --- /dev/null +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -0,0 +1,225 @@ +#![deny(unused_must_use)] + +use crate::diagnostics::diagnostic_builder::{DiagnosticDeriveBuilder, DiagnosticDeriveKind}; +use crate::diagnostics::error::{span_err, DiagnosticDeriveError}; +use crate::diagnostics::utils::{build_field_mapping, 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> { + 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 { + Self { + builder: DiagnosticDeriveBuilder { + diag, + fields: build_field_mapping(&structure), + kind: None, + code: None, + slug: None, + }, + 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! { () } + } + _ => 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) + } + }; + + structure.gen_impl(quote! { + gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess, #param_ty> + for @Self + { + fn into_diagnostic( + self, + #sess: &'__session_diagnostic_sess rustc_session::parse::ParseSess + ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess, #param_ty> { + use rustc_errors::IntoDiagnosticArg; + #implementation + } + } + }) + } +} + +/// The central struct for constructing the `decorate_lint` method from an annotated struct. +pub(crate) struct LintDiagnosticDerive<'a> { + structure: Structure<'a>, + builder: DiagnosticDeriveBuilder, +} + +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, + }, + structure, + } + } + + 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 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, ()>) { + use rustc_errors::IntoDiagnosticArg; + #implementation + } + } + }) + } +} -- cgit v1.2.3