Make --print=check-cfg output compatible --check-cfg arguments

This commit is contained in:
Urgau 2026-01-08 22:06:45 +01:00
parent 32fe406b5e
commit feb44c3f48
3 changed files with 72 additions and 56 deletions

View file

@ -765,30 +765,35 @@ fn print_crate_info(
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::Any => {
check_cfgs.push(format!("cfg({name}, values(any()))"))
}
ExpectedValues::Some(values) => {
if !values.is_empty() {
check_cfgs.extend(values.iter().map(|value| {
let mut values: Vec<_> = values
.iter()
.map(|value| {
if let Some(value) = value {
format!("{name}=\"{value}\"")
format!("\"{value}\"")
} else {
name.to_string()
"none()".to_string()
}
}))
} else {
check_cfgs.push(format!("{name}="))
}
})
.collect();
values.sort_unstable();
let values = values.join(", ");
check_cfgs.push(format!("cfg({name}, values({values}))"))
}
}
}
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()");
}
if !sess.psess.check_config.exhaustive_names
&& sess.psess.check_config.exhaustive_values
{
println_info!("cfg(any())");
}
for check_cfg in check_cfgs {
println_info!("{check_cfg}");

View file

@ -9,18 +9,20 @@ This option of the `--print` flag print the list of all the expected cfgs.
This is related to the [`--check-cfg` flag][check-cfg] which allows specifying arbitrary expected
names and values.
This print option works similarly to `--print=cfg` (modulo check-cfg specifics).
This print option outputs compatible `--check-cfg` arguments with a reduced syntax where all the
expected values are on the same line and `values(...)` is always explicit.
| `--check-cfg` | `--print=check-cfg` |
|-----------------------------------|-----------------------------|
| `cfg(foo)` | `foo` |
| `cfg(foo, values("bar"))` | `foo="bar"` |
| `cfg(foo, values(none(), "bar"))` | `foo` & `foo="bar"` |
| | *check-cfg specific syntax* |
| `cfg(foo, values(any())` | `foo=any()` |
| `cfg(foo, values())` | `foo=` |
| `cfg(any())` | `any()` |
| *none* | `any()=any()` |
| `--check-cfg` | `--print=check-cfg` |
|-----------------------------------|-----------------------------------|
| `cfg(foo)` | `cfg(foo, values(none())) |
| `cfg(foo, values("bar"))` | `cfg(foo, values("bar"))` |
| `cfg(foo, values(none(), "bar"))` | `cfg(foo, values(none(), "bar"))` |
| `cfg(foo, values(any())` | `cfg(foo, values(any())` |
| `cfg(foo, values())` | `cfg(foo, values())` |
| `cfg(any())` | `cfg(any())` |
| *nothing* | *nothing* |
The print option includes well known cfgs.
To be used like this:
@ -28,4 +30,7 @@ To be used like this:
rustc --print=check-cfg -Zunstable-options lib.rs
```
> **Note:** Users should be resilient when parsing, in particular against new predicates that
may be added in the future.
[check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html

View file

@ -14,51 +14,55 @@ struct CheckCfg {
enum Contains {
Some { contains: &'static [&'static str], doesnt_contain: &'static [&'static str] },
Only(&'static str),
Nothing,
}
fn main() {
check(CheckCfg { args: &[], contains: Contains::Only("any()=any()") });
check(CheckCfg { args: &[], contains: Contains::Nothing });
check(CheckCfg {
args: &["--check-cfg=cfg()"],
contains: Contains::Some {
contains: &["unix", "miri"],
doesnt_contain: &["any()", "any()=any()"],
contains: &["cfg(unix, values(none()))", "cfg(miri, values(none()))"],
doesnt_contain: &["cfg(any())"],
},
});
check(CheckCfg {
args: &["--check-cfg=cfg(any())"],
contains: Contains::Some {
contains: &["any()", "unix", r#"target_feature="crt-static""#],
contains: &["cfg(any())", "cfg(unix, values(none()))"],
doesnt_contain: &["any()=any()"],
},
});
check(CheckCfg {
args: &["--check-cfg=cfg(feature)"],
contains: Contains::Some {
contains: &["unix", "miri", "feature"],
doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="],
contains: &[
"cfg(unix, values(none()))",
"cfg(miri, values(none()))",
"cfg(feature, values(none()))",
],
doesnt_contain: &["cfg(any())", "cfg(feature)"],
},
});
check(CheckCfg {
args: &[r#"--check-cfg=cfg(feature, values(none(), "", "test", "lol"))"#],
contains: Contains::Some {
contains: &["feature", "feature=\"\"", "feature=\"test\"", "feature=\"lol\""],
doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="],
contains: &[r#"cfg(feature, values("", "lol", "test", none()))"#],
doesnt_contain: &["cfg(any())", "cfg(feature, values(none()))", "cfg(feature)"],
},
});
check(CheckCfg {
args: &["--check-cfg=cfg(feature, values())"],
contains: Contains::Some {
contains: &["feature="],
doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature"],
contains: &["cfg(feature, values())"],
doesnt_contain: &["cfg(any())", "cfg(feature, values(none()))", "cfg(feature)"],
},
});
check(CheckCfg {
args: &["--check-cfg=cfg(feature, values())", "--check-cfg=cfg(feature, values(none()))"],
contains: Contains::Some {
contains: &["feature"],
doesnt_contain: &["any()", "any()=any()", "feature=none()", "feature="],
contains: &["cfg(feature, values(none()))"],
doesnt_contain: &["cfg(any())", "cfg(feature, values())"],
},
});
check(CheckCfg {
@ -67,8 +71,8 @@ fn main() {
r#"--check-cfg=cfg(feature, values("tmp"))"#,
],
contains: Contains::Some {
contains: &["unix", "miri", "feature=any()"],
doesnt_contain: &["any()", "any()=any()", "feature", "feature=", "feature=\"tmp\""],
contains: &["cfg(feature, values(any()))"],
doesnt_contain: &["cfg(any())", r#"cfg(feature, values("tmp"))"#],
},
});
check(CheckCfg {
@ -78,8 +82,12 @@ fn main() {
r#"--check-cfg=cfg(feature, values("tmp"))"#,
],
contains: Contains::Some {
contains: &["has_foo", "has_bar", "feature=\"tmp\""],
doesnt_contain: &["any()", "any()=any()", "feature"],
contains: &[
"cfg(has_foo, values(none()))",
"cfg(has_bar, values(none()))",
r#"cfg(feature, values("tmp"))"#,
],
doesnt_contain: &["cfg(any())", "cfg(feature)"],
},
});
}
@ -94,16 +102,15 @@ fn check(CheckCfg { args, contains }: CheckCfg) {
for l in stdout.lines() {
assert!(l == l.trim());
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!(found.insert(l.to_string()), "{}", &l);
assert!(l.starts_with("cfg("), "{l}");
assert!(l.ends_with(")"), "{l}");
assert_eq!(
l.chars().filter(|c| *c == '(').count(),
l.chars().filter(|c| *c == ')').count(),
"{l}"
);
assert!(l.chars().filter(|c| *c == '"').count() % 2 == 0, "{l}");
assert!(found.insert(l.to_string()), "{l}");
}
match contains {
@ -131,9 +138,8 @@ fn check(CheckCfg { args, contains }: CheckCfg) {
);
}
}
Contains::Only(only) => {
assert!(found.contains(&only.to_string()), "{:?} != {:?}", &only, &found);
assert!(found.len() == 1, "len: {}, instead of 1", found.len());
Contains::Nothing => {
assert!(found.len() == 0, "len: {}, instead of 0", found.len());
}
}
}