Skip to content

Commit

Permalink
add flag to dump unstable feature status information
Browse files Browse the repository at this point in the history
  • Loading branch information
yaahc committed Nov 22, 2024
1 parent a475551 commit 7a06cbf
Show file tree
Hide file tree
Showing 10 changed files with 210 additions and 3 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3596,6 +3596,7 @@ dependencies = [
"rustc_target",
"rustc_trait_selection",
"rustc_ty_utils",
"serde",
"serde_json",
"shlex",
"time",
Expand Down Expand Up @@ -4012,6 +4013,7 @@ dependencies = [
"rustc_span",
"rustc_target",
"rustc_type_ir",
"serde",
"tempfile",
"tracing",
]
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_driver_impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }
serde = { version = "1.0.125", features = [ "derive" ] }
serde_json = "1.0.59"
shlex = "1.0"
time = { version = "0.3.36", default-features = false, features = ["alloc", "formatting", "macros"] }
Expand Down
34 changes: 32 additions & 2 deletions compiler/rustc_driver_impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,11 @@

use std::cmp::max;
use std::collections::BTreeMap;
use std::error::Error;
use std::ffi::OsString;
use std::fmt::Write as _;
use std::fs::{self, File};
use std::io::{self, IsTerminal, Read, Write};
use std::io::{self, BufWriter, IsTerminal, Read, Write, stdout};
use std::panic::{self, PanicHookInfo, catch_unwind};
use std::path::PathBuf;
use std::process::{self, Command, Stdio};
Expand All @@ -45,7 +46,7 @@ use rustc_errors::registry::Registry;
use rustc_errors::{
ColorConfig, DiagCtxt, ErrCode, ErrorGuaranteed, FatalError, PResult, markdown,
};
use rustc_feature::find_gated_cfg;
use rustc_feature::{LangFeaturesStatus, find_gated_cfg};
use rustc_interface::util::{self, get_codegen_backend};
use rustc_interface::{Linker, Queries, interface, passes};
use rustc_lint::unerased_lint_store;
Expand Down Expand Up @@ -377,6 +378,11 @@ fn run_compiler(
return early_exit();
}

if sess.opts.unstable_opts.dump_features_status {
dump_features_status(sess, codegen_backend);
return early_exit();
}

if !has_input {
#[allow(rustc::diagnostic_outside_of_impl)]
sess.dcx().fatal("no input filename given"); // this is fatal
Expand Down Expand Up @@ -1571,6 +1577,30 @@ fn report_ice(
}
}

fn dump_features_status(sess: &Session, codegen_backend: &dyn CodegenBackend) {
#[derive(serde::Serialize)]
struct FeaturesStatus {
lang_features_status: LangFeaturesStatus,
lib_features_status: locator::LibFeaturesStatus,
}

let result: Result<(), Box<dyn Error>> = try {
let lang_features_status = rustc_feature::lang_features_status();
let lib_features_status =
rustc_metadata::lib_features_status(sess, &*codegen_backend.metadata_loader())?;
let value = FeaturesStatus { lang_features_status, lib_features_status };
let writer = stdout();
let writer = BufWriter::new(writer);
serde_json::to_writer_pretty(writer, &value)?;
};

// this happens before the global context and more importantly the diagnostic context is setup,
// so we can't report with the proper machinery
if let Err(error) = result {
panic!("cannot emit feature status json: {error}")
}
}

/// This allows tools to enable rust logging without having to magically match rustc's
/// tracing crate version.
pub fn init_rustc_env_logger(early_dcx: &EarlyDiagCtxt) {
Expand Down
56 changes: 56 additions & 0 deletions compiler/rustc_feature/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,62 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
}
}

#[derive(serde::Serialize)]
enum LangFeature {
Unstable {
status: &'static str,
symbol: String,
since: &'static str,
issue: Option<NonZero<u32>>,
},
Accepted {
symbol: String,
since: &'static str,
issue: Option<NonZero<u32>>,
},
Removed {
symbol: String,
since: &'static str,
issue: Option<NonZero<u32>>,
reason: Option<&'static str>,
},
}

#[derive(serde::Serialize)]
pub struct LangFeaturesStatus {
lang_features: Vec<LangFeature>,
}

/// Extract the status of all lang features as a json serializable struct
pub fn lang_features_status() -> LangFeaturesStatus {
let unstable_lang_features =
UNSTABLE_LANG_FEATURES.iter().map(|feature| LangFeature::Unstable {
status: Features::feature_status(feature.name),
symbol: feature.name.to_string(),
since: feature.since,
issue: feature.issue,
});

let accepted_lang_features =
ACCEPTED_LANG_FEATURES.iter().map(|feature| LangFeature::Accepted {
symbol: feature.name.to_string(),
since: feature.since,
issue: feature.issue,
});

let removed_lang_features = REMOVED_LANG_FEATURES.iter().map(|removed| LangFeature::Removed {
symbol: removed.feature.name.to_string(),
since: removed.feature.since,
issue: removed.feature.issue,
reason: removed.reason,
});

let lang_features =
unstable_lang_features.chain(accepted_lang_features).chain(removed_lang_features).collect();

LangFeaturesStatus { lang_features }
}

pub use accepted::ACCEPTED_LANG_FEATURES;
pub use builtin_attrs::{
AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate, AttributeType,
Expand Down
23 changes: 22 additions & 1 deletion compiler/rustc_feature/src/unstable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ impl Features {
}
}

macro_rules! status_to_str {
(unstable) => {
"default"
};
(incomplete) => {
"incomplete"
};
(internal) => {
"internal"
};
}

macro_rules! declare_features {
($(
$(#[doc = $doc:tt])* ($status:ident, $feature:ident, $ver:expr, $issue:expr),
Expand Down Expand Up @@ -159,6 +171,15 @@ macro_rules! declare_features {
_ => panic!("`{}` was not listed in `declare_features`", feature),
}
}

pub fn feature_status(feature: Symbol) -> &'static str {
match feature {
$(
sym::$feature => status_to_str!($status),
)*
_ => panic!("`{}` was not listed in `declare_features`", feature),
}
}
}
};
}
Expand Down Expand Up @@ -650,7 +671,7 @@ declare_features! (

// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
// -------------------------------------------------------------------------
);

impl Features {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_metadata/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_type_ir = { path = "../rustc_type_ir" }
serde = { version = "1.0.125", features = [ "derive" ] }
tempfile = "3.2"
tracing = "0.1"
# tidy-alphabetical-end
2 changes: 2 additions & 0 deletions compiler/rustc_metadata/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#![feature(coroutines)]
#![feature(decl_macro)]
#![feature(error_iter)]
#![feature(error_reporter)]
#![feature(extract_if)]
#![feature(file_buffered)]
#![feature(if_let_guard)]
Expand Down Expand Up @@ -35,6 +36,7 @@ pub mod locator;

pub use creader::{DylibError, load_symbol_from_dylib};
pub use fs::{METADATA_FILENAME, emit_wrapper_file};
pub use locator::lib_features_status;
pub use native_libs::{
find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library,
walk_native_lib_search_dirs,
Expand Down
84 changes: 84 additions & 0 deletions compiler/rustc_metadata/src/locator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,7 @@
//! metadata::locator or metadata::creader for all the juicy details!
use std::borrow::Cow;
use std::error::Error;
use std::io::{Result as IoResult, Write};
use std::ops::Deref;
use std::path::{Path, PathBuf};
Expand All @@ -224,6 +225,7 @@ use rustc_data_structures::owned_slice::slice_owned;
use rustc_data_structures::svh::Svh;
use rustc_errors::{DiagArgValue, IntoDiagArg};
use rustc_fs_util::try_canonicalize;
use rustc_middle::middle::lib_features::FeatureStability;
use rustc_session::Session;
use rustc_session::cstore::CrateSource;
use rustc_session::filesearch::FileSearch;
Expand Down Expand Up @@ -864,6 +866,88 @@ fn get_metadata_section<'p>(
}
}

#[derive(serde::Serialize)]
enum LibFeature {
Core { name: String, status: Status },
Std { name: String, status: Status },
}

#[derive(serde::Serialize)]
enum Status {
AcceptedSince(String),
Unstable,
}

#[derive(serde::Serialize)]
pub struct LibFeaturesStatus {
lib_features: Vec<LibFeature>,
}

pub fn lib_features_status(
sess: &Session,
metadata_loader: &dyn MetadataLoader,
) -> Result<LibFeaturesStatus, Box<dyn Error>> {
let is_rlib = true;
let hash = None;
let extra_filename = None;
let path_kind = PathKind::Crate;
let extra_prefix = "";

let mut core_locator = CrateLocator::new(
sess,
metadata_loader,
rustc_span::sym::core,
is_rlib,
hash,
extra_filename,
path_kind,
);
let Ok(Some(core)) = core_locator.find_library_crate(extra_prefix, &mut FxHashSet::default())
else {
Err("unable to locate core library")?
};
let mut std_locator = CrateLocator::new(
sess,
metadata_loader,
rustc_span::sym::std,
is_rlib,
hash,
extra_filename,
path_kind,
);
let Ok(Some(std)) = std_locator.find_library_crate(extra_prefix, &mut FxHashSet::default())
else {
Err("unable to locate standard library")?
};

let core_features =
core.metadata.dump_crate_features_json().into_iter().map(|(name, status)| {
LibFeature::Core {
name,
status: match status {
FeatureStability::AcceptedSince(symbol) => {
Status::AcceptedSince(symbol.to_string())
}
FeatureStability::Unstable => Status::Unstable,
},
}
});
let std_features =
std.metadata.dump_crate_features_json().into_iter().map(|(name, status)| LibFeature::Std {
name,
status: match status {
FeatureStability::AcceptedSince(symbol) => {
Status::AcceptedSince(symbol.to_string())
}
FeatureStability::Unstable => Status::Unstable,
},
});

let lib_features = core_features.chain(std_features).collect();

Ok(LibFeaturesStatus { lib_features })
}

/// A diagnostic function for dumping crate metadata to an output stream.
pub fn list_file_metadata(
target: &Target,
Expand Down
8 changes: 8 additions & 0 deletions compiler/rustc_metadata/src/rmeta/decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -935,6 +935,14 @@ impl MetadataBlob {

Ok(())
}

pub(crate) fn dump_crate_features_json(&self) -> Vec<(String, FeatureStability)> {
let root = self.get_root();
root.lib_features
.decode(self)
.map(|(symbol, status)| (symbol.to_string(), status))
.collect()
}
}

impl CrateRoot {
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_session/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1730,6 +1730,8 @@ options! {
dump_dep_graph: bool = (false, parse_bool, [UNTRACKED],
"dump the dependency graph to $RUST_DEP_GRAPH (default: /tmp/dep_graph.gv) \
(default: no)"),
dump_features_status: bool = (false, parse_bool, [UNTRACKED],
"dump the status of rust language and library features as json"),
dump_mir: Option<String> = (None, parse_opt_string, [UNTRACKED],
"dump MIR state to file.
`val` is used to select which passes and functions to dump. For example:
Expand Down

0 comments on commit 7a06cbf

Please sign in to comment.