diff --git a/src/cargo/core/compiler/fingerprint/dirty_reason.rs b/src/cargo/core/compiler/fingerprint/dirty_reason.rs index 363aab7e624e..38b3fc4411b0 100644 --- a/src/cargo/core/compiler/fingerprint/dirty_reason.rs +++ b/src/cargo/core/compiler/fingerprint/dirty_reason.rs @@ -15,6 +15,10 @@ pub enum DirtyReason { old: String, new: String, }, + DeclaredFeaturesChanged { + old: String, + new: String, + }, TargetConfigurationChanged, PathToSourceChanged, ProfileConfigurationChanged, @@ -141,6 +145,9 @@ impl DirtyReason { DirtyReason::FeaturesChanged { .. } => { s.dirty_because(unit, "the list of features changed") } + DirtyReason::DeclaredFeaturesChanged { .. } => { + s.dirty_because(unit, "the list of declared features changed") + } DirtyReason::TargetConfigurationChanged => { s.dirty_because(unit, "the target configuration changed") } diff --git a/src/cargo/core/compiler/fingerprint/mod.rs b/src/cargo/core/compiler/fingerprint/mod.rs index b1040be41b8f..432837cfce5d 100644 --- a/src/cargo/core/compiler/fingerprint/mod.rs +++ b/src/cargo/core/compiler/fingerprint/mod.rs @@ -65,6 +65,7 @@ //! Target Name | ✓ | ✓ //! TargetKind (bin/lib/etc.) | ✓ | ✓ //! Enabled Features | ✓ | ✓ +//! Declared Features | ✓ | ? //! Immediate dependency’s hashes | ✓[^1] | ✓ //! [`CompileKind`] (host/target) | ✓ | ✓ //! __CARGO_DEFAULT_LIB_METADATA[^4] | | ✓ @@ -572,6 +573,8 @@ pub struct Fingerprint { rustc: u64, /// Sorted list of cfg features enabled. features: String, + /// Sorted list of all the declared cfg features. + declared_features: String, /// Hash of the `Target` struct, including the target name, /// package-relative source path, edition, etc. target: u64, @@ -876,6 +879,7 @@ impl Fingerprint { profile: 0, path: 0, features: String::new(), + declared_features: String::new(), deps: Vec::new(), local: Mutex::new(Vec::new()), memoized_hash: Mutex::new(None), @@ -922,6 +926,12 @@ impl Fingerprint { new: self.features.clone(), }; } + if self.declared_features != old.declared_features { + return DirtyReason::DeclaredFeaturesChanged { + old: old.declared_features.clone(), + new: self.declared_features.clone(), + }; + } if self.target != old.target { return DirtyReason::TargetConfigurationChanged; } @@ -1200,6 +1210,7 @@ impl hash::Hash for Fingerprint { let Fingerprint { rustc, ref features, + ref declared_features, target, path, profile, @@ -1215,6 +1226,7 @@ impl hash::Hash for Fingerprint { ( rustc, features, + declared_features, target, path, profile, @@ -1439,6 +1451,17 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult>() + ) + } else { + "".to_string() + }, deps, local: Mutex::new(local), memoized_hash: Mutex::new(None), diff --git a/tests/testsuite/check_cfg.rs b/tests/testsuite/check_cfg.rs index 57d5f8053636..401c956b50b5 100644 --- a/tests/testsuite/check_cfg.rs +++ b/tests/testsuite/check_cfg.rs @@ -141,6 +141,53 @@ fn features_with_namespaced_features() { .run(); } +#[cargo_test(nightly, reason = "--check-cfg is unstable")] +fn features_fingerprint() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [features] + f_a = [] + "#, + ) + .file("src/main.rs", "fn main() {}") + .build(); + + p.cargo("check -v -Zcheck-cfg") + .masquerade_as_nightly_cargo(&["check-cfg"]) + .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a")) + .run(); + + p.cargo("check -v -Zcheck-cfg") + .masquerade_as_nightly_cargo(&["check-cfg"]) + .with_stderr_does_not_contain("rustc") + .run(); + + p.change_file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [features] + f_a = [] + f_b = [] + "#, + ); + + p.cargo("check -v -Zcheck-cfg") + .masquerade_as_nightly_cargo(&["check-cfg"]) + .with_stderr_contains("[..]Dirty[..]the list of declared features changed") + .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b")) + .run(); +} + #[cargo_test(nightly, reason = "--check-cfg is unstable")] fn well_known_names_values() { let p = project()