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!
}
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()))
"#.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();
+}