diff options
Diffstat (limited to '')
-rw-r--r-- | compiler/rustc_macros/src/diagnostics/diagnostic.rs | 72 |
1 files changed, 63 insertions, 9 deletions
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic.rs b/compiler/rustc_macros/src/diagnostics/diagnostic.rs index ef1985b96..684835d8c 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic.rs @@ -5,6 +5,7 @@ use crate::diagnostics::error::{span_err, DiagnosticDeriveError}; 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. @@ -28,8 +29,8 @@ impl<'a> DiagnosticDerive<'a> { 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 preamble = builder.preamble(variant); + let body = builder.body(variant); let diag = &builder.parent.diag; let DiagnosticDeriveKind::Diagnostic { handler } = &builder.parent.kind else { @@ -38,13 +39,24 @@ impl<'a> DiagnosticDerive<'a> { let init = match builder.slug.value_ref() { None => { span_err(builder.span, "diagnostic slug not specified") - .help(&format!( + .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) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => { + span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match") + .note(format!( + "slug is `{slug_name}` but the crate name is `{crate_name}`" + )) + .help(format!( + "expected a slug starting with `{slug_prefix}_...`" + )) + .emit(); + return DiagnosticDeriveError::ErrorHandled.to_compile_error(); + } Some(slug) => { quote! { let mut #diag = #handler.struct_diagnostic(rustc_errors::fluent::#slug); @@ -69,6 +81,8 @@ impl<'a> DiagnosticDerive<'a> { for @Self where G: rustc_errors::EmissionGuarantee { + + #[track_caller] fn into_diagnostic( self, #handler: &'__diagnostic_handler_sess rustc_errors::Handler @@ -99,8 +113,8 @@ impl<'a> LintDiagnosticDerive<'a> { let LintDiagnosticDerive { 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 preamble = builder.preamble(variant); + let body = builder.body(variant); let diag = &builder.parent.diag; let formatting_init = &builder.formatting_init; @@ -114,25 +128,41 @@ impl<'a> LintDiagnosticDerive<'a> { let msg = builder.each_variant(&mut structure, |mut builder, variant| { // Collect the slug by generating the preamble. - let _ = builder.preamble(&variant); + let _ = builder.preamble(variant); match builder.slug.value_ref() { None => { span_err(builder.span, "diagnostic slug not specified") - .help(&format!( + .help(format!( "specify the slug as the first argument to the attribute, such as \ `#[diag(compiletest_example)]`", )) .emit(); - return DiagnosticDeriveError::ErrorHandled.to_compile_error(); + DiagnosticDeriveError::ErrorHandled.to_compile_error() + } + Some(slug) if let Some( Mismatch { slug_name, crate_name, slug_prefix }) = Mismatch::check(slug) => { + span_err(slug.span().unwrap(), "diagnostic slug and crate name do not match") + .note(format!( + "slug is `{slug_name}` but the crate name is `{crate_name}`" + )) + .help(format!( + "expected a slug starting with `{slug_prefix}_...`" + )) + .emit(); + DiagnosticDeriveError::ErrorHandled.to_compile_error() + } + Some(slug) => { + quote! { + rustc_errors::fluent::#slug.into() + } } - 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 { + #[track_caller] fn decorate_lint<'__b>( self, #diag: &'__b mut rustc_errors::DiagnosticBuilder<'__a, ()> @@ -148,3 +178,27 @@ impl<'a> LintDiagnosticDerive<'a> { }) } } + +struct Mismatch { + slug_name: String, + crate_name: String, + slug_prefix: String, +} + +impl Mismatch { + /// Checks whether the slug starts with the crate name it's in. + fn check(slug: &syn::Path) -> Option<Mismatch> { + // If this is missing we're probably in a test, so bail. + let crate_name = std::env::var("CARGO_CRATE_NAME").ok()?; + + // If we're not in a "rustc_" crate, bail. + let Some(("rustc", slug_prefix)) = crate_name.split_once("_") else { return None }; + + let slug_name = slug.segments.first()?.ident.to_string(); + if !slug_name.starts_with(slug_prefix) { + Some(Mismatch { slug_name, slug_prefix: slug_prefix.to_string(), crate_name }) + } else { + None + } + } +} |