Skip to content

Commit 58fd7b4

Browse files
committed
rustdoc: 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.
1 parent 5337252 commit 58fd7b4

File tree

3 files changed

+79
-1
lines changed

3 files changed

+79
-1
lines changed

src/librustdoc/json/mod.rs

+49
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,54 @@ impl<'tcx> JsonRenderer<'tcx> {
121121
Ok(())
122122
})
123123
}
124+
125+
pub(crate) fn target(&self) -> types::Target {
126+
let sess = self.tcx.sess;
127+
128+
let globally_enabled_features: FxHashMap<&str, ()> =
129+
sess.target_features.iter().map(|sym| (sym.as_str(), ())).collect();
130+
131+
// Build a map of feature stability, ignoring forbidden features which
132+
// cannot be specified by #[target_feature]
133+
use rustc_target::target_features::Stability;
134+
let feature_stability: FxHashMap<_, Option<&str>> = sess
135+
.target
136+
.rust_target_features()
137+
.into_iter()
138+
.filter_map(|(name, stability, _)| match stability {
139+
Stability::Stable => Some((name, None)),
140+
Stability::Unstable(language_feature) => {
141+
Some((name, Some(language_feature.as_str())))
142+
}
143+
Stability::Forbidden { .. } => None,
144+
})
145+
.collect();
146+
147+
types::Target {
148+
target_features: sess
149+
.target
150+
.rust_target_features()
151+
.into_iter()
152+
.copied()
153+
.filter_map(|(name, _, implied)| {
154+
// Look up this feature's stability, skipping if it's forbidden
155+
let unstable = *feature_stability.get(&name)?;
156+
157+
Some(types::TargetFeature {
158+
name: name.into(),
159+
unstable: unstable.map(String::from),
160+
implies_features: implied
161+
.into_iter()
162+
.copied()
163+
.filter(|f| feature_stability.contains_key(f))
164+
.map(String::from)
165+
.collect(),
166+
globally_enabled: globally_enabled_features.contains_key(name),
167+
})
168+
})
169+
.collect(),
170+
}
171+
}
124172
}
125173

126174
impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
@@ -288,6 +336,7 @@ impl<'tcx> FormatRenderer<'tcx> for JsonRenderer<'tcx> {
288336
)
289337
})
290338
.collect(),
339+
target: self.target(),
291340
format_version: types::FORMAT_VERSION,
292341
};
293342
if let Some(ref out_dir) = self.out_dir {

src/rustdoc-json-types/lib.rs

+26-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ pub type FxHashMap<K, V> = HashMap<K, V>; // re-export for use in src/librustdoc
3030
/// This integer is incremented with every breaking change to the API,
3131
/// and is returned along with the JSON blob as [`Crate::format_version`].
3232
/// Consuming code should assert that this value matches the format version(s) that it supports.
33-
pub const FORMAT_VERSION: u32 = 43;
33+
pub const FORMAT_VERSION: u32 = 44;
3434

3535
/// The root of the emitted JSON blob.
3636
///
@@ -52,11 +52,36 @@ pub struct Crate {
5252
pub paths: HashMap<Id, ItemSummary>,
5353
/// Maps `crate_id` of items to a crate name and html_root_url if it exists.
5454
pub external_crates: HashMap<u32, ExternalCrate>,
55+
/// Information about the target for which this documentation was generated
56+
pub target: Target,
5557
/// A single version number to be used in the future when making backwards incompatible changes
5658
/// to the JSON output.
5759
pub format_version: u32,
5860
}
5961

62+
/// Information about a target
63+
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
64+
pub struct Target {
65+
/// A list of `#[target_feature]` which exist for this target, along with their status in this
66+
/// compiler session
67+
pub target_features: Vec<TargetFeature>,
68+
}
69+
70+
/// Information about a `#[target_feature]`
71+
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
72+
pub struct TargetFeature {
73+
/// The name of this target feature
74+
pub name: String,
75+
/// Other target features which are implied by this target feature
76+
pub implies_features: Vec<String>,
77+
/// If this target feature is unstable, the name of the associated language feature gate
78+
pub unstable: Option<String>,
79+
/// Whether this feature is globally enabled for this target, for example, due to the
80+
/// target's ABI requiring this feature, or due to compiler flags like `-C target_feature` or
81+
/// `-C target-cpu`
82+
pub globally_enabled: bool,
83+
}
84+
6085
/// Metadata of a crate, either the same crate on which `rustdoc` was invoked, or its dependency.
6186
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
6287
pub struct ExternalCrate {

src/tools/jsondoclint/src/validator/tests.rs

+4
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ fn errors_on_missing_links() {
4242
)]),
4343
paths: FxHashMap::default(),
4444
external_crates: FxHashMap::default(),
45+
target: rustdoc_json_types::Target { target_features: vec![] },
4546
format_version: rustdoc_json_types::FORMAT_VERSION,
4647
};
4748

@@ -112,6 +113,7 @@ fn errors_on_local_in_paths_and_not_index() {
112113
},
113114
)]),
114115
external_crates: FxHashMap::default(),
116+
target: rustdoc_json_types::Target { target_features: vec![] },
115117
format_version: rustdoc_json_types::FORMAT_VERSION,
116118
};
117119

@@ -216,6 +218,7 @@ fn errors_on_missing_path() {
216218
ItemSummary { crate_id: 0, path: vec!["foo".to_owned()], kind: ItemKind::Module },
217219
)]),
218220
external_crates: FxHashMap::default(),
221+
target: rustdoc_json_types::Target { target_features: vec![] },
219222
format_version: rustdoc_json_types::FORMAT_VERSION,
220223
};
221224

@@ -259,6 +262,7 @@ fn checks_local_crate_id_is_correct() {
259262
)]),
260263
paths: FxHashMap::default(),
261264
external_crates: FxHashMap::default(),
265+
target: rustdoc_json_types::Target { target_features: vec![] },
262266
format_version: FORMAT_VERSION,
263267
};
264268
check(&krate, &[]);

0 commit comments

Comments
 (0)