From ab73b2c35c4b87ee9ab69347c827b094fbdf3ce8 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 21 Jun 2020 17:28:36 -0700 Subject: [PATCH] Fix order-dependent feature resolution. --- src/cargo/core/resolver/dep_cache.rs | 8 ++- tests/testsuite/features.rs | 79 +++++++++++++++++++++++++++- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/cargo/core/resolver/dep_cache.rs b/src/cargo/core/resolver/dep_cache.rs index 7b26d3a5262..c23629d7157 100644 --- a/src/cargo/core/resolver/dep_cache.rs +++ b/src/cargo/core/resolver/dep_cache.rs @@ -402,15 +402,13 @@ impl Requirements<'_> { // If `package` is indeed an optional dependency then we activate the // feature named `package`, but otherwise if `package` is a required // dependency then there's no feature associated with it. - if let Some(dep) = self + if self .summary .dependencies() .iter() - .find(|p| p.name_in_toml() == package) + .any(|dep| dep.name_in_toml() == package && dep.is_optional()) { - if dep.is_optional() { - self.used.insert(package); - } + self.used.insert(package); } self.deps .entry(package) diff --git a/tests/testsuite/features.rs b/tests/testsuite/features.rs index 3980b9bf85b..a427408688a 100644 --- a/tests/testsuite/features.rs +++ b/tests/testsuite/features.rs @@ -1,7 +1,7 @@ //! Tests for `[features]` table. use cargo_test_support::paths::CargoPathExt; -use cargo_test_support::registry::Package; +use cargo_test_support::registry::{Dependency, Package}; use cargo_test_support::{basic_manifest, project}; #[cargo_test] @@ -2113,3 +2113,80 @@ fn slash_optional_enables() { p.cargo("check --features dep/feat").run(); } + +#[cargo_test] +fn registry_summary_order_doesnt_matter() { + // Checks for an issue where the resolver depended on the order of entries + // in the registry summary. If there was a non-optional dev-dependency + // that appeared before an optional normal dependency, then the resolver + // would not activate the optional dependency with a pkg/featname feature + // syntax. + Package::new("dep", "0.1.0") + .feature("feat1", &[]) + .file( + "src/lib.rs", + r#" + #[cfg(feature="feat1")] + pub fn work() { + println!("it works"); + } + "#, + ) + .publish(); + Package::new("bar", "0.1.0") + .feature("bar_feat", &["dep/feat1"]) + .add_dep(Dependency::new("dep", "0.1.0").dev()) + .add_dep(Dependency::new("dep", "0.1.0").optional(true)) + .file( + "src/lib.rs", + r#" + // This will fail to compile without `dep` optional dep activated. + extern crate dep; + + pub fn doit() { + dep::work(); + } + "#, + ) + .publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + edition = "2018" + + [dependencies] + bar = { version="0.1", features = ["bar_feat"] } + "#, + ) + .file( + "src/main.rs", + r#" + fn main() { + bar::doit(); + } + "#, + ) + .build(); + + p.cargo("run") + .with_stderr( + "\ +[UPDATING] [..] +[DOWNLOADING] crates ... +[DOWNLOADED] [..] +[DOWNLOADED] [..] +[COMPILING] dep v0.1.0 +[COMPILING] bar v0.1.0 +[COMPILING] foo v0.1.0 [..] +[FINISHED] [..] +[RUNNING] `target/debug/foo[EXE]` +", + ) + .with_stdout("it works") + .run(); +}