diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs index 46068f8c868cd..7fbe3bc2888c3 100644 --- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs +++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs @@ -6,8 +6,8 @@ use crate::diagnostics::error::{ }; use crate::diagnostics::utils::{ build_field_mapping, is_doc_comment, report_error_if_not_applied_to_span, report_type_error, - should_generate_set_arg, type_is_unit, type_matches_path, FieldInfo, FieldInnerTy, FieldMap, - HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, + should_generate_set_arg, type_is_bool, type_is_unit, type_matches_path, FieldInfo, + FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind, }; use proc_macro2::{Ident, Span, TokenStream}; use quote::{format_ident, quote}; @@ -414,12 +414,15 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> { Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) } SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => { - if type_matches_path(info.ty.inner_type(), &["rustc_span", "Span"]) { + let inner = info.ty.inner_type(); + if type_matches_path(inner, &["rustc_span", "Span"]) { Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug)) - } else if type_is_unit(info.ty.inner_type()) { + } else if type_is_unit(inner) + || (matches!(info.ty, FieldInnerTy::Plain(_)) && type_is_bool(inner)) + { Ok(self.add_subdiagnostic(&fn_ident, slug)) } else { - report_type_error(attr, "`Span` or `()`")? + report_type_error(attr, "`Span`, `bool` or `()`")? } } SubdiagnosticKind::Suggestion { diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs index 27b8f676f3fbb..65bb154d7f39d 100644 --- a/compiler/rustc_macros/src/diagnostics/utils.rs +++ b/compiler/rustc_macros/src/diagnostics/utils.rs @@ -50,6 +50,11 @@ pub(crate) fn type_is_unit(ty: &Type) -> bool { if let Type::Tuple(TypeTuple { elems, .. }) = ty { elems.is_empty() } else { false } } +/// Checks whether the type `ty` is `bool`. +pub(crate) fn type_is_bool(ty: &Type) -> bool { + type_matches_path(ty, &["bool"]) +} + /// Reports a type error for field with `attr`. pub(crate) fn report_type_error( attr: &Attribute, @@ -192,6 +197,11 @@ impl<'ty> FieldInnerTy<'ty> { #inner } }, + FieldInnerTy::Plain(t) if type_is_bool(t) => quote! { + if #binding { + #inner + } + }, FieldInnerTy::Plain(..) => quote! { #inner }, } } diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index 01e6434b07567..3151c712566af 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -513,6 +513,19 @@ struct OptUnitField { bar: Option<()>, } +#[derive(Diagnostic)] +#[diag(no_crate_example)] +struct BoolField { + #[primary_span] + spans: Span, + #[help] + foo: bool, + #[help(no_crate_help)] + //~^ ERROR the `#[help(...)]` attribute can only be applied to fields of type `Span`, `bool` or `()` + // only allow plain 'bool' fields + bar: Option, +} + #[derive(Diagnostic)] #[diag(no_crate_example, code = "E0123")] struct LabelWithTrailingPath { diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index fc0cd8419e440..513b675e5dd41 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -352,8 +352,14 @@ error: invalid applicability LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")] | ^^^^^^^^^^^^^^^^^^^^^^^^ +error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `bool` or `()` + --> $DIR/diagnostic-derive.rs:523:5 + | +LL | #[help(no_crate_help)] + | ^^^^^^^^^^^^^^^^^^^^^^ + error: `#[label(foo)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:519:29 + --> $DIR/diagnostic-derive.rs:532:29 | LL | #[label(no_crate_label, foo)] | ^^^ @@ -361,19 +367,19 @@ LL | #[label(no_crate_label, foo)] = help: a diagnostic slug must be the first argument to the attribute error: `#[label(foo = ...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:527:29 + --> $DIR/diagnostic-derive.rs:540:29 | LL | #[label(no_crate_label, foo = "...")] | ^^^^^^^^^^^ error: `#[label(foo(...))]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:535:29 + --> $DIR/diagnostic-derive.rs:548:29 | LL | #[label(no_crate_label, foo("..."))] | ^^^^^^^^^^ error: `#[primary_span]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:547:5 + --> $DIR/diagnostic-derive.rs:560:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ @@ -381,13 +387,13 @@ LL | #[primary_span] = help: the `primary_span` field attribute is not valid for lint diagnostics error: `#[error(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:567:1 + --> $DIR/diagnostic-derive.rs:580:1 | LL | #[error(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:567:1 + --> $DIR/diagnostic-derive.rs:580:1 | LL | / #[error(no_crate_example, code = "E0123")] LL | | @@ -399,13 +405,13 @@ LL | | struct ErrorAttribute {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[warn_(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:574:1 + --> $DIR/diagnostic-derive.rs:587:1 | LL | #[warn_(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:574:1 + --> $DIR/diagnostic-derive.rs:587:1 | LL | / #[warn_(no_crate_example, code = "E0123")] LL | | @@ -417,13 +423,13 @@ LL | | struct WarnAttribute {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:581:1 + --> $DIR/diagnostic-derive.rs:594:1 | LL | #[lint(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:581:1 + --> $DIR/diagnostic-derive.rs:594:1 | LL | / #[lint(no_crate_example, code = "E0123")] LL | | @@ -435,19 +441,19 @@ LL | | struct LintAttributeOnSessionDiag {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:588:1 + --> $DIR/diagnostic-derive.rs:601:1 | LL | #[lint(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:588:1 + --> $DIR/diagnostic-derive.rs:601:1 | LL | #[lint(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:588:1 + --> $DIR/diagnostic-derive.rs:601:1 | LL | / #[lint(no_crate_example, code = "E0123")] LL | | @@ -460,19 +466,19 @@ LL | | struct LintAttributeOnLintDiag {} = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]` error: specified multiple times - --> $DIR/diagnostic-derive.rs:598:53 + --> $DIR/diagnostic-derive.rs:611:53 | LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] | ^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:598:39 + --> $DIR/diagnostic-derive.rs:611:39 | LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] | ^^^^^^^^^^^^ error: wrong types for suggestion - --> $DIR/diagnostic-derive.rs:607:24 + --> $DIR/diagnostic-derive.rs:620:24 | LL | suggestion: (Span, usize), | ^^^^^ @@ -480,7 +486,7 @@ LL | suggestion: (Span, usize), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: wrong types for suggestion - --> $DIR/diagnostic-derive.rs:615:17 + --> $DIR/diagnostic-derive.rs:628:17 | LL | suggestion: (Span,), | ^^^^^^^ @@ -488,13 +494,13 @@ LL | suggestion: (Span,), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:622:5 + --> $DIR/diagnostic-derive.rs:635:5 | LL | #[suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:629:1 + --> $DIR/diagnostic-derive.rs:642:1 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -502,7 +508,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] = help: consider creating a `Subdiagnostic` instead error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:632:1 + --> $DIR/diagnostic-derive.rs:645:1 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -510,7 +516,7 @@ LL | #[multipart_suggestion()] = help: consider creating a `Subdiagnostic` instead error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:636:5 + --> $DIR/diagnostic-derive.rs:649:5 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -518,7 +524,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] = help: consider creating a `Subdiagnostic` instead error: `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:644:1 + --> $DIR/diagnostic-derive.rs:657:1 | LL | #[suggestion(no_crate_suggestion, code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -526,7 +532,7 @@ LL | #[suggestion(no_crate_suggestion, code = "...")] = help: `#[label]` and `#[suggestion]` can only be applied to fields error: `#[label]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:653:1 + --> $DIR/diagnostic-derive.rs:666:1 | LL | #[label] | ^^^^^^^^ @@ -534,7 +540,7 @@ LL | #[label] = help: `#[label]` and `#[suggestion]` can only be applied to fields error: `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:687:5 + --> $DIR/diagnostic-derive.rs:700:5 | LL | #[subdiagnostic(bad)] | ^^^^^^^^^^^^^^^^^^^^^ @@ -542,13 +548,13 @@ LL | #[subdiagnostic(bad)] = help: `eager` is the only supported nested attribute for `subdiagnostic` error: `#[subdiagnostic = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:695:5 + --> $DIR/diagnostic-derive.rs:708:5 | LL | #[subdiagnostic = "bad"] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:703:5 + --> $DIR/diagnostic-derive.rs:716:5 | LL | #[subdiagnostic(bad, bad)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -556,7 +562,7 @@ LL | #[subdiagnostic(bad, bad)] = help: `eager` is the only supported nested attribute for `subdiagnostic` error: `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:711:5 + --> $DIR/diagnostic-derive.rs:724:5 | LL | #[subdiagnostic("bad")] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -564,7 +570,7 @@ LL | #[subdiagnostic("bad")] = help: `eager` is the only supported nested attribute for `subdiagnostic` error: `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:719:5 + --> $DIR/diagnostic-derive.rs:732:5 | LL | #[subdiagnostic(eager)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -572,25 +578,25 @@ LL | #[subdiagnostic(eager)] = help: eager subdiagnostics are not supported on lints error: expected at least one string literal for `code(...)` - --> $DIR/diagnostic-derive.rs:777:18 + --> $DIR/diagnostic-derive.rs:790:18 | LL | #[suggestion(code())] | ^^^^^^ error: `code(...)` must contain only string literals - --> $DIR/diagnostic-derive.rs:785:23 + --> $DIR/diagnostic-derive.rs:798:23 | LL | #[suggestion(code(foo))] | ^^^ error: `code = "..."`/`code(...)` must contain only string literals - --> $DIR/diagnostic-derive.rs:793:18 + --> $DIR/diagnostic-derive.rs:806:18 | LL | #[suggestion(code = 3)] | ^^^^^^^^ error: `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:808:5 + --> $DIR/diagnostic-derive.rs:821:5 | LL | #[suggestion(no_crate_suggestion, code = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -612,43 +618,43 @@ LL | #[nonsense] | ^^^^^^^^ error: cannot find attribute `error` in this scope - --> $DIR/diagnostic-derive.rs:567:3 + --> $DIR/diagnostic-derive.rs:580:3 | LL | #[error(no_crate_example, code = "E0123")] | ^^^^^ error: cannot find attribute `warn_` in this scope - --> $DIR/diagnostic-derive.rs:574:3 + --> $DIR/diagnostic-derive.rs:587:3 | LL | #[warn_(no_crate_example, code = "E0123")] | ^^^^^ help: a built-in attribute with a similar name exists: `warn` error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive.rs:581:3 + --> $DIR/diagnostic-derive.rs:594:3 | LL | #[lint(no_crate_example, code = "E0123")] | ^^^^ help: a built-in attribute with a similar name exists: `link` error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive.rs:588:3 + --> $DIR/diagnostic-derive.rs:601:3 | LL | #[lint(no_crate_example, code = "E0123")] | ^^^^ help: a built-in attribute with a similar name exists: `link` error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:629:3 + --> $DIR/diagnostic-derive.rs:642:3 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:632:3 + --> $DIR/diagnostic-derive.rs:645:3 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^ error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:636:7 + --> $DIR/diagnostic-derive.rs:649:7 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ @@ -670,7 +676,7 @@ note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg` --> $COMPILER_DIR/rustc_errors/src/diagnostic_builder.rs:LL:CC = note: this error originates in the derive macro `Diagnostic` which comes from the expansion of the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 84 previous errors +error: aborting due to 85 previous errors Some errors have detailed explanations: E0277, E0425. For more information about an error, try `rustc --explain E0277`.