Skip to content

Commit d185062

Browse files
committed
Auto merge of #133417 - RalfJung:aarch64-float-abi, r=workingjubilee
reject aarch64 target feature toggling that would change the float ABI ~~Stacked on top of #133099. Only the last two commits are new.~~ The first new commit lays the groundwork for separately controlling whether a feature may be enabled or disabled. The second commit uses that to make it illegal to *disable* the `neon` feature (which is only possible via `-Ctarget-feature`, and so the new check just adds a warning). Enabling the `neon` feature remains allowed on targets that don't disable `neon` or `fp-armv8`, which is all our built-in targets. This way, the entire PR is not a breaking change. Fixes #131058 for hardfloat targets (together with #133102 which fixed it for softfloat targets). Part of #116344.
2 parents a611773 + 74e2ac4 commit d185062

File tree

9 files changed

+116
-37
lines changed

9 files changed

+116
-37
lines changed

Diff for: compiler/rustc_codegen_gcc/src/gcc_util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
9696
}
9797
Some((_, stability, _)) => {
9898
if let Err(reason) =
99-
stability.compute_toggleability(&sess.target).allow_toggle()
99+
stability.toggle_allowed(&sess.target, enable_disable == '+')
100100
{
101101
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
102102
} else if stability.requires_nightly().is_some() {

Diff for: compiler/rustc_codegen_gcc/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -483,9 +483,9 @@ fn target_features_cfg(
483483
.rust_target_features()
484484
.iter()
485485
.filter(|(_, gate, _)| gate.in_cfg())
486-
.filter_map(|&(feature, gate, _)| {
486+
.filter_map(|(feature, gate, _)| {
487487
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
488-
Some(feature)
488+
Some(*feature)
489489
} else {
490490
None
491491
}

Diff for: compiler/rustc_codegen_llvm/src/llvm_util.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -373,9 +373,9 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
373373
.rust_target_features()
374374
.iter()
375375
.filter(|(_, gate, _)| gate.in_cfg())
376-
.filter_map(|&(feature, gate, _)| {
376+
.filter_map(|(feature, gate, _)| {
377377
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
378-
Some(feature)
378+
Some(*feature)
379379
} else {
380380
None
381381
}
@@ -718,7 +718,7 @@ pub(crate) fn global_llvm_features(
718718
}
719719
Some((_, stability, _)) => {
720720
if let Err(reason) =
721-
stability.compute_toggleability(&sess.target).allow_toggle()
721+
stability.toggle_allowed(&sess.target, enable_disable == '+')
722722
{
723723
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
724724
} else if stability.requires_nightly().is_some() {

Diff for: compiler/rustc_codegen_ssa/src/target_features.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ pub(crate) fn from_target_feature_attr(
6565

6666
// Only allow target features whose feature gates have been enabled
6767
// and which are permitted to be toggled.
68-
if let Err(reason) = stability.allow_toggle() {
68+
if let Err(reason) = stability.toggle_allowed(/*enable*/ true) {
6969
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
7070
span: item.span(),
7171
feature,
@@ -160,7 +160,7 @@ pub(crate) fn provide(providers: &mut Providers) {
160160
.target
161161
.rust_target_features()
162162
.iter()
163-
.map(|&(a, b, _)| (a.to_string(), b.compute_toggleability(target)))
163+
.map(|(a, b, _)| (a.to_string(), b.compute_toggleability(target)))
164164
.collect()
165165
}
166166
},

Diff for: compiler/rustc_target/src/spec/mod.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -2213,6 +2213,10 @@ pub struct TargetOptions {
22132213
/// `-Ctarget-cpu` but can be overwritten with `-Ctarget-features`.
22142214
/// Corresponds to `llc -mattr=$features`.
22152215
/// Note that these are LLVM feature names, not Rust feature names!
2216+
///
2217+
/// Generally it is a bad idea to use negative target features because they often interact very
2218+
/// poorly with how `-Ctarget-cpu` works. Instead, try to use a lower "base CPU" and enable the
2219+
/// features you want to use.
22162220
pub features: StaticCow<str>,
22172221
/// Direct or use GOT indirect to reference external data symbols
22182222
pub direct_access_external_data: Option<bool>,
@@ -2605,15 +2609,11 @@ impl TargetOptions {
26052609
}
26062610

26072611
pub(crate) fn has_feature(&self, search_feature: &str) -> bool {
2608-
self.features.split(',').any(|f| {
2609-
if let Some(f) = f.strip_prefix('+')
2610-
&& f == search_feature
2611-
{
2612-
true
2613-
} else {
2614-
false
2615-
}
2616-
})
2612+
self.features.split(',').any(|f| f.strip_prefix('+').is_some_and(|f| f == search_feature))
2613+
}
2614+
2615+
pub(crate) fn has_neg_feature(&self, search_feature: &str) -> bool {
2616+
self.features.split(',').any(|f| f.strip_prefix('-').is_some_and(|f| f == search_feature))
26172617
}
26182618
}
26192619

Diff for: compiler/rustc_target/src/target_features.rs

+75-20
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"];
2020
/// `Toggleability` is the type storing whether (un)stable features can be toggled:
2121
/// this is initially a function since it can depend on `Target`, but for stable hashing
2222
/// it needs to be something hashable to we have to make the type generic.
23-
#[derive(Debug, Clone, Copy)]
23+
#[derive(Debug, Clone)]
2424
pub enum Stability<Toggleability> {
2525
/// This target feature is stable, it can be used in `#[target_feature]` and
2626
/// `#[cfg(target_feature)]`.
@@ -44,11 +44,21 @@ pub enum Stability<Toggleability> {
4444
Forbidden { reason: &'static str },
4545
}
4646

47-
/// `Stability` where `allow_toggle` has not been computed yet.
4847
/// Returns `Ok` if the toggle is allowed, `Err` with an explanation of not.
49-
pub type StabilityUncomputed = Stability<fn(&Target) -> Result<(), &'static str>>;
48+
/// The `bool` indicates whether the feature is being enabled (`true`) or disabled.
49+
pub type AllowToggleUncomputed = fn(&Target, bool) -> Result<(), &'static str>;
50+
51+
/// The computed result of whether a feature can be enabled/disabled on the current target.
52+
#[derive(Debug, Clone)]
53+
pub struct AllowToggleComputed {
54+
enable: Result<(), &'static str>,
55+
disable: Result<(), &'static str>,
56+
}
57+
58+
/// `Stability` where `allow_toggle` has not been computed yet.
59+
pub type StabilityUncomputed = Stability<AllowToggleUncomputed>;
5060
/// `Stability` where `allow_toggle` has already been computed.
51-
pub type StabilityComputed = Stability<Result<(), &'static str>>;
61+
pub type StabilityComputed = Stability<AllowToggleComputed>;
5262

5363
impl<CTX, Toggleability: HashStable<CTX>> HashStable<CTX> for Stability<Toggleability> {
5464
#[inline]
@@ -69,11 +79,20 @@ impl<CTX, Toggleability: HashStable<CTX>> HashStable<CTX> for Stability<Toggleab
6979
}
7080
}
7181

82+
impl<CTX> HashStable<CTX> for AllowToggleComputed {
83+
#[inline]
84+
fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) {
85+
let AllowToggleComputed { enable, disable } = self;
86+
enable.hash_stable(hcx, hasher);
87+
disable.hash_stable(hcx, hasher);
88+
}
89+
}
90+
7291
impl<Toggleability> Stability<Toggleability> {
7392
/// Returns whether the feature can be used in `cfg(target_feature)` ever.
7493
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
7594
/// `requires_nightly`.)
76-
pub fn in_cfg(self) -> bool {
95+
pub fn in_cfg(&self) -> bool {
7796
!matches!(self, Stability::Forbidden { .. })
7897
}
7998

@@ -85,8 +104,8 @@ impl<Toggleability> Stability<Toggleability> {
85104
/// Before calling this, ensure the feature is even permitted for this use:
86105
/// - for `#[target_feature]`/`-Ctarget-feature`, check `allow_toggle()`
87106
/// - for `cfg(target_feature)`, check `in_cfg`
88-
pub fn requires_nightly(self) -> Option<Symbol> {
89-
match self {
107+
pub fn requires_nightly(&self) -> Option<Symbol> {
108+
match *self {
90109
Stability::Unstable { nightly_feature, .. } => Some(nightly_feature),
91110
Stability::Stable { .. } => None,
92111
Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
@@ -95,35 +114,49 @@ impl<Toggleability> Stability<Toggleability> {
95114
}
96115

97116
impl StabilityUncomputed {
98-
pub fn compute_toggleability(self, target: &Target) -> StabilityComputed {
117+
pub fn compute_toggleability(&self, target: &Target) -> StabilityComputed {
99118
use Stability::*;
100-
match self {
101-
Stable { allow_toggle } => Stable { allow_toggle: allow_toggle(target) },
119+
let compute = |f: AllowToggleUncomputed| AllowToggleComputed {
120+
enable: f(target, true),
121+
disable: f(target, false),
122+
};
123+
match *self {
124+
Stable { allow_toggle } => Stable { allow_toggle: compute(allow_toggle) },
102125
Unstable { nightly_feature, allow_toggle } => {
103-
Unstable { nightly_feature, allow_toggle: allow_toggle(target) }
126+
Unstable { nightly_feature, allow_toggle: compute(allow_toggle) }
104127
}
105128
Forbidden { reason } => Forbidden { reason },
106129
}
107130
}
131+
132+
pub fn toggle_allowed(&self, target: &Target, enable: bool) -> Result<(), &'static str> {
133+
use Stability::*;
134+
match *self {
135+
Stable { allow_toggle } => allow_toggle(target, enable),
136+
Unstable { allow_toggle, .. } => allow_toggle(target, enable),
137+
Forbidden { reason } => Err(reason),
138+
}
139+
}
108140
}
109141

110142
impl StabilityComputed {
111143
/// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
112144
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
113145
/// `requires_nightly`.)
114-
pub fn allow_toggle(self) -> Result<(), &'static str> {
115-
match self {
146+
pub fn toggle_allowed(&self, enable: bool) -> Result<(), &'static str> {
147+
let allow_toggle = match self {
116148
Stability::Stable { allow_toggle } => allow_toggle,
117149
Stability::Unstable { allow_toggle, .. } => allow_toggle,
118-
Stability::Forbidden { reason } => Err(reason),
119-
}
150+
Stability::Forbidden { reason } => return Err(reason),
151+
};
152+
if enable { allow_toggle.enable } else { allow_toggle.disable }
120153
}
121154
}
122155

123156
// Constructors for the list below, defaulting to "always allow toggle".
124-
const STABLE: StabilityUncomputed = Stability::Stable { allow_toggle: |_target| Ok(()) };
157+
const STABLE: StabilityUncomputed = Stability::Stable { allow_toggle: |_target, _enable| Ok(()) };
125158
const fn unstable(nightly_feature: Symbol) -> StabilityUncomputed {
126-
Stability::Unstable { nightly_feature, allow_toggle: |_target| Ok(()) }
159+
Stability::Unstable { nightly_feature, allow_toggle: |_target, _enable| Ok(()) }
127160
}
128161

129162
// Here we list target features that rustc "understands": they can be used in `#[target_feature]`
@@ -184,7 +217,7 @@ const ARM_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
184217
"fpregs",
185218
Stability::Unstable {
186219
nightly_feature: sym::arm_target_feature,
187-
allow_toggle: |target: &Target| {
220+
allow_toggle: |target: &Target, _enable| {
188221
// Only allow toggling this if the target has `soft-float` set. With `soft-float`,
189222
// `fpregs` isn't needed so changing it cannot affect the ABI.
190223
if target.has_feature("soft-float") {
@@ -257,6 +290,7 @@ const AARCH64_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
257290
("flagm", STABLE, &[]),
258291
// FEAT_FLAGM2
259292
("flagm2", unstable(sym::aarch64_unstable_target_feature), &[]),
293+
("fp-armv8", Stability::Forbidden { reason: "Rust ties `fp-armv8` to `neon`" }, &[]),
260294
// FEAT_FP16
261295
// Rust ties FP and Neon: https://github.com/rust-lang/rust/pull/91608
262296
("fp16", STABLE, &["neon"]),
@@ -292,7 +326,28 @@ const AARCH64_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
292326
// FEAT_MTE & FEAT_MTE2
293327
("mte", STABLE, &[]),
294328
// FEAT_AdvSimd & FEAT_FP
295-
("neon", STABLE, &[]),
329+
(
330+
"neon",
331+
Stability::Stable {
332+
allow_toggle: |target, enable| {
333+
if target.abi == "softfloat" {
334+
// `neon` has no ABI implications for softfloat targets, we can allow this.
335+
Ok(())
336+
} else if enable
337+
&& !target.has_neg_feature("fp-armv8")
338+
&& !target.has_neg_feature("neon")
339+
{
340+
// neon is enabled by default, and has not been disabled, so enabling it again
341+
// is redundant and we can permit it. Forbidding this would be a breaking change
342+
// since this feature is stable.
343+
Ok(())
344+
} else {
345+
Err("unsound on hard-float targets because it changes float ABI")
346+
}
347+
},
348+
},
349+
&[],
350+
),
296351
// FEAT_PAUTH (address authentication)
297352
("paca", STABLE, &[]),
298353
// FEAT_PAUTH (generic authentication)
@@ -481,7 +536,7 @@ const X86_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
481536
"x87",
482537
Stability::Unstable {
483538
nightly_feature: sym::x87_target_feature,
484-
allow_toggle: |target: &Target| {
539+
allow_toggle: |target: &Target, _enable| {
485540
// Only allow toggling this if the target has `soft-float` set. With `soft-float`,
486541
// `fpregs` isn't needed so changing it cannot affect the ABI.
487542
if target.has_feature("soft-float") {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
warning: target feature `neon` cannot be toggled with `-Ctarget-feature`: unsound on hard-float targets because it changes float ABI
2+
|
3+
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
4+
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
5+
6+
warning: 1 warning emitted
7+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//@ compile-flags: --target=aarch64-unknown-linux-gnu --crate-type=lib
2+
//@ needs-llvm-components: aarch64
3+
//@ compile-flags: -Ctarget-feature=-neon
4+
// For now this is just a warning.
5+
//@ build-pass
6+
#![feature(no_core, lang_items)]
7+
#![no_core]
8+
9+
#[lang = "sized"]
10+
pub trait Sized {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
warning: target feature `neon` cannot be toggled with `-Ctarget-feature`: unsound on hard-float targets because it changes float ABI
2+
|
3+
= note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
4+
= note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
5+
6+
warning: 1 warning emitted
7+

0 commit comments

Comments
 (0)