Auto merge of #12845 - Urgau:check-cfg-adjust-for-rustc, r=epage

Adjust `-Zcheck-cfg` for new rustc syntax and behavior

https://github.com/rust-lang/rust/pull/111072 introduced a new syntax for `rustc` `--check-cfg` argument. This PR adjust cargo `-Zcheck-cfg` for new that new syntax and behavior.

This PR removes all the `-Zcheck-cfg` options (`features`, `names`, `values`, `output`), as they don't make much sense now since with the new `rustc` behavior: `features`, `names` and `values` are all combine together and the `output` option was only here because the other were.

Now the new behavior from cargo is to always pass one `--check-cfg` argument to rustc for the `feature`s which implicitly enables well known names and values.
This commit is contained in:
bors 2023-10-18 16:29:03 +00:00
commit 16629e6a5a
6 changed files with 91 additions and 277 deletions

View file

@ -403,10 +403,7 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
paths::create_dir_all(&script_out_dir)?;
let nightly_features_allowed = cx.bcx.config.nightly_features_allowed;
let extra_check_cfg = match cx.bcx.config.cli_unstable().check_cfg {
Some((_, _, _, output)) => output,
None => false,
};
let extra_check_cfg = cx.bcx.config.cli_unstable().check_cfg;
let targets: Vec<Target> = unit.pkg.targets().to_vec();
// Need a separate copy for the fresh closure.
let targets_fresh = targets.clone();
@ -1126,10 +1123,7 @@ fn prev_build_output(cx: &mut Context<'_, '_>, unit: &Unit) -> (Option<BuildOutp
&unit.pkg.to_string(),
&prev_script_out_dir,
&script_out_dir,
match cx.bcx.config.cli_unstable().check_cfg {
Some((_, _, _, output)) => output,
None => false,
},
cx.bcx.config.cli_unstable().check_cfg,
cx.bcx.config.nightly_features_allowed,
unit.pkg.targets(),
)

View file

@ -1167,39 +1167,32 @@ fn features_args(unit: &Unit) -> Vec<OsString> {
///
/// [`check-cfg`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg
fn check_cfg_args(cx: &Context<'_, '_>, unit: &Unit) -> Vec<OsString> {
if let Some((features, well_known_names, well_known_values, _output)) =
cx.bcx.config.cli_unstable().check_cfg
{
let mut args = Vec::with_capacity(unit.pkg.summary().features().len() * 2 + 4);
args.push(OsString::from("-Zunstable-options"));
if cx.bcx.config.cli_unstable().check_cfg {
// This generate something like this:
// - cfg(feature, values())
// - cfg(feature, values("foo", "bar"))
//
// NOTE: Despite only explicitly specifying `feature`, well known names and values
// are implicitly enabled when one or more `--check-cfg` argument is passed.
if features {
// This generate something like this:
// - values(feature)
// - values(feature, "foo", "bar")
let mut arg = OsString::from("values(feature");
for (&feat, _) in unit.pkg.summary().features() {
arg.push(", \"");
arg.push(&feat);
arg.push("\"");
let gross_cap_estimation = unit.pkg.summary().features().len() * 7 + 25;
let mut arg_feature = OsString::with_capacity(gross_cap_estimation);
arg_feature.push("cfg(feature, values(");
for (i, feature) in unit.pkg.summary().features().keys().enumerate() {
if i != 0 {
arg_feature.push(", ");
}
arg.push(")");
args.push(OsString::from("--check-cfg"));
args.push(arg);
arg_feature.push("\"");
arg_feature.push(feature);
arg_feature.push("\"");
}
arg_feature.push("))");
if well_known_names {
args.push(OsString::from("--check-cfg"));
args.push(OsString::from("names()"));
}
if well_known_values {
args.push(OsString::from("--check-cfg"));
args.push(OsString::from("values()"));
}
args
vec![
OsString::from("-Zunstable-options"),
OsString::from("--check-cfg"),
arg_feature,
]
} else {
Vec::new()
}

View file

@ -731,8 +731,7 @@ unstable_cli_options!(
#[serde(deserialize_with = "deserialize_build_std")]
build_std: Option<Vec<String>> = ("Enable Cargo to compile the standard library itself as part of a crate graph compilation"),
build_std_features: Option<Vec<String>> = ("Configure features enabled for the standard library itself when building the standard library"),
#[serde(deserialize_with = "deserialize_check_cfg")]
check_cfg: Option<(/*features:*/ bool, /*well_known_names:*/ bool, /*well_known_values:*/ bool, /*output:*/ bool)> = ("Specify scope of compile-time checking of `cfg` names/values"),
check_cfg: bool = ("Enable compile-time checking of `cfg` names/values/features"),
codegen_backend: bool = ("Enable the `codegen-backend` option in profiles in .cargo/config.toml file"),
config_include: bool = ("Enable the `include` key in config files"),
direct_minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum (direct dependencies only)"),
@ -842,20 +841,6 @@ where
))
}
fn deserialize_check_cfg<'de, D>(
deserializer: D,
) -> Result<Option<(bool, bool, bool, bool)>, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde::de::Error;
let Some(crates) = <Option<Vec<String>>>::deserialize(deserializer)? else {
return Ok(None);
};
parse_check_cfg(crates.into_iter()).map_err(D::Error::custom)
}
#[derive(Debug, Copy, Clone, Default, Deserialize)]
pub struct GitoxideFeatures {
/// All fetches are done with `gitoxide`, which includes git dependencies as well as the crates index.
@ -924,32 +909,6 @@ fn parse_gitoxide(
Ok(Some(out))
}
fn parse_check_cfg(
it: impl Iterator<Item = impl AsRef<str>>,
) -> CargoResult<Option<(bool, bool, bool, bool)>> {
let mut features = false;
let mut well_known_names = false;
let mut well_known_values = false;
let mut output = false;
for e in it {
match e.as_ref() {
"features" => features = true,
"names" => well_known_names = true,
"values" => well_known_values = true,
"output" => output = true,
_ => bail!("unstable check-cfg only takes `features`, `names`, `values` or `output` as valid inputs"),
}
}
Ok(Some((
features,
well_known_names,
well_known_values,
output,
)))
}
impl CliUnstable {
pub fn parse(
&mut self,
@ -1107,7 +1066,7 @@ impl CliUnstable {
}
"build-std-features" => self.build_std_features = Some(parse_features(v)),
"check-cfg" => {
self.check_cfg = v.map_or(Ok(None), |v| parse_check_cfg(v.split(',')))?
self.check_cfg = parse_empty(k, v)?;
}
"codegen-backend" => self.codegen_backend = parse_empty(k, v)?,
"config-include" => self.config_include = parse_empty(k, v)?,

View file

@ -137,10 +137,6 @@ fn parse_links_overrides(
config: &Config,
) -> CargoResult<BTreeMap<String, BuildOutput>> {
let mut links_overrides = BTreeMap::new();
let extra_check_cfg = match config.cli_unstable().check_cfg {
Some((_, _, _, output)) => output,
None => false,
};
for (lib_name, value) in links {
// Skip these keys, it shares the namespace with `TargetConfig`.
@ -207,7 +203,7 @@ fn parse_links_overrides(
output.cfgs.extend(list.iter().map(|v| v.0.clone()));
}
"rustc-check-cfg" => {
if extra_check_cfg {
if config.cli_unstable().check_cfg {
let list = value.list(key)?;
output.check_cfgs.extend(list.iter().map(|v| v.0.clone()));
} else {

View file

@ -1080,34 +1080,14 @@ you are ok with dev-deps being build for `cargo doc`.
* RFC: [#3013](https://github.com/rust-lang/rfcs/pull/3013)
* Tracking Issue: [#10554](https://github.com/rust-lang/cargo/issues/10554)
`-Z check-cfg` command line enables compile time checking of name and values in `#[cfg]`, `cfg!`,
`#[link]` and `#[cfg_attr]` with the `rustc` and `rustdoc` unstable `--check-cfg` command line.
`-Z check-cfg` command line enables compile time checking of Cargo features as well as `rustc`
well known names and values in `#[cfg]`, `cfg!`, `#[link]` and `#[cfg_attr]` with the `rustc`
and `rustdoc` unstable `--check-cfg` command line.
It's values are:
- `features`: enables features checking via `--check-cfg=values(feature, ...)`.
Note than this command line options will probably become the default when stabilizing.
- `names`: enables well known names checking via `--check-cfg=names()`.
- `values`: enables well known values checking via `--check-cfg=values()`.
- `output`: enable the use of `rustc-check-cfg` in build script.
For instance:
You can use the flag like this:
```
cargo check -Z unstable-options -Z check-cfg=features
cargo check -Z unstable-options -Z check-cfg=names
cargo check -Z unstable-options -Z check-cfg=values
cargo check -Z unstable-options -Z check-cfg=features,names,values
```
Or for `output`:
```rust,no_run
// build.rs
println!("cargo:rustc-check-cfg=names(foo, bar)");
```
```
cargo check -Z unstable-options -Z check-cfg=output
cargo check -Z unstable-options -Z check-cfg
```
### `cargo:rustc-check-cfg=CHECK_CFG`
@ -1116,12 +1096,23 @@ The `rustc-check-cfg` instruction tells Cargo to pass the given value to the
`--check-cfg` flag to the compiler. This may be used for compile-time
detection of unexpected conditional compilation name and/or values.
This can only be used in combination with `-Zcheck-cfg=output` otherwise it is ignored
This can only be used in combination with `-Zcheck-cfg` otherwise it is ignored
with a warning.
If you want to integrate with Cargo features, use `-Zcheck-cfg=features` instead of
If you want to integrate with Cargo features, only use `-Zcheck-cfg` instead of
trying to do it manually with this option.
You can use the instruction like this:
```rust,no_run
// build.rs
println!("cargo:rustc-check-cfg=cfg(foo, bar)");
```
```
cargo check -Z unstable-options -Z check-cfg
```
## codegen-backend
The `codegen-backend` feature makes it possible to select the codegen backend used by rustc using a profile.

View file

@ -15,16 +15,16 @@ macro_rules! x {
$what, '(', $($who,)* ')', "'", "[..]")
}
}};
($tool:tt => $what:tt of $who:tt with $($values:tt)*) => {{
($tool:tt => $what:tt of $who:tt with $($first_value:tt $($other_values:tt)*)?) => {{
#[cfg(windows)]
{
concat!("[RUNNING] [..]", $tool, "[..] --check-cfg \"",
$what, '(', $who, $(", ", "/\"", $values, "/\"",)* ")", '"', "[..]")
$what, '(', $who, ", values(", $("/\"", $first_value, "/\"", $(", ", "/\"", $other_values, "/\"",)*)* "))", '"', "[..]")
}
#[cfg(not(windows))]
{
concat!("[RUNNING] [..]", $tool, "[..] --check-cfg '",
$what, '(', $who, $(", ", "\"", $values, "\"",)* ")", "'", "[..]")
$what, '(', $who, ", values(", $("\"", $first_value, "\"", $(", ", "\"", $other_values, "\"",)*)* "))", "'", "[..]")
}
}};
}
@ -47,9 +47,9 @@ fn features() {
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v -Zcheck-cfg=features")
p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.run();
}
@ -76,10 +76,9 @@ fn features_with_deps() {
.file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}")
.build();
p.cargo("check -v -Zcheck-cfg=features")
p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "values" of "feature"))
.with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.run();
}
@ -107,10 +106,9 @@ fn features_with_opt_deps() {
.file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}")
.build();
p.cargo("check -v -Zcheck-cfg=features")
p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "values" of "feature"))
.with_stderr_contains(x!("rustc" => "values" of "feature" with "bar" "default" "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "bar" "default" "f_a" "f_b"))
.run();
}
@ -137,111 +135,22 @@ fn features_with_namespaced_features() {
.file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}")
.build();
p.cargo("check -v -Zcheck-cfg=features")
p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn well_known_names() {
fn well_known_names_values() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v -Zcheck-cfg=names")
p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "names"))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn well_known_values() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v -Zcheck-cfg=values")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "values"))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn cli_all_options() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[features]
f_a = []
f_b = []
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v -Zcheck-cfg=features,names,values")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "names"))
.with_stderr_contains(x!("rustc" => "values"))
.with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn features_with_cargo_check() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[features]
f_a = []
f_b = []
"#,
)
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v -Zcheck-cfg=features")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn well_known_names_with_check() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v -Zcheck-cfg=names")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "names"))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn well_known_values_with_check() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("check -v -Zcheck-cfg=values")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "values"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with))
.run();
}
@ -263,9 +172,9 @@ fn features_test() {
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("test -v -Zcheck-cfg=features")
p.cargo("test -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.run();
}
@ -288,64 +197,37 @@ fn features_doctest() {
.file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
.build();
p.cargo("test -v --doc -Zcheck-cfg=features")
p.cargo("test -v --doc -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "values" of "feature" with "default" "f_a" "f_b"))
.with_stderr_contains(x!("rustdoc" => "values" of "feature" with "default" "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "default" "f_a" "f_b"))
.with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with "default" "f_a" "f_b"))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn well_known_names_test() {
fn well_known_names_values_test() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("test -v -Zcheck-cfg=names")
p.cargo("test -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "names"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn well_known_values_test() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/main.rs", "fn main() {}")
.build();
p.cargo("test -v -Zcheck-cfg=values")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "values"))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn well_known_names_doctest() {
fn well_known_names_values_doctest() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
.build();
p.cargo("test -v --doc -Zcheck-cfg=names")
p.cargo("test -v --doc -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "names"))
.with_stderr_contains(x!("rustdoc" => "names"))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn well_known_values_doctest() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
.build();
p.cargo("test -v --doc -Zcheck-cfg=values")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "values"))
.with_stderr_contains(x!("rustdoc" => "values"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with))
.with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with))
.run();
}
@ -368,9 +250,9 @@ fn features_doc() {
.file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
.build();
p.cargo("doc -v -Zcheck-cfg=features")
p.cargo("doc -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustdoc" => "values" of "feature" with "default" "f_a" "f_b"))
.with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with "default" "f_a" "f_b"))
.run();
}
@ -390,13 +272,13 @@ fn build_script_feedback() {
.file("src/main.rs", "fn main() {}")
.file(
"build.rs",
r#"fn main() { println!("cargo:rustc-check-cfg=names(foo)"); }"#,
r#"fn main() { println!("cargo:rustc-check-cfg=cfg(foo)"); }"#,
)
.build();
p.cargo("check -v -Zcheck-cfg=output")
p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "names" of "foo"))
.with_stderr_contains(x!("rustc" => "cfg" of "foo"))
.run();
}
@ -416,12 +298,13 @@ fn build_script_doc() {
.file("src/main.rs", "fn main() {}")
.file(
"build.rs",
r#"fn main() { println!("cargo:rustc-check-cfg=names(foo)"); }"#,
r#"fn main() { println!("cargo:rustc-check-cfg=cfg(foo)"); }"#,
)
.build();
p.cargo("doc -v -Zcheck-cfg=output")
p.cargo("doc -v -Zcheck-cfg")
.with_stderr_does_not_contain("rustc [..] --check-cfg [..]")
.with_stderr_contains(x!("rustdoc" => "names" of "foo"))
.with_stderr_contains(x!("rustdoc" => "cfg" of "foo"))
.with_stderr(
"\
[COMPILING] foo v0.0.1 ([CWD])
@ -458,15 +341,15 @@ fn build_script_override() {
&format!(
r#"
[target.{}.a]
rustc-check-cfg = ["names(foo)"]
rustc-check-cfg = ["cfg(foo)"]
"#,
target
),
)
.build();
p.cargo("check -v -Zcheck-cfg=output")
.with_stderr_contains(x!("rustc" => "names" of "foo"))
p.cargo("check -v -Zcheck-cfg")
.with_stderr_contains(x!("rustc" => "cfg" of "foo"))
.masquerade_as_nightly_cargo(&["check-cfg"])
.run();
}
@ -487,7 +370,7 @@ fn build_script_test() {
.file(
"build.rs",
r#"fn main() {
println!("cargo:rustc-check-cfg=names(foo)");
println!("cargo:rustc-check-cfg=cfg(foo)");
println!("cargo:rustc-cfg=foo");
}"#,
)
@ -516,9 +399,9 @@ fn build_script_test() {
.file("tests/test.rs", "#[cfg(foo)] #[test] fn test_bar() {}")
.build();
p.cargo("test -v -Zcheck-cfg=output")
.with_stderr_contains(x!("rustc" => "names" of "foo"))
.with_stderr_contains(x!("rustdoc" => "names" of "foo"))
p.cargo("test -v -Zcheck-cfg")
.with_stderr_contains(x!("rustc" => "cfg" of "foo"))
.with_stderr_contains(x!("rustdoc" => "cfg" of "foo"))
.with_stdout_contains("test test_foo ... ok")
.with_stdout_contains("test test_bar ... ok")
.with_stdout_contains_n("test [..] ... ok", 3)
@ -546,16 +429,14 @@ fn config_valid() {
".cargo/config.toml",
r#"
[unstable]
check-cfg = ["features", "names", "values"]
check-cfg = true
"#,
)
.build();
p.cargo("check -v -Zcheck-cfg=features,names,values")
p.cargo("check -v")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains(x!("rustc" => "names"))
.with_stderr_contains(x!("rustc" => "values"))
.with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
.with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.run();
}
@ -582,7 +463,7 @@ fn config_invalid() {
p.cargo("check")
.masquerade_as_nightly_cargo(&["check-cfg"])
.with_stderr_contains("error: unstable check-cfg only takes `features`, `names`, `values` or `output` as valid inputs")
.with_stderr_contains("error:[..]`unstable.check-cfg` expected true/false[..]")
.with_status(101)
.run();
}