about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCaleb Zulawski <caleb.zulawski@gmail.com>2024-08-04 23:51:59 -0400
committerCaleb Zulawski <caleb.zulawski@gmail.com>2024-08-07 00:43:52 -0400
commit83276f568032f14b1af7e5cd9f7d928734af8d09 (patch)
treef137dd36c2b2121ecf72e267ec6fc2d7ba87cf73
parent6b96a60611c5edaa107b109b5a50e58a64a33fc2 (diff)
Hide implicit target features from diagnostics when possible
-rw-r--r--compiler/rustc_codegen_gcc/src/attributes.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/attributes.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs28
-rw-r--r--compiler/rustc_const_eval/src/interpret/call.rs13
-rw-r--r--compiler/rustc_middle/src/middle/codegen_fn_attrs.rs11
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs26
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs4
-rw-r--r--src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr4
-rw-r--r--src/tools/miri/tests/fail/function_calls/target_feature.rs2
-rw-r--r--src/tools/miri/tests/fail/function_calls/target_feature.stderr4
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs2
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs2
-rw-r--r--tests/ui/consts/const-eval/const_fn_target_feature.stderr2
-rw-r--r--tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr26
16 files changed, 89 insertions, 43 deletions
diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs
index e521551304e..5fdf2680aac 100644
--- a/compiler/rustc_codegen_gcc/src/attributes.rs
+++ b/compiler/rustc_codegen_gcc/src/attributes.rs
@@ -75,7 +75,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>(
     let function_features = codegen_fn_attrs
         .target_features
         .iter()
-        .map(|features| features.as_str())
+        .map(|features| features.name.as_str())
         .collect::<Vec<&str>>();
 
     if let Some(features) = check_tied_features(
diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs
index ad38814a68b..876f05c6277 100644
--- a/compiler/rustc_codegen_llvm/src/attributes.rs
+++ b/compiler/rustc_codegen_llvm/src/attributes.rs
@@ -496,7 +496,7 @@ pub fn from_fn_attrs<'ll, 'tcx>(
     to_add.extend(tune_cpu_attr(cx));
 
     let function_features =
-        codegen_fn_attrs.target_features.iter().map(|f| f.as_str()).collect::<Vec<&str>>();
+        codegen_fn_attrs.target_features.iter().map(|f| f.name.as_str()).collect::<Vec<&str>>();
 
     if let Some(f) = llvm_util::check_tied_features(
         cx.tcx.sess,
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index c84b844cd04..145b1ece230 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -6,6 +6,7 @@ use rustc_errors::Applicability;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
 use rustc_middle::bug;
+use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 use rustc_session::parse::feature_err;
@@ -18,7 +19,7 @@ pub fn from_target_feature(
     tcx: TyCtxt<'_>,
     attr: &ast::Attribute,
     supported_target_features: &UnordMap<String, Option<Symbol>>,
-    target_features: &mut Vec<Symbol>,
+    target_features: &mut Vec<TargetFeature>,
 ) {
     let Some(list) = attr.meta_item_list() else { return };
     let bad_item = |span| {
@@ -99,14 +100,27 @@ pub fn from_target_feature(
         }));
     }
 
-    // Add both explicit and implied target features, using a set to deduplicate
-    let mut target_features_set = UnordSet::new();
+    // Add explicit features
+    target_features.extend(
+        added_target_features.iter().copied().map(|name| TargetFeature { name, implied: false }),
+    );
+
+    // Add implied features
+    let mut implied_target_features = UnordSet::new();
     for feature in added_target_features.iter() {
-        target_features_set
+        implied_target_features
             .extend_unord(tcx.implied_target_features(*feature).clone().into_items());
     }
-    target_features_set.extend(added_target_features);
-    target_features.extend(target_features_set.into_sorted_stable_ord())
+    for feature in added_target_features.iter() {
+        implied_target_features.remove(feature);
+    }
+    target_features.extend(
+        implied_target_features
+            .into_sorted_stable_ord()
+            .iter()
+            .copied()
+            .map(|name| TargetFeature { name, implied: true }),
+    )
 }
 
 /// 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> {
     let mut target_features = tcx.sess.unstable_target_features.clone();
     if tcx.def_kind(did).has_codegen_attrs() {
         let attrs = tcx.codegen_fn_attrs(did);
-        target_features.extend(&attrs.target_features);
+        target_features.extend(attrs.target_features.iter().map(|feature| feature.name));
         match attrs.instruction_set {
             None => {}
             Some(InstructionSetAttr::ArmA32) => {
diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs
index 2c5147678e8..e5c195f08d7 100644
--- a/compiler/rustc_const_eval/src/interpret/call.rs
+++ b/compiler/rustc_const_eval/src/interpret/call.rs
@@ -317,19 +317,26 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
             && attrs
                 .target_features
                 .iter()
-                .any(|feature| !self.tcx.sess.target_features.contains(feature))
+                .any(|feature| !self.tcx.sess.target_features.contains(&feature.name))
         {
+            // Don't include implicit features in the error, unless only implicit features are
+            // missing. This should be rare, because it can only happen when an implicit feature
+            // is disabled, e.g. `+avx2,-avx`
+            let missing_explicit_features = attrs.target_features.iter().any(|feature| {
+                !feature.implied && !self.tcx.sess.target_features.contains(&feature.name)
+            });
             throw_ub_custom!(
                 fluent::const_eval_unavailable_target_features_for_fn,
                 unavailable_feats = attrs
                     .target_features
                     .iter()
-                    .filter(|&feature| !self.tcx.sess.target_features.contains(feature))
+                    .filter(|&feature| !(missing_explicit_features && feature.implied)
+                        && !self.tcx.sess.target_features.contains(&feature.name))
                     .fold(String::new(), |mut s, feature| {
                         if !s.is_empty() {
                             s.push_str(", ");
                         }
-                        s.push_str(feature.as_str());
+                        s.push_str(feature.name.as_str());
                         s
                     }),
             );
diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
index ff6a3a9c12d..b7d290e58d2 100644
--- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
+++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs
@@ -28,7 +28,7 @@ pub struct CodegenFnAttrs {
     pub link_ordinal: Option<u16>,
     /// The `#[target_feature(enable = "...")]` attribute and the enabled
     /// features (only enabled features are supported right now).
-    pub target_features: Vec<Symbol>,
+    pub target_features: Vec<TargetFeature>,
     /// The `#[linkage = "..."]` attribute on Rust-defined items and the value we found.
     pub linkage: Option<Linkage>,
     /// The `#[linkage = "..."]` attribute on foreign items and the value we found.
@@ -52,6 +52,15 @@ pub struct CodegenFnAttrs {
 }
 
 #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
+pub struct TargetFeature {
+    /// The name of the target feature (e.g. "avx")
+    pub name: Symbol,
+    /// The feature is implied by another feature, rather than explicitly added by the
+    /// `#[target_feature]` attribute
+    pub implied: bool,
+}
+
+#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
 pub struct PatchableFunctionEntry {
     /// Nops to prepend to the function
     prefix: u8,
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 48018fcaa36..0b4f0632f2b 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -5,6 +5,7 @@ use std::ops::Bound;
 use rustc_errors::DiagArgValue;
 use rustc_hir::def::DefKind;
 use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability};
+use rustc_middle::middle::codegen_fn_attrs::TargetFeature;
 use rustc_middle::mir::BorrowKind;
 use rustc_middle::span_bug;
 use rustc_middle::thir::visit::Visitor;
@@ -31,7 +32,7 @@ struct UnsafetyVisitor<'a, 'tcx> {
     safety_context: SafetyContext,
     /// The `#[target_feature]` attributes of the body. Used for checking
     /// calls to functions with `#[target_feature]` (RFC 2396).
-    body_target_features: &'tcx [Symbol],
+    body_target_features: &'tcx [TargetFeature],
     /// When inside the LHS of an assignment to a field, this is the type
     /// of the LHS and the span of the assignment expression.
     assignment_info: Option<Ty<'tcx>>,
@@ -442,14 +443,29 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
                     // is_like_wasm check in hir_analysis/src/collect.rs
                     let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
                     if !self.tcx.sess.target.options.is_like_wasm
-                        && !callee_features
-                            .iter()
-                            .all(|feature| self.body_target_features.contains(feature))
+                        && !callee_features.iter().all(|feature| {
+                            self.body_target_features.iter().any(|f| f.name == feature.name)
+                        })
                     {
+                        // Don't include implicit features in the error, unless only implicit
+                        // features are missing.
+                        let missing_explicit_features = callee_features.iter().any(|feature| {
+                            !feature.implied
+                                && !self.body_target_features.iter().any(|body_feature| {
+                                    !feature.implied && body_feature.name == feature.name
+                                })
+                        });
                         let missing: Vec<_> = callee_features
                             .iter()
                             .copied()
-                            .filter(|feature| !self.body_target_features.contains(feature))
+                            .filter(|feature| {
+                                !(missing_explicit_features && feature.implied)
+                                    && !self
+                                        .body_target_features
+                                        .iter()
+                                        .any(|body_feature| body_feature.name == feature.name)
+                            })
+                            .map(|feature| feature.name)
                             .collect();
                         let build_enabled = self
                             .tcx
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index f30732e6aaf..0f012242c37 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -479,7 +479,9 @@ impl<'tcx> Inliner<'tcx> {
             return Err("incompatible instruction set");
         }
 
-        if callee_attrs.target_features != self.codegen_fn_attrs.target_features {
+        let callee_feature_names = callee_attrs.target_features.iter().map(|f| f.name);
+        let this_feature_names = self.codegen_fn_attrs.target_features.iter().map(|f| f.name);
+        if callee_feature_names.ne(this_feature_names) {
             // In general it is not correct to inline a callee with target features that are a
             // subset of the caller. This is because the callee might contain calls, and the ABI of
             // those calls depends on the target features of the surrounding function. By moving a
diff --git a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr
index 8ebd5d2726f..2544421c7e8 100644
--- a/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr
+++ b/src/tools/miri/tests/fail/function_calls/simd_feature_flag_difference.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3
+error: Undefined Behavior: calling a function that requires unavailable target features: avx
   --> $DIR/simd_feature_flag_difference.rs:LL:CC
    |
 LL |     unsafe { foo(0.0, x) }
-   |              ^^^^^^^^^^^ calling a function that requires unavailable target features: avx, sse3, sse4.1, sse4.2, ssse3
+   |              ^^^^^^^^^^^ calling a function that requires unavailable target features: avx
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.rs b/src/tools/miri/tests/fail/function_calls/target_feature.rs
index 713d7c16f4c..84e01eb4803 100644
--- a/src/tools/miri/tests/fail/function_calls/target_feature.rs
+++ b/src/tools/miri/tests/fail/function_calls/target_feature.rs
@@ -4,7 +4,7 @@
 fn main() {
     assert!(!is_x86_feature_detected!("ssse3"));
     unsafe {
-        ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: sse3, ssse3
+        ssse3_fn(); //~ ERROR: calling a function that requires unavailable target features: ssse3
     }
 }
 
diff --git a/src/tools/miri/tests/fail/function_calls/target_feature.stderr b/src/tools/miri/tests/fail/function_calls/target_feature.stderr
index 74a862c7b68..4d3cf6e9d3b 100644
--- a/src/tools/miri/tests/fail/function_calls/target_feature.stderr
+++ b/src/tools/miri/tests/fail/function_calls/target_feature.stderr
@@ -1,8 +1,8 @@
-error: Undefined Behavior: calling a function that requires unavailable target features: sse3, ssse3
+error: Undefined Behavior: calling a function that requires unavailable target features: ssse3
   --> $DIR/target_feature.rs:LL:CC
    |
 LL |         ssse3_fn();
-   |         ^^^^^^^^^^ calling a function that requires unavailable target features: sse3, ssse3
+   |         ^^^^^^^^^^ calling a function that requires unavailable target features: ssse3
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
index 13ebe561463..7363c753617 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-aes-vaes.rs
@@ -7,7 +7,7 @@
 //@ignore-target-s390x
 //@ignore-target-thumbv7em
 //@ignore-target-wasm32
-//@compile-flags: -C target-feature=+aes,+vaes,+avx512f,+sse4.2
+//@compile-flags: -C target-feature=+aes,+vaes,+avx512f
 
 #![feature(avx512_target_feature, stdarch_x86_avx512)]
 
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
index 18693a2a97d..728f57d48f1 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx.rs
@@ -7,7 +7,7 @@
 //@ignore-target-s390x
 //@ignore-target-thumbv7em
 //@ignore-target-wasm32
-//@compile-flags: -C target-feature=+avx,+sse4.2
+//@compile-flags: -C target-feature=+avx
 
 #[cfg(target_arch = "x86")]
 use std::arch::x86::*;
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs
index f42ff6dfb51..80d125bb856 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx2.rs
@@ -7,7 +7,7 @@
 //@ignore-target-s390x
 //@ignore-target-thumbv7em
 //@ignore-target-wasm32
-//@compile-flags: -C target-feature=+avx2,+sse4.2
+//@compile-flags: -C target-feature=+avx2
 
 #[cfg(target_arch = "x86")]
 use std::arch::x86::*;
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
index 7d25854ccc0..66bfcb20f1c 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs
@@ -7,7 +7,7 @@
 //@ignore-target-s390x
 //@ignore-target-thumbv7em
 //@ignore-target-wasm32
-//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq,+sse4.2
+//@compile-flags: -C target-feature=+avx512f,+avx512vl,+avx512bitalg,+avx512vpopcntdq
 
 #![feature(avx512_target_feature)]
 #![feature(stdarch_x86_avx512)]
diff --git a/tests/ui/consts/const-eval/const_fn_target_feature.stderr b/tests/ui/consts/const-eval/const_fn_target_feature.stderr
index ad40d733546..d3a00b57ebb 100644
--- a/tests/ui/consts/const-eval/const_fn_target_feature.stderr
+++ b/tests/ui/consts/const-eval/const_fn_target_feature.stderr
@@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed
   --> $DIR/const_fn_target_feature.rs:11:24
    |
 LL | const B: () = unsafe { avx2_fn() };
-   |                        ^^^^^^^^^ calling a function that requires unavailable target features: avx, avx2, sse4.1, sse4.2
+   |                        ^^^^^^^^^ calling a function that requires unavailable target features: avx2
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
index c2227f8e847..1ddf05b40a6 100644
--- a/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
+++ b/tests/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr
@@ -4,8 +4,8 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and req
 LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
    |
-   = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
-   = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
+   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
 
 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
   --> $DIR/safe-calls.rs:29:5
@@ -13,8 +13,7 @@ error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
    |
-   = 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
-   = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
 
 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
   --> $DIR/safe-calls.rs:31:5
@@ -22,8 +21,7 @@ error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsa
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
    |
-   = 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
-   = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
 
 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
   --> $DIR/safe-calls.rs:38:5
@@ -31,7 +29,7 @@ error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and
 LL |     avx_bmi2();
    |     ^^^^^^^^^^ call to function with `#[target_feature]`
    |
-   = 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
+   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
 
 error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
   --> $DIR/safe-calls.rs:40:5
@@ -39,7 +37,7 @@ error[E0133]: call to function `Quux::avx_bmi2` with `#[target_feature]` is unsa
 LL |     Quux.avx_bmi2();
    |     ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
    |
-   = 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
+   = help: in order for the call to be safe, the context requires the following additional target features: avx and bmi2
 
 error[E0133]: call to function `avx_bmi2` with `#[target_feature]` is unsafe and requires unsafe function or block
   --> $DIR/safe-calls.rs:47:5
@@ -63,8 +61,8 @@ error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and req
 LL | const _: () = sse2();
    |               ^^^^^^ call to function with `#[target_feature]`
    |
-   = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
-   = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
+   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
 
 error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsafe and requires unsafe function or block
   --> $DIR/safe-calls.rs:64:15
@@ -72,8 +70,8 @@ error[E0133]: call to function `sse2_and_fxsr` with `#[target_feature]` is unsaf
 LL | const _: () = sse2_and_fxsr();
    |               ^^^^^^^^^^^^^^^ call to function with `#[target_feature]`
    |
-   = help: in order for the call to be safe, the context requires the following additional target features: sse, sse2, and fxsr
-   = 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]`
+   = help: in order for the call to be safe, the context requires the following additional target features: sse2 and fxsr
+   = note: the fxsr and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
 
 error[E0133]: call to function `sse2` with `#[target_feature]` is unsafe and requires unsafe block
   --> $DIR/safe-calls.rs:69:5
@@ -82,8 +80,8 @@ LL |     sse2();
    |     ^^^^^^ call to function with `#[target_feature]`
    |
    = note: for more information, see issue #71668 <https://github.com/rust-lang/rust/issues/71668>
-   = help: in order for the call to be safe, the context requires the following additional target features: sse and sse2
-   = note: the sse and sse2 target features being enabled in the build configuration does not remove the requirement to list them in `#[target_feature]`
+   = help: in order for the call to be safe, the context requires the following additional target feature: sse2
+   = note: the sse2 target feature being enabled in the build configuration does not remove the requirement to list it in `#[target_feature]`
 note: an unsafe function restricts its caller, but its body is safe by default
   --> $DIR/safe-calls.rs:68:1
    |