Skip to content

Commit 7a06cbf

Browse files
committed
add flag to dump unstable feature status information
1 parent a475551 commit 7a06cbf

File tree

10 files changed

+210
-3
lines changed

10 files changed

+210
-3
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3596,6 +3596,7 @@ dependencies = [
35963596
"rustc_target",
35973597
"rustc_trait_selection",
35983598
"rustc_ty_utils",
3599+
"serde",
35993600
"serde_json",
36003601
"shlex",
36013602
"time",
@@ -4012,6 +4013,7 @@ dependencies = [
40124013
"rustc_span",
40134014
"rustc_target",
40144015
"rustc_type_ir",
4016+
"serde",
40154017
"tempfile",
40164018
"tracing",
40174019
]

compiler/rustc_driver_impl/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ rustc_span = { path = "../rustc_span" }
4747
rustc_target = { path = "../rustc_target" }
4848
rustc_trait_selection = { path = "../rustc_trait_selection" }
4949
rustc_ty_utils = { path = "../rustc_ty_utils" }
50+
serde = { version = "1.0.125", features = [ "derive" ] }
5051
serde_json = "1.0.59"
5152
shlex = "1.0"
5253
time = { version = "0.3.36", default-features = false, features = ["alloc", "formatting", "macros"] }

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121

2222
use std::cmp::max;
2323
use std::collections::BTreeMap;
24+
use std::error::Error;
2425
use std::ffi::OsString;
2526
use std::fmt::Write as _;
2627
use std::fs::{self, File};
27-
use std::io::{self, IsTerminal, Read, Write};
28+
use std::io::{self, BufWriter, IsTerminal, Read, Write, stdout};
2829
use std::panic::{self, PanicHookInfo, catch_unwind};
2930
use std::path::PathBuf;
3031
use std::process::{self, Command, Stdio};
@@ -45,7 +46,7 @@ use rustc_errors::registry::Registry;
4546
use rustc_errors::{
4647
ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, FatalError, PResult, markdown,
4748
};
48-
use rustc_feature::find_gated_cfg;
49+
use rustc_feature::{LangFeaturesStatus, find_gated_cfg};
4950
use rustc_interface::util::{self, get_codegen_backend};
5051
use rustc_interface::{Linker, Queries, interface, passes};
5152
use rustc_lint::unerased_lint_store;
@@ -377,6 +378,11 @@ fn run_compiler(
377378
return early_exit();
378379
}
379380

381+
if sess.opts.unstable_opts.dump_features_status {
382+
dump_features_status(sess, codegen_backend);
383+
return early_exit();
384+
}
385+
380386
if !has_input {
381387
#[allow(rustc::diagnostic_outside_of_impl)]
382388
sess.dcx().fatal("no input filename given"); // this is fatal
@@ -1571,6 +1577,30 @@ fn report_ice(
15711577
}
15721578
}
15731579

1580+
fn dump_features_status(sess: &Session, codegen_backend: &dyn CodegenBackend) {
1581+
#[derive(serde::Serialize)]
1582+
struct FeaturesStatus {
1583+
lang_features_status: LangFeaturesStatus,
1584+
lib_features_status: locator::LibFeaturesStatus,
1585+
}
1586+
1587+
let result: Result<(), Box<dyn Error>> = try {
1588+
let lang_features_status = rustc_feature::lang_features_status();
1589+
let lib_features_status =
1590+
rustc_metadata::lib_features_status(sess, &*codegen_backend.metadata_loader())?;
1591+
let value = FeaturesStatus { lang_features_status, lib_features_status };
1592+
let writer = stdout();
1593+
let writer = BufWriter::new(writer);
1594+
serde_json::to_writer_pretty(writer, &value)?;
1595+
};
1596+
1597+
// this happens before the global context and more importantly the diagnostic context is setup,
1598+
// so we can't report with the proper machinery
1599+
if let Err(error) = result {
1600+
panic!("cannot emit feature status json: {error}")
1601+
}
1602+
}
1603+
15741604
/// This allows tools to enable rust logging without having to magically match rustc's
15751605
/// tracing crate version.
15761606
pub fn init_rustc_env_logger(early_dcx: &EarlyDiagCtxt) {

compiler/rustc_feature/src/lib.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,62 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
132132
}
133133
}
134134

135+
#[derive(serde::Serialize)]
136+
enum LangFeature {
137+
Unstable {
138+
status: &'static str,
139+
symbol: String,
140+
since: &'static str,
141+
issue: Option<NonZero<u32>>,
142+
},
143+
Accepted {
144+
symbol: String,
145+
since: &'static str,
146+
issue: Option<NonZero<u32>>,
147+
},
148+
Removed {
149+
symbol: String,
150+
since: &'static str,
151+
issue: Option<NonZero<u32>>,
152+
reason: Option<&'static str>,
153+
},
154+
}
155+
156+
#[derive(serde::Serialize)]
157+
pub struct LangFeaturesStatus {
158+
lang_features: Vec<LangFeature>,
159+
}
160+
161+
/// Extract the status of all lang features as a json serializable struct
162+
pub fn lang_features_status() -> LangFeaturesStatus {
163+
let unstable_lang_features =
164+
UNSTABLE_LANG_FEATURES.iter().map(|feature| LangFeature::Unstable {
165+
status: Features::feature_status(feature.name),
166+
symbol: feature.name.to_string(),
167+
since: feature.since,
168+
issue: feature.issue,
169+
});
170+
171+
let accepted_lang_features =
172+
ACCEPTED_LANG_FEATURES.iter().map(|feature| LangFeature::Accepted {
173+
symbol: feature.name.to_string(),
174+
since: feature.since,
175+
issue: feature.issue,
176+
});
177+
178+
let removed_lang_features = REMOVED_LANG_FEATURES.iter().map(|removed| LangFeature::Removed {
179+
symbol: removed.feature.name.to_string(),
180+
since: removed.feature.since,
181+
issue: removed.feature.issue,
182+
reason: removed.reason,
183+
});
184+
185+
let lang_features =
186+
unstable_lang_features.chain(accepted_lang_features).chain(removed_lang_features).collect();
187+
188+
LangFeaturesStatus { lang_features }
189+
}
190+
135191
pub use accepted::ACCEPTED_LANG_FEATURES;
136192
pub use builtin_attrs::{
137193
AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,

compiler/rustc_feature/src/unstable.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,18 @@ impl Features {
9999
}
100100
}
101101

102+
macro_rules! status_to_str {
103+
(unstable) => {
104+
"default"
105+
};
106+
(incomplete) => {
107+
"incomplete"
108+
};
109+
(internal) => {
110+
"internal"
111+
};
112+
}
113+
102114
macro_rules! declare_features {
103115
($(
104116
$(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr),
@@ -159,6 +171,15 @@ macro_rules! declare_features {
159171
_ => panic!("`{}` was not listed in `declare_features`", feature),
160172
}
161173
}
174+
175+
pub fn feature_status(feature: Symbol) -> &'static str {
176+
match feature {
177+
$(
178+
sym::$feature => status_to_str!($status),
179+
)*
180+
_ => panic!("`{}` was not listed in `declare_features`", feature),
181+
}
182+
}
162183
}
163184
};
164185
}
@@ -650,7 +671,7 @@ declare_features! (
650671

651672
// -------------------------------------------------------------------------
652673
// feature-group-end: actual feature gates
653-
// -------------------------------------------------------------------------
674+
// -------------------------------------------------------------------------
654675
);
655676

656677
impl Features {

compiler/rustc_metadata/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ rustc_session = { path = "../rustc_session" }
2828
rustc_span = { path = "../rustc_span" }
2929
rustc_target = { path = "../rustc_target" }
3030
rustc_type_ir = { path = "../rustc_type_ir" }
31+
serde = { version = "1.0.125", features = [ "derive" ] }
3132
tempfile = "3.2"
3233
tracing = "0.1"
3334
# tidy-alphabetical-end

compiler/rustc_metadata/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#![feature(coroutines)]
66
#![feature(decl_macro)]
77
#![feature(error_iter)]
8+
#![feature(error_reporter)]
89
#![feature(extract_if)]
910
#![feature(file_buffered)]
1011
#![feature(if_let_guard)]
@@ -35,6 +36,7 @@ pub mod locator;
3536

3637
pub use creader::{DylibError, load_symbol_from_dylib};
3738
pub use fs::{METADATA_FILENAME, emit_wrapper_file};
39+
pub use locator::lib_features_status;
3840
pub use native_libs::{
3941
find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library,
4042
walk_native_lib_search_dirs,

compiler/rustc_metadata/src/locator.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@
213213
//! metadata::locator or metadata::creader for all the juicy details!
214214
215215
use std::borrow::Cow;
216+
use std::error::Error;
216217
use std::io::{Result as IoResult, Write};
217218
use std::ops::Deref;
218219
use std::path::{Path, PathBuf};
@@ -224,6 +225,7 @@ use rustc_data_structures::owned_slice::slice_owned;
224225
use rustc_data_structures::svh::Svh;
225226
use rustc_errors::{DiagArgValue, IntoDiagArg};
226227
use rustc_fs_util::try_canonicalize;
228+
use rustc_middle::middle::lib_features::FeatureStability;
227229
use rustc_session::Session;
228230
use rustc_session::cstore::CrateSource;
229231
use rustc_session::filesearch::FileSearch;
@@ -864,6 +866,88 @@ fn get_metadata_section<'p>(
864866
}
865867
}
866868

869+
#[derive(serde::Serialize)]
870+
enum LibFeature {
871+
Core { name: String, status: Status },
872+
Std { name: String, status: Status },
873+
}
874+
875+
#[derive(serde::Serialize)]
876+
enum Status {
877+
AcceptedSince(String),
878+
Unstable,
879+
}
880+
881+
#[derive(serde::Serialize)]
882+
pub struct LibFeaturesStatus {
883+
lib_features: Vec<LibFeature>,
884+
}
885+
886+
pub fn lib_features_status(
887+
sess: &Session,
888+
metadata_loader: &dyn MetadataLoader,
889+
) -> Result<LibFeaturesStatus, Box<dyn Error>> {
890+
let is_rlib = true;
891+
let hash = None;
892+
let extra_filename = None;
893+
let path_kind = PathKind::Crate;
894+
let extra_prefix = "";
895+
896+
let mut core_locator = CrateLocator::new(
897+
sess,
898+
metadata_loader,
899+
rustc_span::sym::core,
900+
is_rlib,
901+
hash,
902+
extra_filename,
903+
path_kind,
904+
);
905+
let Ok(Some(core)) = core_locator.find_library_crate(extra_prefix, &mut FxHashSet::default())
906+
else {
907+
Err("unable to locate core library")?
908+
};
909+
let mut std_locator = CrateLocator::new(
910+
sess,
911+
metadata_loader,
912+
rustc_span::sym::std,
913+
is_rlib,
914+
hash,
915+
extra_filename,
916+
path_kind,
917+
);
918+
let Ok(Some(std)) = std_locator.find_library_crate(extra_prefix, &mut FxHashSet::default())
919+
else {
920+
Err("unable to locate standard library")?
921+
};
922+
923+
let core_features =
924+
core.metadata.dump_crate_features_json().into_iter().map(|(name, status)| {
925+
LibFeature::Core {
926+
name,
927+
status: match status {
928+
FeatureStability::AcceptedSince(symbol) => {
929+
Status::AcceptedSince(symbol.to_string())
930+
}
931+
FeatureStability::Unstable => Status::Unstable,
932+
},
933+
}
934+
});
935+
let std_features =
936+
std.metadata.dump_crate_features_json().into_iter().map(|(name, status)| LibFeature::Std {
937+
name,
938+
status: match status {
939+
FeatureStability::AcceptedSince(symbol) => {
940+
Status::AcceptedSince(symbol.to_string())
941+
}
942+
FeatureStability::Unstable => Status::Unstable,
943+
},
944+
});
945+
946+
let lib_features = core_features.chain(std_features).collect();
947+
948+
Ok(LibFeaturesStatus { lib_features })
949+
}
950+
867951
/// A diagnostic function for dumping crate metadata to an output stream.
868952
pub fn list_file_metadata(
869953
target: &Target,

compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,14 @@ impl MetadataBlob {
935935

936936
Ok(())
937937
}
938+
939+
pub(crate) fn dump_crate_features_json(&self) -> Vec<(String, FeatureStability)> {
940+
let root = self.get_root();
941+
root.lib_features
942+
.decode(self)
943+
.map(|(symbol, status)| (symbol.to_string(), status))
944+
.collect()
945+
}
938946
}
939947

940948
impl CrateRoot {

compiler/rustc_session/src/options.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1730,6 +1730,8 @@ options! {
17301730
dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
17311731
"dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \
17321732
(default: no)"),
1733+
dump_features_status: bool = (false, parse_bool, [UNTRACKED],
1734+
"dump the status of rust language and library features as json"),
17331735
dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
17341736
"dump MIR state to file.
17351737
`val` is used to select which passes and functions to dump. For example:

0 commit comments

Comments
 (0)