Skip to content

Commit 83276f5

Browse files
committed
Hide implicit target features from diagnostics when possible
1 parent 6b96a60 commit 83276f5

File tree

16 files changed

+89
-43
lines changed

16 files changed

+89
-43
lines changed

compiler/rustc_codegen_gcc/src/attributes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
7575
let function_features = codegen_fn_attrs
7676
.target_features
7777
.iter()
78-
.map(|features| features.as_str())
78+
.map(|features| features.name.as_str())
7979
.collect::<Vec<&str>>();
8080

8181
if let Some(features) = check_tied_features(

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -496,7 +496,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
496496
to_add.extend(tune_cpu_attr(cx));
497497

498498
let function_features =
499-
codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::<Vec<&str>>();
499+
codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
500500

501501
if let Some(f) = llvm_util::check_tied_features(
502502
cx.tcx.sess,

compiler/rustc_codegen_ssa/src/target_features.rs

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use rustc_errors::Applicability;
66
use rustc_hir::def::DefKind;
77
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
88
use rustc_middle::bug;
9+
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
910
use rustc_middle::query::Providers;
1011
use rustc_middle::ty::TyCtxt;
1112
use rustc_session::parse::feature_err;
@@ -18,7 +19,7 @@ pub fn from_target_feature(
1819
tcx: TyCtxt<'_>,
1920
attr: &ast::Attribute,
2021
supported_target_features: &UnordMap<String, Option<Symbol>>,
21-
target_features: &mut Vec<Symbol>,
22+
target_features: &mut Vec<TargetFeature>,
2223
) {
2324
let Some(list) = attr.meta_item_list() else { return };
2425
let bad_item = |span| {
@@ -99,14 +100,27 @@ pub fn from_target_feature(
99100
}));
100101
}
101102

102-
// Add both explicit and implied target features, using a set to deduplicate
103-
let mut target_features_set = UnordSet::new();
103+
// Add explicit features
104+
target_features.extend(
105+
added_target_features.iter().copied().map(|name| TargetFeature { name, implied: false }),
106+
);
107+
108+
// Add implied features
109+
let mut implied_target_features = UnordSet::new();
104110
for feature in added_target_features.iter() {
105-
target_features_set
111+
implied_target_features
106112
.extend_unord(tcx.implied_target_features(*feature).clone().into_items());
107113
}
108-
target_features_set.extend(added_target_features);
109-
target_features.extend(target_features_set.into_sorted_stable_ord())
114+
for feature in added_target_features.iter() {
115+
implied_target_features.remove(feature);
116+
}
117+
target_features.extend(
118+
implied_target_features
119+
.into_sorted_stable_ord()
120+
.iter()
121+
.copied()
122+
.map(|name| TargetFeature { name, implied: true }),
123+
)
110124
}
111125

112126
/// Computes the set of target features used in a function for the purposes of
@@ -115,7 +129,7 @@ fn asm_target_features(tcx: TyCtxt<'_>, did: DefId) -> &FxIndexSet<Symbol> {
115129
let mut target_features = tcx.sess.unstable_target_features.clone();
116130
if tcx.def_kind(did).has_codegen_attrs() {
117131
let attrs = tcx.codegen_fn_attrs(did);
118-
target_features.extend(&attrs.target_features);
132+
target_features.extend(attrs.target_features.iter().map(|feature| feature.name));
119133
match attrs.instruction_set {
120134
None => {}
121135
Some(InstructionSetAttr::ArmA32) => {

compiler/rustc_const_eval/src/interpret/call.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,19 +317,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
317317
&& attrs
318318
.target_features
319319
.iter()
320-
.any(|feature| !self.tcx.sess.target_features.contains(feature))
320+
.any(|feature| !self.tcx.sess.target_features.contains(&feature.name))
321321
{
322+
// Don't include implicit features in the error, unless only implicit features are
323+
// missing. This should be rare, because it can only happen when an implicit feature
324+
// is disabled, e.g. `+avx2,-avx`
325+
let missing_explicit_features = attrs.target_features.iter().any(|feature| {
326+
!feature.implied && !self.tcx.sess.target_features.contains(&feature.name)
327+
});
322328
throw_ub_custom!(
323329
fluent::const_eval_unavailable_target_features_for_fn,
324330
unavailable_feats = attrs
325331
.target_features
326332
.iter()
327-
.filter(|&feature| !self.tcx.sess.target_features.contains(feature))
333+
.filter(|&feature| !(missing_explicit_features && feature.implied)
334+
&& !self.tcx.sess.target_features.contains(&feature.name))
328335
.fold(String::new(), |mut s, feature| {
329336
if !s.is_empty() {
330337
s.push_str(", ");
331338
}
332-
s.push_str(feature.as_str());
339+
s.push_str(feature.name.as_str());
333340
s
334341
}),
335342
);

compiler/rustc_middle/src/middle/codegen_fn_attrs.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub struct CodegenFnAttrs {
2828
pub link_ordinal: Option<u16>,
2929
/// The `#[target_feature(enable = "...")]` attribute and the enabled
3030
/// features (only enabled features are supported right now).
31-
pub target_features: Vec<Symbol>,
31+
pub target_features: Vec<TargetFeature>,
3232
/// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
3333
pub linkage: Option<Linkage>,
3434
/// The `#[linkage = "..."]` attribute on foreign items and the value we found.
@@ -51,6 +51,15 @@ pub struct CodegenFnAttrs {
5151
pub patchable_function_entry: Option<PatchableFunctionEntry>,
5252
}
5353

54+
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
55+
pub struct TargetFeature {
56+
/// The name of the target feature (e.g. "avx")
57+
pub name: Symbol,
58+
/// The feature is implied by another feature, rather than explicitly added by the
59+
/// `#[target_feature]` attribute
60+
pub implied: bool,
61+
}
62+
5463
#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
5564
pub struct PatchableFunctionEntry {
5665
/// Nops to prepend to the function

compiler/rustc_mir_build/src/check_unsafety.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::ops::Bound;
55
use rustc_errors::DiagArgValue;
66
use rustc_hir::def::DefKind;
77
use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability};
8+
use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
89
use rustc_middle::mir::BorrowKind;
910
use rustc_middle::span_bug;
1011
use rustc_middle::thir::visit::Visitor;
@@ -31,7 +32,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
3132
safety_context: SafetyContext,
3233
/// The `#[target_feature]` attributes of the body. Used for checking
3334
/// calls to functions with `#[target_feature]` (RFC 2396).
34-
body_target_features: &'tcx [Symbol],
35+
body_target_features: &'tcx [TargetFeature],
3536
/// When inside the LHS of an assignment to a field, this is the type
3637
/// of the LHS and the span of the assignment expression.
3738
assignment_info: Option<Ty<'tcx>>,
@@ -442,14 +443,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
442443
// is_like_wasm check in hir_analysis/src/collect.rs
443444
let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
444445
if !self.tcx.sess.target.options.is_like_wasm
445-
&& !callee_features
446-
.iter()
447-
.all(|feature| self.body_target_features.contains(feature))
446+
&& !callee_features.iter().all(|feature| {
447+
self.body_target_features.iter().any(|f| f.name == feature.name)
448+
})
448449
{
450+
// Don't include implicit features in the error, unless only implicit
451+
// features are missing.
452+
let missing_explicit_features = callee_features.iter().any(|feature| {
453+
!feature.implied
454+
&& !self.body_target_features.iter().any(|body_feature| {
455+
!feature.implied && body_feature.name == feature.name
456+
})
457+
});
449458
let missing: Vec<_> = callee_features
450459
.iter()
451460
.copied()
452-
.filter(|feature| !self.body_target_features.contains(feature))
461+
.filter(|feature| {
462+
!(missing_explicit_features && feature.implied)
463+
&& !self
464+
.body_target_features
465+
.iter()
466+
.any(|body_feature| body_feature.name == feature.name)
467+
})
468+
.map(|feature| feature.name)
453469
.collect();
454470
let build_enabled = self
455471
.tcx

compiler/rustc_mir_transform/src/inline.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,9 @@ impl<'tcx> Inliner<'tcx> {
479479
return Err("incompatible instruction set");
480480
}
481481

482-
if callee_attrs.target_features != self.codegen_fn_attrs.target_features {
482+
let callee_feature_names = callee_attrs.target_features.iter().map(|f| f.name);
483+
let this_feature_names = self.codegen_fn_attrs.target_features.iter().map(|f| f.name);
484+
if callee_feature_names.ne(this_feature_names) {
483485
// In general it is not correct to inline a callee with target features that are a
484486
// subset of the caller. This is because the callee might contain calls, and the ABI of
485487
// those calls depends on the target features of the surrounding function. By moving a

src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3
1+
error: Undefined Behavior: calling a function that requires unavailable target features: avx
22
--> $DIR/simd_feature_flag_difference.rs:LL:CC
33
|
44
LL | unsafe { foo(0.0, x) }
5-
| ^^^^^^^^^^^ calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3
5+
| ^^^^^^^^^^^ calling a function that requires unavailable target features: avx
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

src/tools/miri/tests/fail/function_calls/target_feature.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
fn main() {
55
assert!(!is_x86_feature_detected!("ssse3"));
66
unsafe {
7-
ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: sse3, ssse3
7+
ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: ssse3
88
}
99
}
1010

src/tools/miri/tests/fail/function_calls/target_feature.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: calling a function that requires unavailable target features: sse3, ssse3
1+
error: Undefined Behavior: calling a function that requires unavailable target features: ssse3
22
--> $DIR/target_feature.rs:LL:CC
33
|
44
LL | ssse3_fn();
5-
| ^^^^^^^^^^ calling a function that requires unavailable target features: sse3, ssse3
5+
| ^^^^^^^^^^ calling a function that requires unavailable target features: ssse3
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//@ignore-target-s390x
88
//@ignore-target-thumbv7em
99
//@ignore-target-wasm32
10-
//@compile-flags: -C target-feature=+aes,+vaes,+avx512f,+sse4.2
10+
//@compile-flags: -C target-feature=+aes,+vaes,+avx512f
1111

1212
#![feature(avx512_target_feature, stdarch_x86_avx512)]
1313

src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//@ignore-target-s390x
88
//@ignore-target-thumbv7em
99
//@ignore-target-wasm32
10-
//@compile-flags: -C target-feature=+avx,+sse4.2
10+
//@compile-flags: -C target-feature=+avx
1111

1212
#[cfg(target_arch = "x86")]
1313
use std::arch::x86::*;

src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//@ignore-target-s390x
88
//@ignore-target-thumbv7em
99
//@ignore-target-wasm32
10-
//@compile-flags: -C target-feature=+avx2,+sse4.2
10+
//@compile-flags: -C target-feature=+avx2
1111

1212
#[cfg(target_arch = "x86")]
1313
use std::arch::x86::*;

src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//@ignore-target-s390x
88
//@ignore-target-thumbv7em
99
//@ignore-target-wasm32
10-
//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq,+sse4.2
10+
//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq
1111

1212
#![feature(avx512_target_feature)]
1313
#![feature(stdarch_x86_avx512)]

tests/ui/consts/const-eval/const_fn_target_feature.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
22
--> $DIR/const_fn_target_feature.rs:11:24
33
|
44
LL | const B: () = unsafe { avx2_fn() };
5-
| ^^^^^^^^^ calling a function that requires unavailable target features: avx, avx2, sse4.1, sse4.2
5+
| ^^^^^^^^^ calling a function that requires unavailable target features: avx2
66

77
error: aborting due to 1 previous error
88

tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,42 +4,40 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and req
44
LL | sse2();
55
| ^^^^^^ call to function with `#[target_feature]`
66
|
7-
= help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
8-
= note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
7+
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
8+
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
99

1010
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
1111
--> $DIR/safe-calls.rs:29:5
1212
|
1313
LL | avx_bmi2();
1414
| ^^^^^^^^^^ call to function with `#[target_feature]`
1515
|
16-
= help: in order for the call to be safe, the context requires the following additional target features: avx, sse, sse2, sse3, sse4.1, sse4.2, ssse3, and bmi2
17-
= note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
16+
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
1817

1918
error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
2019
--> $DIR/safe-calls.rs:31:5
2120
|
2221
LL | Quux.avx_bmi2();
2322
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
2423
|
25-
= help: in order for the call to be safe, the context requires the following additional target features: avx, sse, sse2, sse3, sse4.1, sse4.2, ssse3, and bmi2
26-
= note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
24+
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
2725

2826
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
2927
--> $DIR/safe-calls.rs:38:5
3028
|
3129
LL | avx_bmi2();
3230
| ^^^^^^^^^^ call to function with `#[target_feature]`
3331
|
34-
= help: in order for the call to be safe, the context requires the following additional target features: avx, sse3, sse4.1, sse4.2, ssse3, and bmi2
32+
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
3533

3634
error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
3735
--> $DIR/safe-calls.rs:40:5
3836
|
3937
LL | Quux.avx_bmi2();
4038
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
4139
|
42-
= help: in order for the call to be safe, the context requires the following additional target features: avx, sse3, sse4.1, sse4.2, ssse3, and bmi2
40+
= help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
4341

4442
error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
4543
--> $DIR/safe-calls.rs:47:5
@@ -63,17 +61,17 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and req
6361
LL | const _: () = sse2();
6462
| ^^^^^^ call to function with `#[target_feature]`
6563
|
66-
= help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
67-
= note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
64+
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
65+
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
6866

6967
error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block
7068
--> $DIR/safe-calls.rs:64:15
7169
|
7270
LL | const _: () = sse2_and_fxsr();
7371
| ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
7472
|
75-
= help: in order for the call to be safe, the context requires the following additional target features: sse, sse2, and fxsr
76-
= note: the fxsr, sse, and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
73+
= help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr
74+
= note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
7775

7876
error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block
7977
--> $DIR/safe-calls.rs:69:5
@@ -82,8 +80,8 @@ LL | sse2();
8280
| ^^^^^^ call to function with `#[target_feature]`
8381
|
8482
= note: for more information, see issue #71668 <https://github.com/rust-lang/rust/issues/71668>
85-
= help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
86-
= note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
83+
= help: in order for the call to be safe, the context requires the following additional target feature: sse2
84+
= note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
8785
note: an unsafe function restricts its caller, but its body is safe by default
8886
--> $DIR/safe-calls.rs:68:1
8987
|

0 commit comments

Comments
 (0)