diff --git a/src/cargo/core/resolver/features.rs b/src/cargo/core/resolver/features.rs index 9dd514339f5..7c16010ab9c 100644 --- a/src/cargo/core/resolver/features.rs +++ b/src/cargo/core/resolver/features.rs @@ -298,7 +298,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { let member_features = self.ws.members_with_features(specs, requested_features)?; for (member, requested_features) in &member_features { let fvs = self.fvs_from_requested(member.package_id(), requested_features); - let for_host = self.opts.decouple_host_deps && self.is_proc_macro(member.package_id()); + let for_host = self.is_proc_macro(member.package_id()); self.activate_pkg(member.package_id(), &fvs, for_host)?; if for_host { // Also activate without for_host. This is needed if the @@ -324,7 +324,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { // finding bugs where the resolver missed something it should have visited. // Remove this in the future if `activated_features` uses an empty default. self.activated_features - .entry((pkg_id, for_host)) + .entry((pkg_id, self.opts.decouple_host_deps && for_host)) .or_insert_with(BTreeSet::new); for fv in fvs { self.activate_fv(pkg_id, fv, for_host)?; @@ -418,7 +418,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { ) -> CargoResult<()> { let enabled = self .activated_features - .entry((pkg_id, for_host)) + .entry((pkg_id, self.opts.decouple_host_deps && for_host)) .or_insert_with(BTreeSet::new); if !enabled.insert(feature_to_enable) { // Already enabled. @@ -541,8 +541,7 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { true }) .map(|dep| { - let dep_for_host = for_host - || (self.opts.decouple_host_deps && (dep.is_build() || is_proc_macro)); + let dep_for_host = for_host || dep.is_build() || is_proc_macro; (dep, dep_for_host) }) .collect::>(); diff --git a/tests/testsuite/features2.rs b/tests/testsuite/features2.rs index beb950df88a..d85b0b13a70 100644 --- a/tests/testsuite/features2.rs +++ b/tests/testsuite/features2.rs @@ -1,8 +1,9 @@ //! Tests for the new feature resolver. +use cargo_test_support::cross_compile::{self, alternate}; use cargo_test_support::paths::CargoPathExt; use cargo_test_support::registry::{Dependency, Package}; -use cargo_test_support::{basic_manifest, project}; +use cargo_test_support::{basic_manifest, project, rustc_host}; #[cargo_test] fn inactivate_targets() { @@ -183,6 +184,49 @@ fn inactive_target_optional() { .run(); } +#[cargo_test] +fn itarget_proc_macro() { + // itarget inside a proc-macro while cross-compiling + if cross_compile::disabled() { + return; + } + Package::new("hostdep", "1.0.0").publish(); + Package::new("pm", "1.0.0") + .proc_macro(true) + .target_dep("hostdep", "1.0", &rustc_host()) + .file("src/lib.rs", "extern crate hostdep;") + .publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + pm = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check").run(); + p.cargo("check -Zfeatures=itarget") + .masquerade_as_nightly_cargo() + .run(); + p.cargo("check --target").arg(alternate()).run(); + p.cargo("check -Zfeatures=itarget --target") + .arg(alternate()) + .masquerade_as_nightly_cargo() + .run(); + // For good measure, just make sure things don't break. + p.cargo("check -Zfeatures=all --target") + .arg(alternate()) + .masquerade_as_nightly_cargo() + .run(); +} + #[cargo_test] fn decouple_host_deps() { // Basic test for `host_dep` decouple. @@ -1185,3 +1229,63 @@ fn has_dev_dep_for_test() { ) .run(); } + +#[cargo_test] +fn build_dep_activated() { + // Build dependencies always match the host for [target.*.build-dependencies]. + if cross_compile::disabled() { + return; + } + Package::new("somedep", "1.0.0") + .file("src/lib.rs", "") + .publish(); + Package::new("targetdep", "1.0.0").publish(); + Package::new("hostdep", "1.0.0") + // Check that "for_host" is sticky. + .target_dep("somedep", "1.0", &rustc_host()) + .feature("feat1", &[]) + .file( + "src/lib.rs", + r#" + extern crate somedep; + + #[cfg(not(feature="feat1"))] + compile_error!{"feat1 missing"} + "#, + ) + .publish(); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + # This should never be selected. + [target.'{}'.build-dependencies] + targetdep = "1.0" + + [target.'{}'.build-dependencies] + hostdep = {{version="1.0", features=["feat1"]}} + "#, + alternate(), + rustc_host() + ), + ) + .file("src/lib.rs", "") + .file("build.rs", "fn main() {}") + .build(); + + p.cargo("check").run(); + p.cargo("check -Zfeatures=all") + .masquerade_as_nightly_cargo() + .run(); + p.cargo("check --target").arg(alternate()).run(); + p.cargo("check -Zfeatures=all --target") + .arg(alternate()) + .masquerade_as_nightly_cargo() + .run(); +}