Add feature hint for unstable diagnostic attributes

This commit is contained in:
mejrs
2026-04-12 18:38:17 +02:00
parent 55cd47658c
commit 08a12dc143
4 changed files with 45 additions and 21 deletions
+15 -11
View File
@@ -1521,20 +1521,24 @@ pub(crate) struct RedundantImportVisibility {
#[diag("unknown diagnostic attribute")]
pub(crate) struct UnknownDiagnosticAttribute {
#[subdiagnostic]
pub typo: Option<UnknownDiagnosticAttributeTypoSugg>,
pub help: Option<UnknownDiagnosticAttributeHelp>,
}
#[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.
+28 -10
View File
@@ -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::<Vec<_>>();
find_best_match_for_name(&candidates, name, None).map(|typo_name| {
errors::UnknownDiagnosticAttributeHelp::Typo { span, typo_name }
})
.collect::<Vec<_>>();
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 },
);
}
@@ -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`
@@ -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
|