diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 2bd58680eef..08b97b4953e 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -804,6 +804,39 @@ fn print_crate_info( println_info!("{cfg}"); } } + CheckCfg => { + let mut check_cfgs: Vec = Vec::with_capacity(410); + + // INSTABILITY: We are sorting the output below. + #[allow(rustc::potential_query_instability)] + for (name, expected_values) in &sess.psess.check_config.expecteds { + use crate::config::ExpectedValues; + match expected_values { + ExpectedValues::Any => check_cfgs.push(format!("{name}=any()")), + ExpectedValues::Some(values) => { + check_cfgs.extend(values.iter().map(|value| { + if let Some(value) = value { + format!("{name}=\"{value}\"") + } else { + name.to_string() + } + })) + } + } + } + + check_cfgs.sort_unstable(); + if !sess.psess.check_config.exhaustive_names { + if !sess.psess.check_config.exhaustive_values { + println_info!("any()=any()"); + } else { + println_info!("any()"); + } + } + for check_cfg in check_cfgs { + println_info!("{check_cfg}"); + } + } CallingConventions => { let mut calling_conventions = rustc_target::spec::abi::all_names(); calling_conventions.sort_unstable(); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index c90da966e70..0287085ad60 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -773,6 +773,7 @@ pub enum PrintKind { TargetLibdir, CrateName, Cfg, + CheckCfg, CallingConventions, TargetList, TargetCPUs, @@ -1443,7 +1444,7 @@ pub fn rustc_short_optgroups() -> Vec { "", "print", "Compiler information to print on stdout", - "[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\ + "[crate-name|file-names|sysroot|target-libdir|cfg|check-cfg|calling-conventions|\ target-list|target-cpus|target-features|relocation-models|code-models|\ tls-models|target-spec-json|all-target-specs-json|native-static-libs|\ stack-protector-strategies|link-args|deployment-target]", @@ -1859,6 +1860,7 @@ fn collect_print_requests( ("all-target-specs-json", PrintKind::AllTargetSpecs), ("calling-conventions", PrintKind::CallingConventions), ("cfg", PrintKind::Cfg), + ("check-cfg", PrintKind::CheckCfg), ("code-models", PrintKind::CodeModels), ("crate-name", PrintKind::CrateName), ("deployment-target", PrintKind::DeploymentTarget), @@ -1908,6 +1910,16 @@ fn collect_print_requests( ); } } + Some((_, PrintKind::CheckCfg)) => { + if unstable_opts.unstable_options { + PrintKind::CheckCfg + } else { + early_dcx.early_fatal( + "the `-Z unstable-options` flag must also be passed to \ + enable the check-cfg print option", + ); + } + } Some(&(_, print_kind)) => print_kind, None => { let prints = diff --git a/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md new file mode 100644 index 00000000000..e55165b5374 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/print-check-cfg.md @@ -0,0 +1,25 @@ +# `print=check-cfg` + +The tracking issue for this feature is: [#XXXXXX](https://github.com/rust-lang/rust/issues/XXXXXX). + +------------------------ + +This option of the `--print` flag print the list of expected cfgs. + +This is related to the `--check-cfg` flag which allows specifying arbitrary expected +names and values. + +This print option works similarly to `--print=cfg` (modulo check-cfg specifics): + - *check_cfg syntax*: *output of --print=check-cfg* + - `cfg(windows)`: `windows` + - `cfg(feature, values("foo", "bar"))`: `feature="foo"` and `feature="bar"` + - `cfg(feature, values(none(), ""))`: `feature` and `feature=""` + - `cfg(feature, values(any()))`: `feature=any()` + - `cfg(any())`: `any()` + - *nothing*: `any()=any()` + +To be used like this: + +```bash +rustc --print=check-cfg -Zunstable-options lib.rs +``` diff --git a/tests/run-make/print-check-cfg/lib.rs b/tests/run-make/print-check-cfg/lib.rs new file mode 100644 index 00000000000..c09e4c98dff --- /dev/null +++ b/tests/run-make/print-check-cfg/lib.rs @@ -0,0 +1 @@ +// empty crate diff --git a/tests/run-make/print-check-cfg/rmake.rs b/tests/run-make/print-check-cfg/rmake.rs new file mode 100644 index 00000000000..554884b7d57 --- /dev/null +++ b/tests/run-make/print-check-cfg/rmake.rs @@ -0,0 +1,106 @@ +//! This checks the output of `--print=check-cfg` + +extern crate run_make_support; + +use std::collections::HashSet; +use std::iter::FromIterator; +use std::ops::Deref; + +use run_make_support::rustc; + +fn main() { + check( + /*args*/ &[], + /*has_any*/ false, + /*has_any_any*/ true, + /*contains*/ &[], + ); + check( + /*args*/ &["--check-cfg=cfg()"], + /*has_any*/ false, + /*has_any_any*/ false, + /*contains*/ &["unix", "miri"], + ); + check( + /*args*/ &["--check-cfg=cfg(any())"], + /*has_any*/ true, + /*has_any_any*/ false, + /*contains*/ &["windows", "test"], + ); + check( + /*args*/ &["--check-cfg=cfg(feature)"], + /*has_any*/ false, + /*has_any_any*/ false, + /*contains*/ &["unix", "miri", "feature"], + ); + check( + /*args*/ &[r#"--check-cfg=cfg(feature, values(none(), "", "test", "lol"))"#], + /*has_any*/ false, + /*has_any_any*/ false, + /*contains*/ &["feature", "feature=\"\"", "feature=\"test\"", "feature=\"lol\""], + ); + check( + /*args*/ &[ + r#"--check-cfg=cfg(feature, values(any()))"#, + r#"--check-cfg=cfg(feature, values("tmp"))"# + ], + /*has_any*/ false, + /*has_any_any*/ false, + /*contains*/ &["unix", "miri", "feature=any()"], + ); + check( + /*args*/ &[ + r#"--check-cfg=cfg(has_foo, has_bar)"#, + r#"--check-cfg=cfg(feature, values("tmp"))"#, + r#"--check-cfg=cfg(feature, values("tmp"))"# + ], + /*has_any*/ false, + /*has_any_any*/ false, + /*contains*/ &["has_foo", "has_bar", "feature=\"tmp\""], + ); +} + +fn check(args: &[&str], has_any: bool, has_any_any: bool, contains: &[&str]) { + let output = rustc() + .input("lib.rs") + .arg("-Zunstable-options") + .arg("--print=check-cfg") + .args(&*args) + .run(); + + let stdout = String::from_utf8(output.stdout).unwrap(); + + let mut found_any = false; + let mut found_any_any = false; + let mut found = HashSet::::new(); + let mut recorded = HashSet::::new(); + + for l in stdout.lines() { + assert!(l == l.trim()); + if l == "any()" { + found_any = true; + } else if l == "any()=any()" { + found_any_any = true; + } else if let Some((left, right)) = l.split_once('=') { + if right != "any()" && right != "" { + assert!(right.starts_with("\"")); + assert!(right.ends_with("\"")); + } + assert!(!left.contains("\"")); + } else { + assert!(!l.contains("\"")); + } + assert!(recorded.insert(l.to_string()), "{}", &l); + if contains.contains(&l) { + assert!(found.insert(l.to_string()), "{}", &l); + } + } + + let should_found = HashSet::::from_iter(contains.iter().map(|s| s.to_string())); + let diff: Vec<_> = should_found.difference(&found).collect(); + + assert_eq!(found_any, has_any); + assert_eq!(found_any_any, has_any_any); + assert_eq!(found_any_any, recorded.len() == 1); + assert!(diff.is_empty(), "{:?} != {:?} (~ {:?})", &should_found, &found, &diff); +} diff --git a/tests/ui/feature-gates/feature-gate-print-check-cfg.rs b/tests/ui/feature-gates/feature-gate-print-check-cfg.rs new file mode 100644 index 00000000000..304e0c132e5 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-print-check-cfg.rs @@ -0,0 +1,3 @@ +//@ compile-flags: --print=check-cfg + +fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr b/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr new file mode 100644 index 00000000000..62ee44b94a4 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-print-check-cfg.stderr @@ -0,0 +1,2 @@ +error: the `-Z unstable-options` flag must also be passed to enable the check-cfg print option + diff --git a/tests/ui/invalid-compile-flags/print.stderr b/tests/ui/invalid-compile-flags/print.stderr index 0a032aabdfe..70b4a394dd0 100644 --- a/tests/ui/invalid-compile-flags/print.stderr +++ b/tests/ui/invalid-compile-flags/print.stderr @@ -1,4 +1,4 @@ error: unknown print request: `yyyy` | - = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models` + = help: valid print requests are: `all-target-specs-json`, `calling-conventions`, `cfg`, `check-cfg`, `code-models`, `crate-name`, `deployment-target`, `file-names`, `link-args`, `native-static-libs`, `relocation-models`, `split-debuginfo`, `stack-protector-strategies`, `sysroot`, `target-cpus`, `target-features`, `target-libdir`, `target-list`, `target-spec-json`, `tls-models`