From c08a666a24b5e95474d9e61f6cfaef76f7ff529e Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 29 Jun 2022 14:16:36 +0200 Subject: [PATCH 1/2] Fix config deserilization of check-cfg --- src/cargo/core/features.rs | 74 +++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 779bca4ce02..2a9b32e8ca3 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -641,6 +641,7 @@ unstable_cli_options!( build_std_features: Option> = ("Configure features enabled for the standard library itself when building the standard library"), config_include: bool = ("Enable the `include` key in config files"), credential_process: bool = ("Add a config setting to fetch registry authentication tokens by calling an external process"), + #[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"), doctest_in_workspace: bool = ("Compile doctests with paths relative to the workspace root"), doctest_xcompile: bool = ("Compile and run doctests for non-host target using runner config"), @@ -733,6 +734,47 @@ where )) } +fn deserialize_check_cfg<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + use serde::de::Error; + let crates = match >>::deserialize(deserializer)? { + Some(list) => list, + None => return Ok(None), + }; + + parse_check_cfg(crates.into_iter()).map_err(D::Error::custom) +} + +fn parse_check_cfg( + it: impl Iterator>, +) -> CargoResult> { + 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, @@ -783,34 +825,6 @@ impl CliUnstable { } } - fn parse_check_cfg(value: Option<&str>) -> CargoResult> { - if let Some(value) = value { - let mut features = false; - let mut well_known_names = false; - let mut well_known_values = false; - let mut output = false; - - for e in value.split(',') { - match e { - "features" => features = true, - "names" => well_known_names = true, - "values" => well_known_values = true, - "output" => output = true, - _ => bail!("flag -Zcheck-cfg only takes `features`, `names`, `values` or `output` as valid inputs"), - } - } - - Ok(Some(( - features, - well_known_names, - well_known_values, - output, - ))) - } else { - Ok(None) - } - } - // Asserts that there is no argument to the flag. fn parse_empty(key: &str, value: Option<&str>) -> CargoResult { if let Some(v) = value { @@ -868,7 +882,9 @@ impl CliUnstable { "minimal-versions" => self.minimal_versions = parse_empty(k, v)?, "advanced-env" => self.advanced_env = parse_empty(k, v)?, "config-include" => self.config_include = parse_empty(k, v)?, - "check-cfg" => self.check_cfg = parse_check_cfg(v)?, + "check-cfg" => { + self.check_cfg = v.map_or(Ok(None), |v| parse_check_cfg(v.split(',')))? + } "dual-proc-macros" => self.dual_proc_macros = parse_empty(k, v)?, // can also be set in .cargo/config or with and ENV "mtime-on-use" => self.mtime_on_use = parse_empty(k, v)?, From 23f59d4eeb85de6766b3dd7b3d0ee4d19a448c13 Mon Sep 17 00:00:00 2001 From: Urgau Date: Wed, 29 Jun 2022 14:51:40 +0200 Subject: [PATCH 2/2] Add regression tests for check-cfg unstable config --- tests/testsuite/check_cfg.rs | 71 ++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/testsuite/check_cfg.rs b/tests/testsuite/check_cfg.rs index ab7d4f9a2e0..330a0ae9715 100644 --- a/tests/testsuite/check_cfg.rs +++ b/tests/testsuite/check_cfg.rs @@ -629,3 +629,74 @@ fn build_script_test() { .masquerade_as_nightly_cargo() .run(); } + +#[cargo_test] +fn config_valid() { + if !is_nightly() { + // --check-cfg is a nightly only rustc command line + return; + } + + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.1.0" + + [features] + f_a = [] + f_b = [] + "#, + ) + .file("src/main.rs", "fn main() {}") + .file( + ".cargo/config.toml", + r#" + [unstable] + check-cfg = ["features", "names", "values"] + "#, + ) + .build(); + + p.cargo("build -v -Zcheck-cfg=features,names,values") + .masquerade_as_nightly_cargo() + .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] +fn config_invalid() { + if !is_nightly() { + // --check-cfg is a nightly only rustc command line + return; + } + + let p = project() + .file( + "Cargo.toml", + r#" + [project] + name = "foo" + version = "0.1.0" + "#, + ) + .file("src/main.rs", "fn main() {}") + .file( + ".cargo/config.toml", + r#" + [unstable] + check-cfg = ["va"] + "#, + ) + .build(); + + p.cargo("build") + .masquerade_as_nightly_cargo() + .with_stderr_contains("error: unstable check-cfg only takes `features`, `names`, `values` or `output` as valid inputs") + .with_status(101) + .run(); +}