Skip to content

Commit 236d73e

Browse files
committed
target_features: control separately whether enabling and disabling a target feature is allowed
1 parent 41ab0fc commit 236d73e

File tree

5 files changed

+67
-30
lines changed

5 files changed

+67
-30
lines changed

compiler/rustc_codegen_gcc/src/gcc_util.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
9595
sess.dcx().emit_warn(unknown_feature);
9696
}
9797
Some((_, stability, _)) => {
98-
if let Err(reason) = stability.compute(&sess.target).allow_toggle() {
98+
if let Err(reason) =
99+
stability.allow_toggle(&sess.target, enable_disable == '+')
100+
{
99101
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
100102
} else if stability.requires_nightly().is_some() {
101103
// An unstable feature. Warn about using it. (It makes little sense

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
}

compiler/rustc_codegen_llvm/src/llvm_util.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -370,9 +370,9 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
370370
.rust_target_features()
371371
.iter()
372372
.filter(|(_, gate, _)| gate.in_cfg())
373-
.filter_map(|&(feature, gate, _)| {
373+
.filter_map(|(feature, gate, _)| {
374374
if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
375-
Some(feature)
375+
Some(*feature)
376376
} else {
377377
None
378378
}
@@ -714,7 +714,9 @@ pub(crate) fn global_llvm_features(
714714
sess.dcx().emit_warn(unknown_feature);
715715
}
716716
Some((_, stability, _)) => {
717-
if let Err(reason) = stability.compute(&sess.target).allow_toggle() {
717+
if let Err(reason) =
718+
stability.allow_toggle(&sess.target, enable_disable == '+')
719+
{
718720
sess.dcx().emit_warn(ForbiddenCTargetFeature { feature, reason });
719721
} else if stability.requires_nightly().is_some() {
720722
// An unstable feature. Warn about using it. (It makes little sense

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.allow_toggle(/*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(target)))
163+
.map(|(a, b, _)| (a.to_string(), b.compute(target)))
164164
.collect()
165165
}
166166
},

compiler/rustc_target/src/target_features.rs

+55-22
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub const RUSTC_SPECIAL_FEATURES: &[&str] = &["backchain"];
2020
/// `AllowToggle` 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<AllowToggle> {
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<AllowToggle> {
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, AllowToggle: HashStable<CTX>> HashStable<CTX> for Stability<AllowToggle> {
5464
#[inline]
@@ -69,51 +79,74 @@ impl<CTX, AllowToggle: HashStable<CTX>> HashStable<CTX> for Stability<AllowToggl
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<AllowToggle> Stability<AllowToggle> {
7392
/// Returns whether the feature can be queried in `cfg` ever.
7493
/// (It might still be nightly-only even if this returns `true`).
75-
pub fn in_cfg(self) -> bool {
94+
pub fn in_cfg(&self) -> bool {
7695
!matches!(self, Stability::Forbidden { .. })
7796
}
7897

7998
/// Returns the nightly feature that is required to toggle or query this target feature. Ensure
8099
/// to also check `allow_toggle()` before allowing to toggle!
81-
pub fn requires_nightly(self) -> Option<Symbol> {
100+
pub fn requires_nightly(&self) -> Option<Symbol> {
82101
match self {
83-
Stability::Unstable { nightly_feature, .. } => Some(nightly_feature),
84-
Stability::Stable { .. } => None,
85-
Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
102+
&Stability::Unstable { nightly_feature, .. } => Some(nightly_feature),
103+
&Stability::Stable { .. } => None,
104+
&Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
86105
}
87106
}
88107
}
89108

90109
impl StabilityUncomputed {
91-
pub fn compute(self, target: &Target) -> StabilityComputed {
110+
pub fn compute(&self, target: &Target) -> StabilityComputed {
92111
use Stability::*;
112+
let compute = |f: AllowToggleUncomputed| AllowToggleComputed {
113+
enable: f(target, true),
114+
disable: f(target, false),
115+
};
93116
match self {
94-
Stable { allow_toggle } => Stable { allow_toggle: allow_toggle(target) },
95-
Unstable { nightly_feature, allow_toggle } => {
96-
Unstable { nightly_feature, allow_toggle: allow_toggle(target) }
117+
&Stable { allow_toggle } => Stable { allow_toggle: compute(allow_toggle) },
118+
&Unstable { nightly_feature, allow_toggle } => {
119+
Unstable { nightly_feature, allow_toggle: compute(allow_toggle) }
97120
}
98-
Forbidden { reason } => Forbidden { reason },
121+
&Forbidden { reason } => Forbidden { reason },
122+
}
123+
}
124+
125+
pub fn allow_toggle(&self, target: &Target, enable: bool) -> Result<(), &'static str> {
126+
use Stability::*;
127+
match self {
128+
&Stable { allow_toggle } => allow_toggle(target, enable),
129+
&Unstable { allow_toggle, .. } => allow_toggle(target, enable),
130+
&Forbidden { reason } => Err(reason),
99131
}
100132
}
101133
}
102134

103135
impl StabilityComputed {
104-
pub fn allow_toggle(self) -> Result<(), &'static str> {
105-
match self {
136+
pub fn allow_toggle(&self, enable: bool) -> Result<(), &'static str> {
137+
let allow_toggle = match self {
106138
Stability::Stable { allow_toggle } => allow_toggle,
107139
Stability::Unstable { allow_toggle, .. } => allow_toggle,
108-
Stability::Forbidden { reason } => Err(reason),
109-
}
140+
Stability::Forbidden { reason } => return Err(reason),
141+
};
142+
if enable { allow_toggle.enable } else { allow_toggle.disable }
110143
}
111144
}
112145

113146
// Constructors for the list below, defaulting to "always allow toggle".
114-
const STABLE: StabilityUncomputed = Stability::Stable { allow_toggle: |_target| Ok(()) };
147+
const STABLE: StabilityUncomputed = Stability::Stable { allow_toggle: |_target, _enable| Ok(()) };
115148
const fn unstable(nightly_feature: Symbol) -> StabilityUncomputed {
116-
Stability::Unstable { nightly_feature, allow_toggle: |_target| Ok(()) }
149+
Stability::Unstable { nightly_feature, allow_toggle: |_target, _enable| Ok(()) }
117150
}
118151

119152
// Here we list target features that rustc "understands": they can be used in `#[target_feature]`
@@ -174,7 +207,7 @@ const ARM_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
174207
"fpregs",
175208
Stability::Unstable {
176209
nightly_feature: sym::arm_target_feature,
177-
allow_toggle: |target: &Target| {
210+
allow_toggle: |target: &Target, _enable| {
178211
// Only allow toggling this if the target has `soft-float` set. With `soft-float`,
179212
// `fpregs` isn't needed so changing it cannot affect the ABI.
180213
if target.has_feature("soft-float") {
@@ -471,7 +504,7 @@ const X86_FEATURES: &[(&str, StabilityUncomputed, ImpliedFeatures)] = &[
471504
"x87",
472505
Stability::Unstable {
473506
nightly_feature: sym::x87_target_feature,
474-
allow_toggle: |target: &Target| {
507+
allow_toggle: |target: &Target, _enable| {
475508
// Only allow toggling this if the target has `soft-float` set. With `soft-float`,
476509
// `fpregs` isn't needed so changing it cannot affect the ABI.
477510
if target.has_feature("soft-float") {

0 commit comments

Comments
 (0)