Skip to content

Commit 8f5bcc0

Browse files
authored
Rollup merge of rust-lang#153966 - folkertdev:suggest-target-feature-names, r=mati865
suggest valid features when target feature is invalid I run into this quite frequently, where I remember some part of a feature name but not the exact name. Now this emits suggestions like ``` 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 ```
2 parents 267748b + cd4fd28 commit 8f5bcc0

4 files changed

Lines changed: 68 additions & 31 deletions

File tree

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ use std::process::ExitStatus;
88

99
use rustc_errors::codes::*;
1010
use rustc_errors::{
11-
Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, IntoDiagArg, Level, msg,
11+
Diag, DiagArgValue, DiagCtxtHandle, DiagSymbolList, Diagnostic, EmissionGuarantee, IntoDiagArg,
12+
Level, msg,
1213
};
1314
use rustc_macros::{Diagnostic, Subdiagnostic};
1415
use rustc_middle::ty::layout::LayoutError;
@@ -1249,20 +1250,29 @@ pub(crate) struct FeatureNotValid<'a> {
12491250
#[label("`{$feature}` is not valid for this target")]
12501251
pub span: Span,
12511252
#[subdiagnostic]
1252-
pub plus_hint: Option<RemovePlusFromFeatureName<'a>>,
1253+
pub hint: FeatureNotValidHint<'a>,
12531254
}
12541255

12551256
#[derive(Subdiagnostic)]
1256-
#[suggestion(
1257-
"consider removing the leading `+` in the feature name",
1258-
code = "enable = \"{stripped}\"",
1259-
applicability = "maybe-incorrect",
1260-
style = "verbose"
1261-
)]
1262-
pub struct RemovePlusFromFeatureName<'a> {
1263-
#[primary_span]
1264-
pub span: Span,
1265-
pub stripped: &'a str,
1257+
pub(crate) enum FeatureNotValidHint<'a> {
1258+
#[suggestion(
1259+
"consider removing the leading `+` in the feature name",
1260+
code = "enable = \"{stripped}\"",
1261+
applicability = "maybe-incorrect",
1262+
style = "verbose"
1263+
)]
1264+
RemovePlusFromFeatureName {
1265+
#[primary_span]
1266+
span: Span,
1267+
stripped: &'a str,
1268+
},
1269+
#[help(
1270+
"valid names are: {$possibilities}{$and_more ->
1271+
[0] {\"\"}
1272+
*[other] {\" \"}and {$and_more} more
1273+
}"
1274+
)]
1275+
ValidFeatureNames { possibilities: DiagSymbolList<&'a str>, and_more: usize },
12661276
}
12671277

12681278
#[derive(Diagnostic)]

compiler/rustc_codegen_ssa/src/target_features.rs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ use rustc_middle::ty::TyCtxt;
99
use rustc_session::Session;
1010
use rustc_session::lint::builtin::AARCH64_SOFTFLOAT_NEON;
1111
use rustc_session::parse::feature_err;
12-
use rustc_span::{Span, Symbol, sym};
12+
use rustc_span::{Span, Symbol, edit_distance, sym};
1313
use rustc_target::spec::Arch;
1414
use rustc_target::target_features::{RUSTC_SPECIFIC_FEATURES, Stability};
1515
use smallvec::SmallVec;
1616

17-
use crate::errors::{FeatureNotValid, RemovePlusFromFeatureName};
17+
use crate::errors::{FeatureNotValid, FeatureNotValidHint};
1818
use crate::{errors, target_features};
1919

2020
/// Compute the enabled target features from the `#[target_feature]` function attribute.
@@ -32,15 +32,25 @@ pub(crate) fn from_target_feature_attr(
3232
for &(feature, feature_span) in features {
3333
let feature_str = feature.as_str();
3434
let Some(stability) = rust_target_features.get(feature_str) else {
35-
let plus_hint = feature_str
36-
.strip_prefix('+')
37-
.filter(|stripped| rust_target_features.contains_key(*stripped))
38-
.map(|stripped| RemovePlusFromFeatureName { span: feature_span, stripped });
39-
tcx.dcx().emit_err(FeatureNotValid {
40-
feature: feature_str,
41-
span: feature_span,
42-
plus_hint,
43-
});
35+
let hint = if let Some(stripped) = feature_str.strip_prefix('+')
36+
&& rust_target_features.contains_key(stripped)
37+
{
38+
FeatureNotValidHint::RemovePlusFromFeatureName { span: feature_span, stripped }
39+
} else {
40+
// Show the 5 feature names that are most similar to the input.
41+
let mut valid_names: Vec<_> =
42+
rust_target_features.keys().map(|name| name.as_str()).into_sorted_stable_ord();
43+
valid_names.sort_by_key(|name| {
44+
edit_distance::edit_distance(name, feature.as_str(), 5).unwrap_or(usize::MAX)
45+
});
46+
valid_names.truncate(5);
47+
48+
FeatureNotValidHint::ValidFeatureNames {
49+
possibilities: valid_names.into(),
50+
and_more: rust_target_features.len().saturating_sub(5),
51+
}
52+
};
53+
tcx.dcx().emit_err(FeatureNotValid { feature: feature_str, span: feature_span, hint });
4454
continue;
4555
};
4656

tests/ui/target-feature/invalid-attribute.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,12 @@ fn main() {
119119
//~| NOTE `+sse2` is not valid for this target
120120
unsafe fn hey() {}
121121

122-
#[target_feature(enable = "+sse5")]
123-
//~^ ERROR `+sse5` is not valid for this target
124-
//~| NOTE `+sse5` is not valid for this target
125-
unsafe fn typo() {}
122+
#[target_feature(enable = "sse5")]
123+
//~^ ERROR `sse5` is not valid for this target
124+
//~| NOTE `sse5` is not valid for this target
125+
unsafe fn typo_sse() {}
126+
127+
#[target_feature(enable = "avx512")]
128+
//~^ ERROR `avx512` is not valid for this target
129+
//~| NOTE `avx512` is not valid for this target
130+
unsafe fn typo_avx512() {}

tests/ui/target-feature/invalid-attribute.stderr

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ error: the feature named `foo` is not valid for this target
160160
|
161161
LL | #[target_feature(enable = "foo")]
162162
| ^^^^^^^^^^^^^^ `foo` is not valid for this target
163+
|
164+
= help: valid names are: `fma`, `xop`, `adx`, `aes`, and `avx` and 74 more
163165

164166
error[E0046]: not all trait items implemented, missing: `foo`
165167
--> $DIR/invalid-attribute.rs:81:1
@@ -205,13 +207,23 @@ LL - #[target_feature(enable = "+sse2")]
205207
LL + #[target_feature(enable = "sse2")]
206208
|
207209

208-
error: the feature named `+sse5` is not valid for this target
210+
error: the feature named `sse5` is not valid for this target
209211
--> $DIR/invalid-attribute.rs:122:18
210212
|
211-
LL | #[target_feature(enable = "+sse5")]
212-
| ^^^^^^^^^^^^^^^^ `+sse5` is not valid for this target
213+
LL | #[target_feature(enable = "sse5")]
214+
| ^^^^^^^^^^^^^^^ `sse5` is not valid for this target
215+
|
216+
= help: valid names are: `sse`, `sse2`, `sse3`, `sse4a`, and `ssse3` and 74 more
217+
218+
error: the feature named `avx512` is not valid for this target
219+
--> $DIR/invalid-attribute.rs:127:18
220+
|
221+
LL | #[target_feature(enable = "avx512")]
222+
| ^^^^^^^^^^^^^^^^^ `avx512` is not valid for this target
223+
|
224+
= help: valid names are: `avx512f`, `avx2`, `avx512bw`, `avx512cd`, and `avx512dq` and 74 more
213225

214-
error: aborting due to 25 previous errors
226+
error: aborting due to 26 previous errors
215227

216228
Some errors have detailed explanations: E0046, E0053, E0539, E0658.
217229
For more information about an error, try `rustc --explain E0046`.

0 commit comments

Comments
 (0)