Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

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

0 commit comments

Comments
 (0)