diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs index bcc754fd984d..8c7bf61949a2 100644 --- a/compiler/rustc_resolve/src/errors.rs +++ b/compiler/rustc_resolve/src/errors.rs @@ -1521,20 +1521,24 @@ pub(crate) struct RedundantImportVisibility { #[diag("unknown diagnostic attribute")] pub(crate) struct UnknownDiagnosticAttribute { #[subdiagnostic] - pub typo: Option, + pub help: Option, } #[derive(Subdiagnostic)] -#[suggestion( - "an attribute with a similar name exists", - style = "verbose", - code = "{typo_name}", - applicability = "machine-applicable" -)] -pub(crate) struct UnknownDiagnosticAttributeTypoSugg { - #[primary_span] - pub span: Span, - pub typo_name: Symbol, +pub(crate) enum UnknownDiagnosticAttributeHelp { + #[suggestion( + "an attribute with a similar name exists", + style = "verbose", + code = "{typo_name}", + applicability = "machine-applicable" + )] + Typo { + #[primary_span] + span: Span, + typo_name: Symbol, + }, + #[help("add `#![feature({$feature})]` to the crate attributes to enable")] + UseFeature { feature: Symbol }, } // FIXME: Make this properly translatable. diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index f106d88a8320..13bda9c98c0a 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -723,26 +723,44 @@ fn smart_resolve_macro_path( if res == Res::NonMacroAttr(NonMacroAttrKind::Tool) && let [namespace, attribute, ..] = &*path.segments && namespace.ident.name == sym::diagnostic - && !DIAGNOSTIC_ATTRIBUTES.iter().any(|(attr, stable)| { + && !DIAGNOSTIC_ATTRIBUTES.iter().any(|(attr, feature)| { attribute.ident.name == *attr - && stable.is_none_or(|f| self.tcx.features().enabled(f)) + && feature.is_none_or(|f| self.tcx.features().enabled(f)) }) { + let name = attribute.ident.name; let span = attribute.span(); - let candidates = DIAGNOSTIC_ATTRIBUTES - .iter() - .filter_map(|(sym, stable)| { - stable.is_none_or(|f| self.tcx.features().enabled(f)).then_some(*sym) + + let help = 'help: { + if self.tcx.sess.is_nightly_build() { + for (attr, feature) in DIAGNOSTIC_ATTRIBUTES { + if let Some(feature) = *feature + && *attr == name + { + break 'help Some(errors::UnknownDiagnosticAttributeHelp::UseFeature { + feature, + }); + } + } + } + + let candidates = DIAGNOSTIC_ATTRIBUTES + .iter() + .filter_map(|(attr, feature)| { + feature.is_none_or(|f| self.tcx.features().enabled(f)).then_some(*attr) + }) + .collect::>(); + + find_best_match_for_name(&candidates, name, None).map(|typo_name| { + errors::UnknownDiagnosticAttributeHelp::Typo { span, typo_name } }) - .collect::>(); - let typo = find_best_match_for_name(&candidates, attribute.ident.name, None) - .map(|typo_name| errors::UnknownDiagnosticAttributeTypoSugg { span, typo_name }); + }; self.tcx.sess.psess.buffer_lint( UNKNOWN_DIAGNOSTIC_ATTRIBUTES, span, node_id, - errors::UnknownDiagnosticAttribute { typo }, + errors::UnknownDiagnosticAttribute { help }, ); } diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr index 83d6448ed570..593120edd170 100644 --- a/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr +++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-move.stderr @@ -4,6 +4,7 @@ warning: unknown diagnostic attribute LL | #[diagnostic::on_move(message = "Foo")] | ^^^^^^^ | + = help: add `#![feature(diagnostic_on_move)]` to the crate attributes to enable = note: `#[warn(unknown_diagnostic_attributes)]` (part of `#[warn(unknown_or_malformed_diagnostic_attributes)]`) on by default error[E0382]: use of moved value: `foo` diff --git a/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr index f6d7ffadacea..d9c8071339b7 100644 --- a/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr +++ b/tests/ui/feature-gates/feature-gate-diagnostic-on-unknown.stderr @@ -10,6 +10,7 @@ error: unknown diagnostic attribute LL | #[diagnostic::on_unknown(message = "Tada")] | ^^^^^^^^^^ | + = help: add `#![feature(diagnostic_on_unknown)]` to the crate attributes to enable note: the lint level is defined here --> $DIR/feature-gate-diagnostic-on-unknown.rs:1:9 |