about summary refs log tree commit diff
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2025-02-25 20:38:13 +0100
committerJosh Stone <jistone@redhat.com>2025-03-14 14:12:37 -0700
commitc13521b739511d4a0cb7d6941e93eadd9e59aaf9 (patch)
treef0e77950e91bd400c37ab842cc1d88e47462304a
parentd4de520fc458f67758ad7d7fb024e065f840f61e (diff)
downloadrust-c13521b739511d4a0cb7d6941e93eadd9e59aaf9.tar.gz
rust-c13521b739511d4a0cb7d6941e93eadd9e59aaf9.zip
also fix potential issues with mixed stable/unstable target features in rustdoc
(cherry picked from commit 039af88e09f4f4beb47406f4771bffc2e61d800a)
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs40
1 files changed, 32 insertions, 8 deletions
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index d673cd6e6b4..bffcdca299b 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -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;
 
@@ -150,13 +150,37 @@ pub(crate) fn provide(providers: &mut Providers) {
             let target = &tcx.sess.target;
             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.compute_toggleability(target)))
-                    .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.compute_toggleability(target));
+                        }
+                        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.compute_toggleability(target));
+                                }
+                            }
+                        }
+                    }
+                }
+                result
             } else {
                 tcx.sess
                     .target