Skip to content

Commit 039af88

Browse files
committed
also fix potential issues with mixed stable/unstable target features in rustdoc
1 parent b6f2240 commit 039af88

File tree

1 file changed

+33
-12
lines changed

1 file changed

+33
-12
lines changed

compiler/rustc_codegen_ssa/src/target_features.rs

+33-12
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use rustc_middle::query::Providers;
1010
use rustc_middle::ty::TyCtxt;
1111
use rustc_session::parse::feature_err;
1212
use rustc_span::{Span, Symbol, sym};
13-
use rustc_target::target_features;
13+
use rustc_target::target_features::{self, Stability};
1414

1515
use crate::errors;
1616

@@ -87,10 +87,7 @@ pub(crate) fn from_target_feature_attr(
8787
// But ensure the ABI does not forbid enabling this.
8888
// Here we do assume that LLVM doesn't add even more implied features
8989
// we don't know about, at least no features that would have ABI effects!
90-
// We skip this check in rustdoc, like we skip all target feature related checks.
91-
if !tcx.sess.opts.actually_rustdoc
92-
&& abi_feature_constraints.incompatible.contains(&name.as_str())
93-
{
90+
if abi_feature_constraints.incompatible.contains(&name.as_str()) {
9491
tcx.dcx().emit_err(errors::ForbiddenTargetFeatureAttr {
9592
span: item.span(),
9693
feature: name.as_str(),
@@ -146,13 +143,37 @@ pub(crate) fn provide(providers: &mut Providers) {
146143
assert_eq!(cnum, LOCAL_CRATE);
147144
if tcx.sess.opts.actually_rustdoc {
148145
// HACK: rustdoc would like to pretend that we have all the target features, so we
149-
// have to merge all the lists into one. The result has a "random" stability
150-
// (depending on the order in which we consider features); all places that check
151-
// target stability are expected to check `actually_rustdoc` and do nothing when
152-
// that is set.
153-
rustc_target::target_features::all_rust_features()
154-
.map(|(a, b)| (a.to_string(), b))
155-
.collect()
146+
// have to merge all the lists into one. To ensure an unstable target never prevents
147+
// a stable one from working, we merge the stability info of all instances of the
148+
// same target feature name, with the "most stable" taking precedence. And then we
149+
// hope that this doesn't cause issues anywhere else in the compiler...
150+
let mut result: UnordMap<String, Stability> = Default::default();
151+
for (name, stability) in rustc_target::target_features::all_rust_features() {
152+
use std::collections::hash_map::Entry;
153+
match result.entry(name.to_owned()) {
154+
Entry::Vacant(vacant_entry) => {
155+
vacant_entry.insert(stability);
156+
}
157+
Entry::Occupied(mut occupied_entry) => {
158+
// Merge the two stabilities, "more stable" taking precedence.
159+
match (occupied_entry.get(), stability) {
160+
(Stability::Stable, _)
161+
| (
162+
Stability::Unstable { .. },
163+
Stability::Unstable { .. } | Stability::Forbidden { .. },
164+
)
165+
| (Stability::Forbidden { .. }, Stability::Forbidden { .. }) => {
166+
// The stability in the entry is at least as good as the new one, just keep it.
167+
}
168+
_ => {
169+
// Overwrite stabilite.
170+
occupied_entry.insert(stability);
171+
}
172+
}
173+
}
174+
}
175+
}
176+
result
156177
} else {
157178
tcx.sess
158179
.target

0 commit comments

Comments
 (0)