Only hash OutputTypes keys in non-crate-hash mode

This effectively turns OutputTypes into a hybrid where keys (OutputType)
are TRACKED and the values (optional paths) are TRACKED_NO_CRATE_HASH.
This commit is contained in:
Aaron Hill 2021-06-19 19:22:14 -05:00 committed by Jeremy Fitzhardinge
parent f1f7f2f508
commit 99f652ff22
3 changed files with 77 additions and 37 deletions

View file

@ -160,9 +160,9 @@ fn test_output_types_tracking_hash_different_paths() {
v2.output_types = OutputTypes::new(&[(OutputType::Exe, Some(PathBuf::from("/some/thing")))]);
v3.output_types = OutputTypes::new(&[(OutputType::Exe, None)]);
assert_same_hash(&v1, &v2);
assert_same_hash(&v1, &v3);
assert_same_hash(&v2, &v3);
assert_non_crate_hash_different(&v1, &v2);
assert_non_crate_hash_different(&v1, &v3);
assert_non_crate_hash_different(&v2, &v3);
}
#[test]

View file

@ -31,7 +31,7 @@ use std::collections::btree_map::{
};
use std::collections::{BTreeMap, BTreeSet};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::hash::Hash;
use std::iter::{self, FromIterator};
use std::path::{Path, PathBuf};
use std::str::{self, FromStr};
@ -328,19 +328,9 @@ impl Default for TrimmedDefPaths {
/// *Do not* switch `BTreeMap` out for an unsorted container type! That would break
/// dependency tracking for command-line arguments. Also only hash keys, since tracking
/// should only depend on the output types, not the paths they're written to.
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Hash)]
pub struct OutputTypes(BTreeMap<OutputType, Option<PathBuf>>);
impl Hash for OutputTypes {
fn hash<H: Hasher>(&self, hasher: &mut H) {
for k in self.keys() {
k.hash(hasher);
}
}
}
impl_stable_hash_via_hash!(OutputTypes);
impl OutputTypes {
pub fn new(entries: &[(OutputType, Option<PathBuf>)]) -> OutputTypes {
OutputTypes(BTreeMap::from_iter(entries.iter().map(|&(k, ref v)| (k, v.clone()))))
@ -2436,8 +2426,8 @@ crate mod dep_tracking {
use super::LdImpl;
use super::{
CFGuard, CrateType, DebugInfo, ErrorOutputType, InstrumentCoverage, LinkerPluginLto,
LtoCli, OptLevel, OutputTypes, Passes, SourceFileHashAlgorithm, SwitchWithOptPath,
SymbolManglingVersion, TrimmedDefPaths,
LtoCli, OptLevel, OutputType, OutputTypes, Passes, SourceFileHashAlgorithm,
SwitchWithOptPath, SymbolManglingVersion, TrimmedDefPaths,
};
use crate::lint;
use crate::options::WasiExecModel;
@ -2453,13 +2443,18 @@ crate mod dep_tracking {
use std::path::PathBuf;
pub trait DepTrackingHash {
fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType);
fn hash(
&self,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,
for_crate_hash: bool,
);
}
macro_rules! impl_dep_tracking_hash_via_hash {
($($t:ty),+ $(,)?) => {$(
impl DepTrackingHash for $t {
fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType, _for_crate_hash: bool) {
Hash::hash(self, hasher);
}
}
@ -2467,11 +2462,16 @@ crate mod dep_tracking {
}
impl<T: DepTrackingHash> DepTrackingHash for Option<T> {
fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
fn hash(
&self,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,
for_crate_hash: bool,
) {
match self {
Some(x) => {
Hash::hash(&1, hasher);
DepTrackingHash::hash(x, hasher, error_format);
DepTrackingHash::hash(x, hasher, error_format, for_crate_hash);
}
None => Hash::hash(&0, hasher),
}
@ -2501,7 +2501,6 @@ crate mod dep_tracking {
LtoCli,
DebugInfo,
UnstableFeatures,
OutputTypes,
NativeLib,
NativeLibKind,
SanitizerSet,
@ -2515,6 +2514,7 @@ crate mod dep_tracking {
SourceFileHashAlgorithm,
TrimmedDefPaths,
Option<LdImpl>,
OutputType,
);
impl<T1, T2> DepTrackingHash for (T1, T2)
@ -2522,11 +2522,16 @@ crate mod dep_tracking {
T1: DepTrackingHash,
T2: DepTrackingHash,
{
fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
fn hash(
&self,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,
for_crate_hash: bool,
) {
Hash::hash(&0, hasher);
DepTrackingHash::hash(&self.0, hasher, error_format);
DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
Hash::hash(&1, hasher);
DepTrackingHash::hash(&self.1, hasher, error_format);
DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
}
}
@ -2536,22 +2541,49 @@ crate mod dep_tracking {
T2: DepTrackingHash,
T3: DepTrackingHash,
{
fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
fn hash(
&self,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,
for_crate_hash: bool,
) {
Hash::hash(&0, hasher);
DepTrackingHash::hash(&self.0, hasher, error_format);
DepTrackingHash::hash(&self.0, hasher, error_format, for_crate_hash);
Hash::hash(&1, hasher);
DepTrackingHash::hash(&self.1, hasher, error_format);
DepTrackingHash::hash(&self.1, hasher, error_format, for_crate_hash);
Hash::hash(&2, hasher);
DepTrackingHash::hash(&self.2, hasher, error_format);
DepTrackingHash::hash(&self.2, hasher, error_format, for_crate_hash);
}
}
impl<T: DepTrackingHash> DepTrackingHash for Vec<T> {
fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) {
fn hash(
&self,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,
for_crate_hash: bool,
) {
Hash::hash(&self.len(), hasher);
for (index, elem) in self.iter().enumerate() {
Hash::hash(&index, hasher);
DepTrackingHash::hash(elem, hasher, error_format);
DepTrackingHash::hash(elem, hasher, error_format, for_crate_hash);
}
}
}
impl DepTrackingHash for OutputTypes {
fn hash(
&self,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,
for_crate_hash: bool,
) {
Hash::hash(&self.0.len(), hasher);
for (key, val) in &self.0 {
DepTrackingHash::hash(key, hasher, error_format, for_crate_hash);
if !for_crate_hash {
DepTrackingHash::hash(val, hasher, error_format, for_crate_hash);
}
}
}
}
@ -2561,13 +2593,14 @@ crate mod dep_tracking {
sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>,
hasher: &mut DefaultHasher,
error_format: ErrorOutputType,
for_crate_hash: bool,
) {
for (key, sub_hash) in sub_hashes {
// Using Hash::hash() instead of DepTrackingHash::hash() is fine for
// the keys, as they are just plain strings
Hash::hash(&key.len(), hasher);
Hash::hash(key, hasher);
sub_hash.hash(hasher, error_format);
sub_hash.hash(hasher, error_format, for_crate_hash);
}
}
}

View file

@ -48,7 +48,11 @@ macro_rules! hash_substruct {
($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [TRACKED_NO_CRATE_HASH]) => {{}};
($opt_name:ident, $opt_expr:expr, $error_format:expr, $for_crate_hash:expr, $hasher:expr, [SUBSTRUCT]) => {
use crate::config::dep_tracking::DepTrackingHash;
$opt_expr.dep_tracking_hash($for_crate_hash, $error_format).hash($hasher, $error_format);
$opt_expr.dep_tracking_hash($for_crate_hash, $error_format).hash(
$hasher,
$error_format,
$for_crate_hash,
);
};
}
@ -79,7 +83,8 @@ macro_rules! top_level_options {
let mut hasher = DefaultHasher::new();
dep_tracking::stable_hash(sub_hashes,
&mut hasher,
self.error_format);
self.error_format,
for_crate_hash);
$({
hash_substruct!($opt,
&self.$opt,
@ -236,19 +241,21 @@ macro_rules! options {
build_options(matches, $stat, $prefix, $outputname, error_format)
}
fn dep_tracking_hash(&self, _for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
fn dep_tracking_hash(&self, for_crate_hash: bool, error_format: ErrorOutputType) -> u64 {
let mut sub_hashes = BTreeMap::new();
$({
hash_opt!($opt,
&self.$opt,
&mut sub_hashes,
_for_crate_hash,
for_crate_hash,
[$dep_tracking_marker]);
})*
let mut hasher = DefaultHasher::new();
dep_tracking::stable_hash(sub_hashes,
&mut hasher,
error_format);
error_format,
for_crate_hash
);
hasher.finish()
}
}