suggest valid features when target feature is invalid

This commit is contained in:
Folkert de Vries
2026-03-16 17:36:53 +01:00
parent ec15ca96ff
commit cd4fd289cd
4 changed files with 68 additions and 31 deletions
+22 -12
View File
@@ -8,7 +8,8 @@
use rustc_errors::codes::*;
use rustc_errors::{
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, msg,
Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, IntoDiagArg,
Level, msg,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_middle::ty::layout::LayoutError;
@@ -1249,20 +1250,29 @@ pub(crate) struct FeatureNotValid<'a> {
#[label("`{$feature}` is not valid for this target")]
pub span: Span,
#[subdiagnostic]
pub plus_hint: Option<RemovePlusFromFeatureName<'a>>,
pub hint: FeatureNotValidHint<'a>,
}
#[derive(Subdiagnostic)]
#[suggestion(
"consider removing the leading `+` in the feature name",
code = "enable = \"{stripped}\"",
applicability = "maybe-incorrect",
style = "verbose"
)]
pub struct RemovePlusFromFeatureName<'a> {
#[primary_span]
pub span: Span,
pub stripped: &'a str,
pub(crate) enum FeatureNotValidHint<'a> {
#[suggestion(
"consider removing the leading `+` in the feature name",
code = "enable = \"{stripped}\"",
applicability = "maybe-incorrect",
style = "verbose"
)]
RemovePlusFromFeatureName {
#[primary_span]
span: Span,
stripped: &'a str,
},
#[help(
"valid names are: {$possibilities}{$and_more ->
[0] {\"\"}
*[other] {\" \"}and {$and_more} more
}"
)]
ValidFeatureNames { possibilities: DiagSymbolList<&'a str>, and_more: usize },
}
#[derive(Diagnostic)]
@@ -9,12 +9,12 @@
use rustc_session::Session;
use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};
use rustc_span::{Span, Symbol, edit_distance, sym};
use rustc_target::spec::Arch;
use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability};
use smallvec::SmallVec;
use crate::errors::{FeatureNotValid, RemovePlusFromFeatureName};
use crate::errors::{FeatureNotValid, FeatureNotValidHint};
use crate::{errors, target_features};
/// Compute the enabled target features from the `#[target_feature]` function attribute.
@@ -32,15 +32,25 @@ pub(crate) fn from_target_feature_attr(
for &(feature, feature_span) in features {
let feature_str = feature.as_str();
let Some(stability) = rust_target_features.get(feature_str) else {
let plus_hint = feature_str
.strip_prefix('+')
.filter(|stripped| rust_target_features.contains_key(*stripped))
.map(|stripped| RemovePlusFromFeatureName { span: feature_span, stripped });
tcx.dcx().emit_err(FeatureNotValid {
feature: feature_str,
span: feature_span,
plus_hint,
});
let hint = if let Some(stripped) = feature_str.strip_prefix('+')
&& rust_target_features.contains_key(stripped)
{
FeatureNotValidHint::RemovePlusFromFeatureName { span: feature_span, stripped }
} else {
// Show the 5 feature names that are most similar to the input.
let mut valid_names: Vec<_> =
rust_target_features.keys().map(|name| name.as_str()).into_sorted_stable_ord();
valid_names.sort_by_key(|name| {
edit_distance::edit_distance(name, feature.as_str(), 5).unwrap_or(usize::MAX)
});
valid_names.truncate(5);
FeatureNotValidHint::ValidFeatureNames {
possibilities: valid_names.into(),
and_more: rust_target_features.len().saturating_sub(5),
}
};
tcx.dcx().emit_err(FeatureNotValid { feature: feature_str, span: feature_span, hint });
continue;
};
+9 -4
View File
@@ -119,7 +119,12 @@ fn main() {
//~| NOTE `+sse2` is not valid for this target
unsafe fn hey() {}
#[target_feature(enable = "+sse5")]
//~^ ERROR `+sse5` is not valid for this target
//~| NOTE `+sse5` is not valid for this target
unsafe fn typo() {}
#[target_feature(enable = "sse5")]
//~^ ERROR `sse5` is not valid for this target
//~| NOTE `sse5` is not valid for this target
unsafe fn typo_sse() {}
#[target_feature(enable = "avx512")]
//~^ ERROR `avx512` is not valid for this target
//~| NOTE `avx512` is not valid for this target
unsafe fn typo_avx512() {}
@@ -160,6 +160,8 @@ error: the feature named `foo` is not valid for this target
|
LL | #[target_feature(enable = "foo")]
| ^^^^^^^^^^^^^^ `foo` is not valid for this target
|
= help: valid names are: `fma`, `xop`, `adx`, `aes`, and `avx` and 74 more
error[E0046]: not all trait items implemented, missing: `foo`
--> $DIR/invalid-attribute.rs:81:1
@@ -205,13 +207,23 @@ LL - #[target_feature(enable = "+sse2")]
LL + #[target_feature(enable = "sse2")]
|
error: the feature named `+sse5` is not valid for this target
error: the feature named `sse5` is not valid for this target
--> $DIR/invalid-attribute.rs:122:18
|
LL | #[target_feature(enable = "+sse5")]
| ^^^^^^^^^^^^^^^^ `+sse5` is not valid for this target
LL | #[target_feature(enable = "sse5")]
| ^^^^^^^^^^^^^^^ `sse5` is not valid for this target
|
= help: valid names are: `sse`, `sse2`, `sse3`, `sse4a`, and `ssse3` and 74 more
error: aborting due to 25 previous errors
error: the feature named `avx512` is not valid for this target
--> $DIR/invalid-attribute.rs:127:18
|
LL | #[target_feature(enable = "avx512")]
| ^^^^^^^^^^^^^^^^^ `avx512` is not valid for this target
|
= help: valid names are: `avx512f`, `avx2`, `avx512bw`, `avx512cd`, and `avx512dq` and 74 more
error: aborting due to 26 previous errors
Some errors have detailed explanations: E0046, E0053, E0539, E0658.
For more information about an error, try `rustc --explain E0046`.