From 6db28647d3eed0d29ffebd3308f8aeb7334fdc09 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 8 Jul 2024 16:44:24 -0500 Subject: [PATCH 1/3] refactor(toml): Make room for resolving features --- src/cargo/util/toml/mod.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index 1d2c23a92b6..c70badc45c3 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -291,7 +291,7 @@ fn resolve_toml( dev_dependencies2: None, build_dependencies: None, build_dependencies2: None, - features: original_toml.features.clone(), + features: None, target: None, replace: original_toml.replace.clone(), patch: original_toml.patch.clone(), @@ -322,6 +322,8 @@ fn resolve_toml( }); resolved_toml.package = Some(resolved_package); + resolved_toml.features = resolve_features(original_toml.features.as_ref())?; + resolved_toml.lib = targets::resolve_lib( original_toml.lib.as_ref(), package_root, @@ -686,6 +688,17 @@ fn default_readme_from_package_root(package_root: &Path) -> Option { None } +#[tracing::instrument(skip_all)] +fn resolve_features( + original_features: Option<&BTreeMap>>, +) -> CargoResult>>> { + let Some(resolved_features) = original_features.cloned() else { + return Ok(None); + }; + + Ok(Some(resolved_features)) +} + #[tracing::instrument(skip_all)] fn resolve_dependencies<'a>( gctx: &GlobalContext, From 85cc9940af8dba0200075f8bd011d464f1ebd0da Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 9 Jul 2024 13:43:33 -0500 Subject: [PATCH 2/3] test: Show bad error for dep_name/feature_name on 2024 --- tests/testsuite/features.rs | 57 +++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/tests/testsuite/features.rs b/tests/testsuite/features.rs index a7c43132b48..5e8a5550d86 100644 --- a/tests/testsuite/features.rs +++ b/tests/testsuite/features.rs @@ -1847,6 +1847,63 @@ fn features_option_given_twice() { p.cargo("check --features a --features b").run(); } +#[cargo_test(nightly, reason = "edition2024 is not stable")] +fn strong_dep_feature_edition2024() { + let p = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["edition2024"] + [package] + name = "foo" + version = "0.1.0" + edition = "2024" + + [features] + optional_dep = ["optional_dep/foo"] + + [dependencies] + optional_dep = { path = "optional_dep", optional = true } + "#, + ) + .file( + "src/main.rs", + r#" + fn main() {} + "#, + ) + .file( + "optional_dep/Cargo.toml", + r#" + [package] + name = "optional_dep" + [features] + foo = [] +"#, + ) + .file( + "optional_dep/src/lib.rs", + r#" +"#, + ) + .build(); + + p.cargo("metadata") + .masquerade_as_nightly_cargo(&["edition2024"]) + .with_status(101) + .with_stderr_data(str![[r#" +[ERROR] feature `optional_dep` includes `optional_dep/foo`, but `optional_dep` is not a dependency + --> Cargo.toml:9:32 + | +9 | optional_dep = ["optional_dep/foo"] + | ^^^^^^^^^^^^^^^^^^^^ + | +[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` + +"#]]) + .run(); +} + #[cargo_test] fn multi_multi_features() { let p = project() From 99fae9187ac0bae12a03585083169e34dc7a197d Mon Sep 17 00:00:00 2001 From: Ed Page Date: Tue, 9 Jul 2024 13:27:42 -0500 Subject: [PATCH 3/3] fix: Ensure dep/feature activates the dependency on 2024 This doesn't revert the last commit of #14018 so that it works properly on Editions 2021 and 2024. Fixes #14016 --- src/cargo/util/toml/mod.rs | 27 +++++++++++++++++++++++++-- tests/testsuite/features.rs | 32 +++++++++++++++++++++----------- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/cargo/util/toml/mod.rs b/src/cargo/util/toml/mod.rs index c70badc45c3..5bd6f79fe48 100644 --- a/src/cargo/util/toml/mod.rs +++ b/src/cargo/util/toml/mod.rs @@ -322,7 +322,7 @@ fn resolve_toml( }); resolved_toml.package = Some(resolved_package); - resolved_toml.features = resolve_features(original_toml.features.as_ref())?; + resolved_toml.features = resolve_features(original_toml.features.as_ref(), edition)?; resolved_toml.lib = targets::resolve_lib( original_toml.lib.as_ref(), @@ -691,11 +691,34 @@ fn default_readme_from_package_root(package_root: &Path) -> Option { #[tracing::instrument(skip_all)] fn resolve_features( original_features: Option<&BTreeMap>>, + edition: Edition, ) -> CargoResult>>> { - let Some(resolved_features) = original_features.cloned() else { + let Some(mut resolved_features) = original_features.cloned() else { return Ok(None); }; + if Edition::Edition2024 <= edition { + for activations in resolved_features.values_mut() { + let mut deps = Vec::new(); + for feature_value in activations.iter() { + let feature_value = FeatureValue::new(InternedString::new(feature_value)); + let FeatureValue::DepFeature { + dep_name, + dep_feature: _, + weak: false, + } = feature_value + else { + continue; + }; + let dep = FeatureValue::Dep { dep_name }.to_string(); + if !activations.contains(&dep) { + deps.push(dep); + } + } + activations.extend(deps); + } + } + Ok(Some(resolved_features)) } diff --git a/tests/testsuite/features.rs b/tests/testsuite/features.rs index 5e8a5550d86..1213c4a5574 100644 --- a/tests/testsuite/features.rs +++ b/tests/testsuite/features.rs @@ -1890,17 +1890,27 @@ fn strong_dep_feature_edition2024() { p.cargo("metadata") .masquerade_as_nightly_cargo(&["edition2024"]) - .with_status(101) - .with_stderr_data(str![[r#" -[ERROR] feature `optional_dep` includes `optional_dep/foo`, but `optional_dep` is not a dependency - --> Cargo.toml:9:32 - | -9 | optional_dep = ["optional_dep/foo"] - | ^^^^^^^^^^^^^^^^^^^^ - | -[ERROR] failed to parse manifest at `[ROOT]/foo/Cargo.toml` - -"#]]) + .with_stdout_data( + str![[r#" +{ + "metadata": null, + "packages": [ + { + "features": { + "optional_dep": [ + "optional_dep/foo", + "dep:optional_dep" + ] + }, + "name": "foo", + "...": "{...}" + } + ], + "...": "{...}" +} +"#]] + .json(), + ) .run(); }