Skip to content

Commit 9b60e0f

Browse files
Rollup merge of rust-lang#155962 - romancardenas:cfg-only-stable-target-feature, r=RalfJung
`rustc`: `target_features`: allow for `cfg`-only stable `target_features` This PR introduces a new stabilization level for `target_features`: `CfgOnlyStable`. The motivation is allowing the Rust compiler to expose `target_features` of targets so users can use `cfg(target_feature = "feature")` for conditional blocks depending on target features. However, `CfgOnlyStable` cannot be used for `#[target_feature(enable = "feature")]`, as this is still considered unstable. Accordingly, the compiler will still raise an error if these expressions are used on stable. This PR relates partially to rust-lang#150257. As discussed, for RISC-V targets, having the `"d"`, `"e"`, and `"f"` target features exposed will allow baremetal developers to adapt the code depending on the target's properties. r? @RalfJung
2 parents c68c66a + ee9a01a commit 9b60e0f

3 files changed

Lines changed: 54 additions & 16 deletions

File tree

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1212,9 +1212,10 @@ pub(crate) struct UnknownCTargetFeature<'a> {
12121212

12131213
#[derive(Diagnostic)]
12141214
#[diag("unstable feature specified for `-Ctarget-feature`: `{$feature}`")]
1215-
#[note("this feature is not stably supported; its behavior can change in the future")]
1215+
#[note("{$note}; its behavior can change in the future")]
12161216
pub(crate) struct UnstableCTargetFeature<'a> {
12171217
pub feature: &'a str,
1218+
pub note: &'a str,
12181219
}
12191220

12201221
#[derive(Diagnostic)]

compiler/rustc_codegen_ssa/src/target_features.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,15 @@ pub(crate) fn from_target_feature_attr(
6262
feature: feature_str,
6363
reason,
6464
});
65-
} else if let Some(nightly_feature) = stability.requires_nightly()
65+
} else if let Some(nightly_feature) = stability.requires_nightly(/* in_cfg */ false)
6666
&& !rust_features.enabled(nightly_feature)
6767
{
68-
feature_err(
69-
&tcx.sess,
70-
nightly_feature,
71-
feature_span,
72-
format!("the target feature `{feature}` is currently unstable"),
73-
)
74-
.emit();
68+
let explain = if stability.is_cfg_stable_toggle_unstable() {
69+
format!("the target feature `{feature}` is allowed in cfg but unstable otherwise")
70+
} else {
71+
format!("the target feature `{feature}` is currently unstable")
72+
};
73+
feature_err(&tcx.sess, nightly_feature, feature_span, explain).emit();
7574
} else {
7675
// Add this and the implied features.
7776
for &name in tcx.implied_target_features(feature) {
@@ -315,12 +314,19 @@ pub fn cfg_target_feature<'a, const N: usize>(
315314
enabled: if enable { "enabled" } else { "disabled" },
316315
reason,
317316
});
318-
} else if stability.requires_nightly().is_some() {
317+
} else if stability.requires_nightly(/* in_cfg */ false).is_some() {
319318
// An unstable feature. Warn about using it. It makes little sense
320319
// to hard-error here since we just warn about fully unknown
321320
// features above.
322-
sess.dcx()
323-
.emit_warn(errors::UnstableCTargetFeature { feature: base_feature });
321+
let note = if stability.is_cfg_stable_toggle_unstable() {
322+
"this feature is allowed in cfg but unstable otherwise"
323+
} else {
324+
"this feature is not stably supported"
325+
};
326+
sess.dcx().emit_warn(errors::UnstableCTargetFeature {
327+
feature: base_feature,
328+
note,
329+
});
324330
}
325331
}
326332
}
@@ -346,7 +352,8 @@ pub fn cfg_target_feature<'a, const N: usize>(
346352
// "forbidden" features.
347353
if allow_unstable
348354
|| (gate.in_cfg()
349-
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
355+
&& (sess.is_nightly_build()
356+
|| gate.requires_nightly(/* in_cfg */ true).is_none()))
350357
{
351358
Some(Symbol::intern(feature))
352359
} else {

compiler/rustc_target/src/target_features.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ pub enum Stability {
1717
/// This target feature is stable, it can be used in `#[target_feature]` and
1818
/// `#[cfg(target_feature)]`.
1919
Stable,
20+
/// This target feature is cfg-stable. It can be used for `#[cfg(target_feature)]` on stable,
21+
/// but using it in `#[target_feature]` requires the given nightly feature.
22+
CfgStableToggleUnstable(
23+
/// This must be a *language* feature, or else rustc will ICE when reporting a missing
24+
/// feature gate!
25+
Symbol,
26+
),
2027
/// This target feature is unstable. It is only present in `#[cfg(target_feature)]` on
2128
/// nightly and using it in `#[target_feature]` requires enabling the given nightly feature.
2229
Unstable(
@@ -37,7 +44,12 @@ impl Stability {
3744
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
3845
/// `requires_nightly`.)
3946
pub fn in_cfg(&self) -> bool {
40-
matches!(self, Stability::Stable | Stability::Unstable { .. })
47+
matches!(
48+
self,
49+
Stability::Stable
50+
| Stability::CfgStableToggleUnstable { .. }
51+
| Stability::Unstable { .. }
52+
)
4153
}
4254

4355
/// Returns the nightly feature that is required to toggle this target feature via
@@ -48,20 +60,38 @@ impl Stability {
4860
/// Before calling this, ensure the feature is even permitted for this use:
4961
/// - for `#[target_feature]`/`-Ctarget-feature`, check `toggle_allowed()`
5062
/// - for `cfg(target_feature)`, check `in_cfg()`
51-
pub fn requires_nightly(&self) -> Option<Symbol> {
63+
///
64+
/// The `in_cfg` parameter is used to determine whether it will be used in
65+
/// `cfg(target_feature)` (true) or `#[target_feature]`/`-Ctarget-feature` (false)
66+
pub fn requires_nightly(&self, in_cfg: bool) -> Option<Symbol> {
5267
match *self {
5368
Stability::Unstable(nightly_feature) => Some(nightly_feature),
69+
Stability::CfgStableToggleUnstable(nightly_feature) => {
70+
if in_cfg {
71+
None
72+
} else {
73+
Some(nightly_feature)
74+
}
75+
}
5476
Stability::Stable { .. } => None,
5577
Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
5678
}
5779
}
5880

81+
/// Returns whether the feature is cfg-stable but still requires a nightly feature gate to
82+
/// be used in `#[target_feature]`/`-Ctarget-feature`.
83+
pub fn is_cfg_stable_toggle_unstable(&self) -> bool {
84+
matches!(self, Stability::CfgStableToggleUnstable { .. })
85+
}
86+
5987
/// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
6088
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
6189
/// `requires_nightly`.)
6290
pub fn toggle_allowed(&self) -> Result<(), &'static str> {
6391
match self {
64-
Stability::Unstable(_) | Stability::Stable { .. } => Ok(()),
92+
Stability::Unstable(_)
93+
| Stability::CfgStableToggleUnstable(_)
94+
| Stability::Stable { .. } => Ok(()),
6595
Stability::Forbidden { reason } => Err(reason),
6696
}
6797
}

0 commit comments

Comments
 (0)