diff --git a/src/cargo/core/compiler/fingerprint/dirty_reason.rs b/src/cargo/core/compiler/fingerprint/dirty_reason.rs index 363aab7e624..38b3fc4411b 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 b1040be41b8..e1737a8b657 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, @@ -1431,6 +1443,9 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult>(); + declared_features.sort(); // to avoid useless rebuild if the user orders it's features + // differently Ok(Fingerprint { rustc: util::hash_u64(&cx.bcx.rustc().verbose_version), target: util::hash_u64(&unit.target), @@ -1439,6 +1454,14 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult "cfg" of "feature" with "f_a" "f_b")) + .with_stderr_does_not_contain("[..]unexpected_cfgs[..]") + .run(); + + p.cargo("check -v -Zcheck-cfg") + .masquerade_as_nightly_cargo(&["check-cfg"]) + .with_stderr_does_not_contain("[..]rustc[..]") + .run(); + + // checking that re-ordering the features does not invalid the fingerprint + p.change_file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [features] + f_b = [] + f_a = [] + "#, + ); + + 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 = [] + "#, + ); + + p.cargo("check -v -Zcheck-cfg") + .masquerade_as_nightly_cargo(&["check-cfg"]) + // we check that the fingerprint is indeed dirty + .with_stderr_contains("[..]Dirty[..]the list of declared features changed") + // that is cause rustc to be called again with the new check-cfg args + .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a")) + // and that we indeed found a new warning from the unexpected_cfgs lint + .with_stderr_contains("[..]unexpected_cfgs[..]") + .run(); +} + #[cargo_test(nightly, reason = "--check-cfg is unstable")] fn well_known_names_values() { let p = project()