Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
}