diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 24f731c01996d..1e178880865b2 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -62,7 +62,7 @@ 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(false) && !rust_features.enabled(nightly_feature) { feature_err( @@ -315,7 +315,7 @@ 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(true).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. @@ -346,7 +346,7 @@ 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(true).is_none())) { Some(Symbol::intern(feature)) } else { diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 963b167be424d..eedc826d28aab 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -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. + CfgOnlyStable( + /// 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,10 @@ 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::CfgOnlyStable { .. } | Stability::Unstable { .. } + ) } /// Returns the nightly feature that is required to toggle this target feature via @@ -48,9 +58,19 @@ 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 { + /// + /// The `is_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, is_cfg: bool) -> Option { match *self { Stability::Unstable(nightly_feature) => Some(nightly_feature), + Stability::CfgOnlyStable(nightly_feature) => { + if is_cfg { + None + } else { + Some(nightly_feature) + } + } Stability::Stable { .. } => None, Stability::Forbidden { .. } => panic!("forbidden features should not reach this far"), } @@ -61,7 +81,9 @@ impl Stability { /// `requires_nightly`.) pub fn toggle_allowed(&self) -> Result<(), &'static str> { match self { - Stability::Unstable(_) | Stability::Stable { .. } => Ok(()), + Stability::Unstable(_) | Stability::CfgOnlyStable(_) | Stability::Stable { .. } => { + Ok(()) + } Stability::Forbidden { reason } => Err(reason), } }