Skip to content

Commit ec2b0e4

Browse files
committed
Auto merge of #154724 - Daniel-B-Smith:smithdb3/fix-94878, r=<try>
Computing crate_hash from metadata encoding instead of HIR (implements #94878) (very draft)
2 parents 52b6e2c + 31ed5df commit ec2b0e4

11 files changed

Lines changed: 366 additions & 192 deletions

File tree

compiler/rustc_ast_lowering/src/lib.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,8 +562,11 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> mid_hir::Crate<'_> {
562562
}
563563

564564
// Don't hash unless necessary, because it's expensive.
565-
let opt_hir_hash =
566-
if tcx.needs_crate_hash() { Some(compute_hir_hash(tcx, &owners)) } else { None };
565+
let opt_hir_hash = if tcx.needs_crate_hash() && !tcx.needs_metadata() {
566+
Some(compute_hir_hash(tcx, &owners))
567+
} else {
568+
None
569+
};
567570

568571
let delayed_resolver = Steal::new((resolver, krate));
569572
mid_hir::Crate::new(owners, delayed_ids, delayed_resolver, opt_hir_hash)

compiler/rustc_driver_impl/src/lib.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -324,10 +324,6 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
324324

325325
tcx.ensure_ok().analysis(());
326326

327-
if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
328-
dump_feature_usage_metrics(tcx, metrics_dir);
329-
}
330-
331327
if callbacks.after_analysis(compiler, tcx) == Compilation::Stop {
332328
return early_exit();
333329
}
@@ -340,6 +336,10 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
340336

341337
let linker = Linker::codegen_and_build_linker(tcx, &*compiler.codegen_backend);
342338

339+
if let Some(metrics_dir) = &sess.opts.unstable_opts.metrics_dir {
340+
dump_feature_usage_metrics(tcx, metrics_dir);
341+
}
342+
343343
tcx.report_unused_features();
344344

345345
Some(linker)

compiler/rustc_interface/src/passes.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -948,8 +948,13 @@ pub fn create_and_enter_global_ctxt<T, F: for<'tcx> FnOnce(TyCtxt<'tcx>) -> T>(
948948
let definitions = FreezeLock::new(Definitions::new(stable_crate_id));
949949

950950
let stable_crate_ids = FreezeLock::new(StableCrateIdMap::default());
951-
let untracked =
952-
Untracked { cstore, source_span: AppendOnlyIndexVec::new(), definitions, stable_crate_ids };
951+
let untracked = Untracked {
952+
cstore,
953+
source_span: AppendOnlyIndexVec::new(),
954+
definitions,
955+
stable_crate_ids,
956+
local_crate_hash: OnceLock::new(),
957+
};
953958

954959
// We're constructing the HIR here; we don't care what we will
955960
// read, since we haven't even constructed the *input* to

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ use std::any::Any;
22
use std::mem;
33
use std::sync::Arc;
44

5+
use rustc_data_structures::fingerprint::Fingerprint;
6+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
7+
use rustc_data_structures::svh::Svh;
58
use rustc_hir::attrs::Deprecation;
69
use rustc_hir::def::{CtorKind, DefKind};
710
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
811
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
912
use rustc_middle::arena::ArenaAllocatable;
1013
use rustc_middle::bug;
1114
use rustc_middle::metadata::{AmbigModChild, ModChild};
15+
use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
1216
use rustc_middle::middle::exported_symbols::ExportedSymbol;
1317
use rustc_middle::middle::stability::DeprecationEntry;
1418
use rustc_middle::queries::ExternProviders;
@@ -20,7 +24,7 @@ use rustc_serialize::Decoder;
2024
use rustc_session::StableCrateId;
2125
use rustc_session::cstore::{CrateStore, ExternCrate};
2226
use rustc_span::hygiene::ExpnId;
23-
use rustc_span::{Span, Symbol, kw};
27+
use rustc_span::{Span, Symbol, kw, with_metavar_spans};
2428

2529
use super::{Decodable, DecodeIterator};
2630
use crate::creader::{CStore, LoadedMacro};
@@ -750,4 +754,104 @@ fn provide_cstore_hooks(providers: &mut Providers) {
750754
cdata.imported_source_file(tcx, file_index as u32);
751755
}
752756
};
757+
758+
providers.queries.crate_hash = |tcx: TyCtxt<'_>, _: LocalCrate| {
759+
if tcx.needs_metadata() {
760+
*tcx.untracked()
761+
.local_crate_hash
762+
.get()
763+
.expect("crate_hash(LOCAL_CRATE) called before metadata encoding")
764+
} else {
765+
crate_hash(tcx)
766+
}
767+
};
768+
}
769+
770+
pub(super) fn crate_hash(tcx: TyCtxt<'_>) -> Svh {
771+
let krate = tcx.hir_crate(());
772+
let hir_body_hash = krate.opt_hir_hash.expect("HIR hash missing while computing crate hash");
773+
774+
let upstream_crates = upstream_crates(tcx);
775+
776+
let resolutions = tcx.resolutions(());
777+
778+
// We hash the final, remapped names of all local source files so we
779+
// don't have to include the path prefix remapping commandline args.
780+
// If we included the full mapping in the SVH, we could only have
781+
// reproducible builds by compiling from the same directory. So we just
782+
// hash the result of the mapping instead of the mapping itself.
783+
let mut source_file_names: Vec<_> = tcx
784+
.sess
785+
.source_map()
786+
.files()
787+
.iter()
788+
.filter(|source_file| source_file.cnum == LOCAL_CRATE)
789+
.map(|source_file| source_file.stable_id)
790+
.collect();
791+
792+
source_file_names.sort_unstable();
793+
794+
// We have to take care of debugger visualizers explicitly. The HIR (and
795+
// thus `hir_body_hash`) contains the #[debugger_visualizer] attributes but
796+
// these attributes only store the file path to the visualizer file, not
797+
// their content. Yet that content is exported into crate metadata, so any
798+
// changes to it need to be reflected in the crate hash.
799+
let debugger_visualizers: Vec<_> = tcx
800+
.debugger_visualizers(LOCAL_CRATE)
801+
.iter()
802+
// We ignore the path to the visualizer file since it's not going to be
803+
// encoded in crate metadata and we already hash the full contents of
804+
// the file.
805+
.map(DebuggerVisualizerFile::path_erased)
806+
.collect();
807+
808+
let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| {
809+
let mut stable_hasher = StableHasher::new();
810+
hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
811+
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
812+
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
813+
debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher);
814+
if tcx.sess.opts.incremental.is_some() {
815+
let definitions = tcx.untracked().definitions.freeze();
816+
let mut owner_spans: Vec<_> = tcx
817+
.hir_crate_items(())
818+
.definitions()
819+
.map(|def_id| {
820+
let def_path_hash = definitions.def_path_hash(def_id);
821+
let span = tcx.source_span(def_id);
822+
debug_assert_eq!(span.parent(), None);
823+
(def_path_hash, span)
824+
})
825+
.collect();
826+
owner_spans.sort_unstable_by_key(|bn| bn.0);
827+
owner_spans.hash_stable(&mut hcx, &mut stable_hasher);
828+
}
829+
tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher);
830+
tcx.stable_crate_id(LOCAL_CRATE).hash_stable(&mut hcx, &mut stable_hasher);
831+
// Hash visibility information since it does not appear in HIR.
832+
// FIXME: Figure out how to remove `visibilities_for_hashing` by hashing visibilities on
833+
// the fly in the resolver, storing only their accumulated hash in `ResolverGlobalCtxt`,
834+
// and combining it with other hashes here.
835+
resolutions.visibilities_for_hashing.hash_stable(&mut hcx, &mut stable_hasher);
836+
with_metavar_spans(|mspans| {
837+
mspans.freeze_and_get_read_spans().hash_stable(&mut hcx, &mut stable_hasher);
838+
});
839+
stable_hasher.finish()
840+
});
841+
842+
Svh::new(crate_hash)
843+
}
844+
845+
fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> {
846+
let mut upstream_crates: Vec<_> = tcx
847+
.crates(())
848+
.iter()
849+
.map(|&cnum| {
850+
let stable_crate_id = tcx.stable_crate_id(cnum);
851+
let hash = tcx.crate_hash(cnum);
852+
(stable_crate_id, hash)
853+
})
854+
.collect();
855+
upstream_crates.sort_unstable_by_key(|&(stable_crate_id, _)| stable_crate_id);
856+
upstream_crates
753857
}

0 commit comments

Comments
 (0)