generalize 'forbidden feature' concept so that even (un)stable feature can be invalid to toggle
Also rename some things for extra clarity
This commit is contained in:
parent
1f3bf231e1
commit
2d887a5c5c
13 changed files with 468 additions and 401 deletions
|
@ -11,7 +11,7 @@ use rustc_middle::ty::TyCtxt;
|
|||
use rustc_session::parse::feature_err;
|
||||
use rustc_span::Span;
|
||||
use rustc_span::symbol::{Symbol, sym};
|
||||
use rustc_target::target_features::{self, Stability};
|
||||
use rustc_target::target_features;
|
||||
|
||||
use crate::errors;
|
||||
|
||||
|
@ -20,7 +20,7 @@ use crate::errors;
|
|||
pub(crate) fn from_target_feature_attr(
|
||||
tcx: TyCtxt<'_>,
|
||||
attr: &ast::Attribute,
|
||||
rust_target_features: &UnordMap<String, target_features::Stability>,
|
||||
rust_target_features: &UnordMap<String, target_features::StabilityComputed>,
|
||||
target_features: &mut Vec<TargetFeature>,
|
||||
) {
|
||||
let Some(list) = attr.meta_item_list() else { return };
|
||||
|
@ -63,32 +63,24 @@ pub(crate) fn from_target_feature_attr(
|
|||
return None;
|
||||
};
|
||||
|
||||
// Only allow target features whose feature gates have been enabled.
|
||||
let allowed = match stability {
|
||||
Stability::Forbidden { .. } => false,
|
||||
Stability::Stable => true,
|
||||
Stability::Unstable(name) => rust_features.enabled(*name),
|
||||
};
|
||||
if !allowed {
|
||||
match stability {
|
||||
Stability::Stable => unreachable!(),
|
||||
&Stability::Unstable(lang_feature_name) => {
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
lang_feature_name,
|
||||
item.span(),
|
||||
format!("the target feature `{feature}` is currently unstable"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
Stability::Forbidden { reason } => {
|
||||
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
||||
span: item.span(),
|
||||
feature,
|
||||
reason,
|
||||
});
|
||||
}
|
||||
}
|
||||
// Only allow target features whose feature gates have been enabled
|
||||
// and which are permitted to be toggled.
|
||||
if let Err(reason) = stability.allow_toggle() {
|
||||
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
|
||||
span: item.span(),
|
||||
feature,
|
||||
reason,
|
||||
});
|
||||
} else if let Some(nightly_feature) = stability.requires_nightly()
|
||||
&& !rust_features.enabled(nightly_feature)
|
||||
{
|
||||
feature_err(
|
||||
&tcx.sess,
|
||||
nightly_feature,
|
||||
item.span(),
|
||||
format!("the target feature `{feature}` is currently unstable"),
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
Some(Symbol::intern(feature))
|
||||
}));
|
||||
|
@ -156,18 +148,19 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
*providers = Providers {
|
||||
rust_target_features: |tcx, cnum| {
|
||||
assert_eq!(cnum, LOCAL_CRATE);
|
||||
let target = &tcx.sess.target;
|
||||
if tcx.sess.opts.actually_rustdoc {
|
||||
// rustdoc needs to be able to document functions that use all the features, so
|
||||
// whitelist them all
|
||||
rustc_target::target_features::all_rust_features()
|
||||
.map(|(a, b)| (a.to_string(), b))
|
||||
.map(|(a, b)| (a.to_string(), b.compute(target)))
|
||||
.collect()
|
||||
} else {
|
||||
tcx.sess
|
||||
.target
|
||||
.rust_target_features()
|
||||
.iter()
|
||||
.map(|&(a, b, _)| (a.to_string(), b))
|
||||
.map(|&(a, b, _)| (a.to_string(), b.compute(target)))
|
||||
.collect()
|
||||
}
|
||||
},
|
||||
|
|
|
@ -45,7 +45,9 @@ pub trait CodegenBackend {
|
|||
|
||||
fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {}
|
||||
|
||||
fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
|
||||
/// Returns the features that should be set in `cfg(target_features)`.
|
||||
/// RUSTC_SPECIFIC_FEATURES should be skipped here, those are handled outside codegen.
|
||||
fn target_features_cfg(&self, _sess: &Session, _allow_unstable: bool) -> Vec<Symbol> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue