Don't synthesize feature diretives for non-optional deps

Currently when Cargo is invoked on the command like `cargo build
--features foo/bar` then it will actually always compile the current
crate with `feature = "foo"` even if `foo` is a non-optional dependency.
This isn't intended because the crate doesn't actually have a `foo`
feature as so no directive should be emitted or passed to the compiler.

This was discovered in rust-lang/rust where Cargo is being built with
the `rustc-workspace-hack` feature but when the RLS depends on Cargo it
doesn't enable the same feature. This feature, however, doesn't actually
exist for Cargo!
This commit is contained in:
Alex Crichton 2019-06-05 09:10:10 -07:00
parent 0e38712d4d
commit dbc2c2b57d
2 changed files with 54 additions and 1 deletions

View file

@ -415,7 +415,19 @@ impl Requirements<'_> {
}
fn require_crate_feature(&mut self, package: InternedString, feat: InternedString) {
self.used.insert(package);
// 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
.summary
.dependencies()
.iter()
.find(|p| p.name_in_toml() == package)
{
if dep.is_optional() {
self.used.insert(package);
}
}
self.deps
.entry(package)
.or_insert((false, BTreeSet::new()))

View file

@ -1870,3 +1870,44 @@ fn warn_if_default_features() {
"#.trim(),
).run();
}
#[test]
fn no_feature_for_non_optional_dep() {
let p = project()
.file(
"Cargo.toml",
r#"
[project]
name = "foo"
version = "0.0.1"
authors = []
[dependencies]
bar = { path = "bar" }
"#,
)
.file(
"src/main.rs",
r#"
#[cfg(not(feature = "bar"))]
fn main() {
}
"#,
)
.file(
"bar/Cargo.toml",
r#"
[project]
name = "bar"
version = "0.0.1"
authors = []
[features]
a = []
"#,
)
.file("bar/src/lib.rs", "pub fn bar() {}")
.build();
p.cargo("build --features bar/a").run();
}