Skip to content

Commit 4231106

Browse files
committed
Auto merge of #10799 - Urgau:check-cfg-fix-config-deserialization, r=ehuss
Fix deserialization of check-cfg in config.toml When improving the check-cfg implementation in #10566 I changed the internal representation of `check_cfg` from multiple `bool` options to one `Option<(bool, bool, bool, bool)>` but I didn't realize until rust-lang/rust#82450 (comment) that the internal representation is actually somewhat public as it's used in the `[unstable]` in `.cargo/config.toml`. And because TOML cannot represent tuples there is no way to set it from the `[unstable]` section. This PR fix this oversight by using a custom deserializer method similar to what was already done for `build-std`.
2 parents a3ae668 + 23f59d4 commit 4231106

File tree

2 files changed

+116
-29
lines changed

2 files changed

+116
-29
lines changed

src/cargo/core/features.rs

Lines changed: 45 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -641,6 +641,7 @@ unstable_cli_options!(
641641
build_std_features: Option<Vec<String>> = ("Configure features enabled for the standard library itself when building the standard library"),
642642
config_include: bool = ("Enable the `include` key in config files"),
643643
credential_process: bool = ("Add a config setting to fetch registry authentication tokens by calling an external process"),
644+
#[serde(deserialize_with = "deserialize_check_cfg")]
644645
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"),
645646
doctest_in_workspace: bool = ("Compile doctests with paths relative to the workspace root"),
646647
doctest_xcompile: bool = ("Compile and run doctests for non-host target using runner config"),
@@ -733,6 +734,47 @@ where
733734
))
734735
}
735736

737+
fn deserialize_check_cfg<'de, D>(
738+
deserializer: D,
739+
) -> Result<Option<(bool, bool, bool, bool)>, D::Error>
740+
where
741+
D: serde::Deserializer<'de>,
742+
{
743+
use serde::de::Error;
744+
let crates = match <Option<Vec<String>>>::deserialize(deserializer)? {
745+
Some(list) => list,
746+
None => return Ok(None),
747+
};
748+
749+
parse_check_cfg(crates.into_iter()).map_err(D::Error::custom)
750+
}
751+
752+
fn parse_check_cfg(
753+
it: impl Iterator<Item = impl AsRef<str>>,
754+
) -> CargoResult<Option<(bool, bool, bool, bool)>> {
755+
let mut features = false;
756+
let mut well_known_names = false;
757+
let mut well_known_values = false;
758+
let mut output = false;
759+
760+
for e in it {
761+
match e.as_ref() {
762+
"features" => features = true,
763+
"names" => well_known_names = true,
764+
"values" => well_known_values = true,
765+
"output" => output = true,
766+
_ => bail!("unstable check-cfg only takes `features`, `names`, `values` or `output` as valid inputs"),
767+
}
768+
}
769+
770+
Ok(Some((
771+
features,
772+
well_known_names,
773+
well_known_values,
774+
output,
775+
)))
776+
}
777+
736778
impl CliUnstable {
737779
pub fn parse(
738780
&mut self,
@@ -783,34 +825,6 @@ impl CliUnstable {
783825
}
784826
}
785827

786-
fn parse_check_cfg(value: Option<&str>) -> CargoResult<Option<(bool, bool, bool, bool)>> {
787-
if let Some(value) = value {
788-
let mut features = false;
789-
let mut well_known_names = false;
790-
let mut well_known_values = false;
791-
let mut output = false;
792-
793-
for e in value.split(',') {
794-
match e {
795-
"features" => features = true,
796-
"names" => well_known_names = true,
797-
"values" => well_known_values = true,
798-
"output" => output = true,
799-
_ => bail!("flag -Zcheck-cfg only takes `features`, `names`, `values` or `output` as valid inputs"),
800-
}
801-
}
802-
803-
Ok(Some((
804-
features,
805-
well_known_names,
806-
well_known_values,
807-
output,
808-
)))
809-
} else {
810-
Ok(None)
811-
}
812-
}
813-
814828
// Asserts that there is no argument to the flag.
815829
fn parse_empty(key: &str, value: Option<&str>) -> CargoResult<bool> {
816830
if let Some(v) = value {
@@ -868,7 +882,9 @@ impl CliUnstable {
868882
"minimal-versions" => self.minimal_versions = parse_empty(k, v)?,
869883
"advanced-env" => self.advanced_env = parse_empty(k, v)?,
870884
"config-include" => self.config_include = parse_empty(k, v)?,
871-
"check-cfg" => self.check_cfg = parse_check_cfg(v)?,
885+
"check-cfg" => {
886+
self.check_cfg = v.map_or(Ok(None), |v| parse_check_cfg(v.split(',')))?
887+
}
872888
"dual-proc-macros" => self.dual_proc_macros = parse_empty(k, v)?,
873889
// can also be set in .cargo/config or with and ENV
874890
"mtime-on-use" => self.mtime_on_use = parse_empty(k, v)?,

tests/testsuite/check_cfg.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -629,3 +629,74 @@ fn build_script_test() {
629629
.masquerade_as_nightly_cargo()
630630
.run();
631631
}
632+
633+
#[cargo_test]
634+
fn config_valid() {
635+
if !is_nightly() {
636+
// --check-cfg is a nightly only rustc command line
637+
return;
638+
}
639+
640+
let p = project()
641+
.file(
642+
"Cargo.toml",
643+
r#"
644+
[project]
645+
name = "foo"
646+
version = "0.1.0"
647+
648+
[features]
649+
f_a = []
650+
f_b = []
651+
"#,
652+
)
653+
.file("src/main.rs", "fn main() {}")
654+
.file(
655+
".cargo/config.toml",
656+
r#"
657+
[unstable]
658+
check-cfg = ["features", "names", "values"]
659+
"#,
660+
)
661+
.build();
662+
663+
p.cargo("build -v -Zcheck-cfg=features,names,values")
664+
.masquerade_as_nightly_cargo()
665+
.with_stderr_contains(x!("rustc" => "names"))
666+
.with_stderr_contains(x!("rustc" => "values"))
667+
.with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
668+
.run();
669+
}
670+
671+
#[cargo_test]
672+
fn config_invalid() {
673+
if !is_nightly() {
674+
// --check-cfg is a nightly only rustc command line
675+
return;
676+
}
677+
678+
let p = project()
679+
.file(
680+
"Cargo.toml",
681+
r#"
682+
[project]
683+
name = "foo"
684+
version = "0.1.0"
685+
"#,
686+
)
687+
.file("src/main.rs", "fn main() {}")
688+
.file(
689+
".cargo/config.toml",
690+
r#"
691+
[unstable]
692+
check-cfg = ["va"]
693+
"#,
694+
)
695+
.build();
696+
697+
p.cargo("build")
698+
.masquerade_as_nightly_cargo()
699+
.with_stderr_contains("error: unstable check-cfg only takes `features`, `names`, `values` or `output` as valid inputs")
700+
.with_status(101)
701+
.run();
702+
}

0 commit comments

Comments
 (0)