1
Fork 0

also fix potential issues with mixed stable/unstable target features in rustdoc

This commit is contained in:
Ralf Jung 2025-02-25 20:38:13 +01:00
parent b6f2240000
commit 039af88e09

View file

@ -10,7 +10,7 @@ use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_span::{Span, Symbol, sym};
use rustc_target::target_features;
use rustc_target::target_features::{self, Stability};
use crate::errors;
@ -87,10 +87,7 @@ pub(crate) fn from_target_feature_attr(
// But ensure the ABI does not forbid enabling this.
// Here we do assume that LLVM doesn't add even more implied features
// we don't know about, at least no features that would have ABI effects!
// We skip this check in rustdoc, like we skip all target feature related checks.
if !tcx.sess.opts.actually_rustdoc
&& abi_feature_constraints.incompatible.contains(&name.as_str())
{
if abi_feature_constraints.incompatible.contains(&name.as_str()) {
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
span: item.span(),
feature: name.as_str(),
@ -146,13 +143,37 @@ pub(crate) fn provide(providers: &mut Providers) {
assert_eq!(cnum, LOCAL_CRATE);
if tcx.sess.opts.actually_rustdoc {
// HACK: rustdoc would like to pretend that we have all the target features, so we
// have to merge all the lists into one. The result has a "random" stability
// (depending on the order in which we consider features); all places that check
// target stability are expected to check `actually_rustdoc` and do nothing when
// that is set.
rustc_target::target_features::all_rust_features()
.map(|(a, b)| (a.to_string(), b))
.collect()
// have to merge all the lists into one. To ensure an unstable target never prevents
// a stable one from working, we merge the stability info of all instances of the
// same target feature name, with the "most stable" taking precedence. And then we
// hope that this doesn't cause issues anywhere else in the compiler...
let mut result: UnordMap<String, Stability> = Default::default();
for (name, stability) in rustc_target::target_features::all_rust_features() {
use std::collections::hash_map::Entry;
match result.entry(name.to_owned()) {
Entry::Vacant(vacant_entry) => {
vacant_entry.insert(stability);
}
Entry::Occupied(mut occupied_entry) => {
// Merge the two stabilities, "more stable" taking precedence.
match (occupied_entry.get(), stability) {
(Stability::Stable, _)
| (
Stability::Unstable { .. },
Stability::Unstable { .. } | Stability::Forbidden { .. },
)
| (Stability::Forbidden { .. }, Stability::Forbidden { .. }) => {
// The stability in the entry is at least as good as the new one, just keep it.
}
_ => {
// Overwrite stabilite.
occupied_entry.insert(stability);
}
}
}
}
}
result
} else {
tcx.sess
.target