Rollup merge of #139393 - willglynn:rustdoc_output_target_feature_information, r=aDotInTheVoid
rustdoc-json: Output target feature information `#[target_feature]` attributes refer to a target-specific list of features. Enabling certain features can imply enabling other features. Certain features are always enabled on certain targets, since they are required by the target's ABI. Features can also be enabled indirectly based on other compiler flags. Feature information is ultimately known to `rustc`. Rather than force external tools to track it – which may be wildly impractical due to `-C target-cpu` – have `rustdoc` output `rustc`'s feature data. This change is motivated by https://github.com/obi1kenobi/cargo-semver-checks/issues/1246, which intends to detect semver hazards caused by `#[target_feature]`. try-job: aarch64-gnu try-job: armhf-gnu try-job: test-various try-job: x86_64-msvc-1 try-job: i686-msvc-1 try-job: x86_64-mingw-1 try-job: aarch64-apple
This commit is contained in:
commit
e15cf92b67
15 changed files with 257 additions and 2 deletions
|
|
@ -14,6 +14,7 @@ use std::io::{BufWriter, Write, stdout};
|
|||
use std::path::PathBuf;
|
||||
use std::rc::Rc;
|
||||
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir::def_id::{DefId, DefIdSet};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_session::Session;
|
||||
|
|
@ -123,6 +124,58 @@ impl<'tcx> JsonRenderer<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn target(sess: &rustc_session::Session) -> types::Target {
|
||||
// Build a set of which features are enabled on this target
|
||||
let globally_enabled_features: FxHashSet<&str> =
|
||||
sess.unstable_target_features.iter().map(|name| name.as_str()).collect();
|
||||
|
||||
// Build a map of target feature stability by feature name
|
||||
use rustc_target::target_features::Stability;
|
||||
let feature_stability: FxHashMap<&str, Stability> = sess
|
||||
.target
|
||||
.rust_target_features()
|
||||
.into_iter()
|
||||
.copied()
|
||||
.map(|(name, stability, _)| (name, stability))
|
||||
.collect();
|
||||
|
||||
types::Target {
|
||||
triple: sess.opts.target_triple.tuple().into(),
|
||||
target_features: sess
|
||||
.target
|
||||
.rust_target_features()
|
||||
.into_iter()
|
||||
.copied()
|
||||
.filter(|(_, stability, _)| {
|
||||
// Describe only target features which the user can toggle
|
||||
stability.toggle_allowed().is_ok()
|
||||
})
|
||||
.map(|(name, stability, implied_features)| {
|
||||
types::TargetFeature {
|
||||
name: name.into(),
|
||||
unstable_feature_gate: match stability {
|
||||
Stability::Unstable(feature_gate) => Some(feature_gate.as_str().into()),
|
||||
_ => None,
|
||||
},
|
||||
implies_features: implied_features
|
||||
.into_iter()
|
||||
.copied()
|
||||
.filter(|name| {
|
||||
// Imply only target features which the user can toggle
|
||||
feature_stability
|
||||
.get(name)
|
||||
.map(|stability| stability.toggle_allowed().is_ok())
|
||||
.unwrap_or(false)
|
||||
})
|
||||
.map(String::from)
|
||||
.collect(),
|
||||
globally_enabled: globally_enabled_features.contains(name),
|
||||
}
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
||||
fn descr() -> &'static str {
|
||||
"json"
|
||||
|
|
@ -248,6 +301,12 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
|||
let e = ExternalCrate { crate_num: LOCAL_CRATE };
|
||||
let index = (*self.index).clone().into_inner();
|
||||
|
||||
// Note that tcx.rust_target_features is inappropriate here because rustdoc tries to run for
|
||||
// multiple targets: https://github.com/rust-lang/rust/pull/137632
|
||||
//
|
||||
// We want to describe a single target, so pass tcx.sess rather than tcx.
|
||||
let target = target(self.tcx.sess);
|
||||
|
||||
debug!("Constructing Output");
|
||||
let output_crate = types::Crate {
|
||||
root: self.id_from_item_default(e.def_id().into()),
|
||||
|
|
@ -288,6 +347,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
|
|||
)
|
||||
})
|
||||
.collect(),
|
||||
target,
|
||||
format_version: types::FORMAT_VERSION,
|
||||
};
|
||||
if let Some(ref out_dir) = self.out_dir {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue