mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-06 08:36:52 -04:00
Rollup merge of #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/rust#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
This commit is contained in:
@@ -1212,9 +1212,10 @@ pub(crate) struct UnknownCTargetFeature<'a> {
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag("unstable feature specified for `-Ctarget-feature`: `{$feature}`")]
|
||||
#[note("this feature is not stably supported; its behavior can change in the future")]
|
||||
#[note("{$note}; its behavior can change in the future")]
|
||||
pub(crate) struct UnstableCTargetFeature<'a> {
|
||||
pub feature: &'a str,
|
||||
pub note: &'a str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
|
||||
@@ -62,16 +62,15 @@ pub(crate) fn from_target_feature_attr(
|
||||
feature: feature_str,
|
||||
reason,
|
||||
});
|
||||
} else if let Some(nightly_feature) = stability.requires_nightly()
|
||||
} else if let Some(nightly_feature) = stability.requires_nightly(/* in_cfg */ false)
|
||||
&& !rust_features.enabled(nightly_feature)
|
||||
{
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
nightly_feature,
|
||||
feature_span,
|
||||
format!("the target feature `{feature}` is currently unstable"),
|
||||
)
|
||||
.emit();
|
||||
let explain = if stability.is_cfg_stable_toggle_unstable() {
|
||||
format!("the target feature `{feature}` is allowed in cfg but unstable otherwise")
|
||||
} else {
|
||||
format!("the target feature `{feature}` is currently unstable")
|
||||
};
|
||||
feature_err(&tcx.sess, nightly_feature, feature_span, explain).emit();
|
||||
} else {
|
||||
// Add this and the implied features.
|
||||
for &name in tcx.implied_target_features(feature) {
|
||||
@@ -315,12 +314,19 @@ pub fn cfg_target_feature<'a, const N: usize>(
|
||||
enabled: if enable { "enabled" } else { "disabled" },
|
||||
reason,
|
||||
});
|
||||
} else if stability.requires_nightly().is_some() {
|
||||
} else if stability.requires_nightly(/* in_cfg */ false).is_some() {
|
||||
// An unstable feature. Warn about using it. It makes little sense
|
||||
// to hard-error here since we just warn about fully unknown
|
||||
// features above.
|
||||
sess.dcx()
|
||||
.emit_warn(errors::UnstableCTargetFeature { feature: base_feature });
|
||||
let note = if stability.is_cfg_stable_toggle_unstable() {
|
||||
"this feature is allowed in cfg but unstable otherwise"
|
||||
} else {
|
||||
"this feature is not stably supported"
|
||||
};
|
||||
sess.dcx().emit_warn(errors::UnstableCTargetFeature {
|
||||
feature: base_feature,
|
||||
note,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -346,7 +352,8 @@ pub fn cfg_target_feature<'a, const N: usize>(
|
||||
// "forbidden" features.
|
||||
if allow_unstable
|
||||
|| (gate.in_cfg()
|
||||
&& (sess.is_nightly_build() || gate.requires_nightly().is_none()))
|
||||
&& (sess.is_nightly_build()
|
||||
|| gate.requires_nightly(/* in_cfg */ true).is_none()))
|
||||
{
|
||||
Some(Symbol::intern(feature))
|
||||
} else {
|
||||
|
||||
@@ -17,6 +17,13 @@ pub enum Stability {
|
||||
/// This target feature is stable, it can be used in `#[target_feature]` and
|
||||
/// `#[cfg(target_feature)]`.
|
||||
Stable,
|
||||
/// This target feature is cfg-stable. It can be used for `#[cfg(target_feature)]` on stable,
|
||||
/// but using it in `#[target_feature]` requires the given nightly feature.
|
||||
CfgStableToggleUnstable(
|
||||
/// This must be a *language* feature, or else rustc will ICE when reporting a missing
|
||||
/// feature gate!
|
||||
Symbol,
|
||||
),
|
||||
/// This target feature is unstable. It is only present in `#[cfg(target_feature)]` on
|
||||
/// nightly and using it in `#[target_feature]` requires enabling the given nightly feature.
|
||||
Unstable(
|
||||
@@ -37,7 +44,12 @@ impl Stability {
|
||||
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
|
||||
/// `requires_nightly`.)
|
||||
pub fn in_cfg(&self) -> bool {
|
||||
matches!(self, Stability::Stable | Stability::Unstable { .. })
|
||||
matches!(
|
||||
self,
|
||||
Stability::Stable
|
||||
| Stability::CfgStableToggleUnstable { .. }
|
||||
| Stability::Unstable { .. }
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns the nightly feature that is required to toggle this target feature via
|
||||
@@ -48,20 +60,38 @@ impl Stability {
|
||||
/// Before calling this, ensure the feature is even permitted for this use:
|
||||
/// - for `#[target_feature]`/`-Ctarget-feature`, check `toggle_allowed()`
|
||||
/// - for `cfg(target_feature)`, check `in_cfg()`
|
||||
pub fn requires_nightly(&self) -> Option<Symbol> {
|
||||
///
|
||||
/// The `in_cfg` parameter is used to determine whether it will be used in
|
||||
/// `cfg(target_feature)` (true) or `#[target_feature]`/`-Ctarget-feature` (false)
|
||||
pub fn requires_nightly(&self, in_cfg: bool) -> Option<Symbol> {
|
||||
match *self {
|
||||
Stability::Unstable(nightly_feature) => Some(nightly_feature),
|
||||
Stability::CfgStableToggleUnstable(nightly_feature) => {
|
||||
if in_cfg {
|
||||
None
|
||||
} else {
|
||||
Some(nightly_feature)
|
||||
}
|
||||
}
|
||||
Stability::Stable { .. } => None,
|
||||
Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the feature is cfg-stable but still requires a nightly feature gate to
|
||||
/// be used in `#[target_feature]`/`-Ctarget-feature`.
|
||||
pub fn is_cfg_stable_toggle_unstable(&self) -> bool {
|
||||
matches!(self, Stability::CfgStableToggleUnstable { .. })
|
||||
}
|
||||
|
||||
/// Returns whether the feature may be toggled via `#[target_feature]` or `-Ctarget-feature`.
|
||||
/// (It might still be nightly-only even if this returns `true`, so make sure to also check
|
||||
/// `requires_nightly`.)
|
||||
pub fn toggle_allowed(&self) -> Result<(), &'static str> {
|
||||
match self {
|
||||
Stability::Unstable(_) | Stability::Stable { .. } => Ok(()),
|
||||
Stability::Unstable(_)
|
||||
| Stability::CfgStableToggleUnstable(_)
|
||||
| Stability::Stable { .. } => Ok(()),
|
||||
Stability::Forbidden { reason } => Err(reason),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user