Skip to content

Commit

Permalink
Auto merge of #12130 - ehuss:dep-with-slash, r=weihanglo
Browse files Browse the repository at this point in the history
Fix dep/feat syntax with hidden implicit optional dependencies

This fixes an issue with `dep/feat` syntax in the `[features]` table where it wouldn't work if the optional dependency had its implicit feature removed via the `dep:` syntax.

The problem is that both resolvers were expecting that `dep/feat` would be able to activate a feature named "dep". But if that implicit feature wasn't created, then it would fail with an error.

This was just an oversight (which probably happened in #9574).

Fixes #10788
  • Loading branch information
bors committed May 12, 2023
2 parents 13413c6 + 996bca2 commit e41605b
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 2 deletions.
7 changes: 6 additions & 1 deletion src/cargo/core/resolver/dep_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,12 @@ impl Requirements<'_> {
.iter()
.any(|dep| dep.name_in_toml() == package && dep.is_optional())
{
self.require_feature(package)?;
// This optional dependency may not have an implicit feature of
// the same name if the `dep:` syntax is used to avoid creating
// that implicit feature.
if self.summary.features().contains_key(&package) {
self.require_feature(package)?;
}
}
self.deps.entry(package).or_default().insert(feat);
Ok(())
Expand Down
10 changes: 9 additions & 1 deletion src/cargo/core/resolver/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,15 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> {
// The old behavior before weak dependencies were
// added is to also enables a feature of the same
// name.
self.activate_rec(pkg_id, fk, dep_name)?;
//
// Don't enable if the implicit optional dependency
// feature wasn't created due to `dep:` hiding.
// See rust-lang/cargo#10788 and rust-lang/cargo#12130
let summary = self.resolve.summary(pkg_id);
let feature_map = summary.features();
if feature_map.contains_key(&dep_name) {
self.activate_rec(pkg_id, fk, dep_name)?;
}
}
}
// Activate the feature on the dependency.
Expand Down
78 changes: 78 additions & 0 deletions tests/testsuite/features_namespaced.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1216,3 +1216,81 @@ Caused by:
)
.run();
}

#[cargo_test]
fn dep_feature_when_hidden() {
// Checks for behavior with dep:bar and bar/feat syntax when there is no
// `bar` feature.
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
[dependencies]
bar = { path = "bar", optional = true }
[features]
f1 = ["dep:bar"]
f2 = ["bar/bar_feat"]
"#,
)
.file("src/lib.rs", "")
.file(
"bar/Cargo.toml",
r#"
[package]
name = "bar"
version = "0.1.0"
[features]
bar_feat = []
"#,
)
.file("bar/src/lib.rs", "")
.build();

p.cargo("tree -f")
.arg("{p} features={f}")
.with_stdout(
"\
foo v0.1.0 ([ROOT]/foo) features=",
)
.with_stderr("")
.run();

p.cargo("tree -F f1 -f")
.arg("{p} features={f}")
.with_stdout(
"\
foo v0.1.0 ([ROOT]/foo) features=f1
└── bar v0.1.0 ([ROOT]/foo/bar) features=
",
)
.with_stderr("")
.run();

p.cargo("tree -F f2 -f")
.arg("{p} features={f}")
.with_stdout(
"\
foo v0.1.0 ([ROOT]/foo) features=f2
└── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat
",
)
.with_stderr("")
.run();

p.cargo("tree --all-features -f")
.arg("{p} features={f}")
.with_stdout(
"\
foo v0.1.0 ([ROOT]/foo) features=f1,f2
└── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat
",
)
.with_stderr("")
.run();
}

0 comments on commit e41605b

Please sign in to comment.