diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 9b4388c911f1b..7b81fbf494fd1 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -216,6 +216,7 @@ fn check_paths<'tcx>(tcx: TyCtxt<'tcx>, if_this_changed: &Sources, then_this_wou } fn dump_graph(tcx: TyCtxt<'_>) { + tcx.build_debug_def_path_hash_map(); let path: String = env::var("RUST_DEP_GRAPH").unwrap_or_else(|_| "dep_graph".to_string()); let query = tcx.dep_graph.query(); diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index 35428dc8d84e5..e371a01ae89fe 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -210,6 +210,12 @@ pub fn load_query_result_cache<'a>( definitions: &Definitions, ) -> Option> { if sess.opts.incremental.is_none() { + // Create a cache so that we can map any `DefPathHash` + // to its `DefId` when printing the dep graph + if sess.opts.debugging_opts.dump_dep_graph { + return Some(OnDiskCache::new_empty(sess.source_map())); + } + // We have no use for a cache return None; } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 43f7b2a992838..a716d45804c61 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1591,6 +1591,29 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }) } + fn num_def_ids(&self) -> usize { + self.root.tables.def_keys.size() + } + + // Only used when certain `-Z` flags are enabled - should *not* be used + // otherwise + fn debug_all_def_path_hashes_and_def_ids(&self) -> Vec<(DefPathHash, DefId)> { + let mut def_path_hashes = self.def_path_hash_cache.lock(); + let mut def_index_to_data = |index| { + (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) + }; + if let Some(data) = &self.root.proc_macro_data { + std::iter::once(CRATE_DEF_INDEX) + .chain(data.macros.decode(self)) + .map(def_index_to_data) + .collect() + } else { + (0..self.num_def_ids()) + .map(|index| def_index_to_data(DefIndex::from_usize(index))) + .collect() + } + } + #[inline] fn def_path_hash(&self, index: DefIndex) -> DefPathHash { let mut def_path_hashes = self.def_path_hash_cache.lock(); @@ -1926,10 +1949,6 @@ impl CrateMetadata { self.root.hash } - fn num_def_ids(&self) -> usize { - self.root.tables.def_keys.size() - } - fn local_def_id(&self, index: DefIndex) -> DefId { DefId { krate: self.cnum, index } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index b7f2288521790..9cf95472adcf0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -529,4 +529,12 @@ impl CrateStore for CStore { fn allocator_kind(&self) -> Option { self.allocator_kind() } + + fn debug_all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)> { + self.get_crate_data(cnum).debug_all_def_path_hashes_and_def_ids() + } + + fn num_def_ids(&self, cnum: CrateNum) -> usize { + self.get_crate_data(cnum).num_def_ids() + } } diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index 6d2c43874bc0f..93a33c9f8c5b1 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -210,6 +210,8 @@ pub trait CrateStore { fn encode_metadata(&self, tcx: TyCtxt<'_>) -> EncodedMetadata; fn metadata_encoding_version(&self) -> &[u8]; fn allocator_kind(&self) -> Option; + fn debug_all_def_path_hashes_and_def_ids(&self, cnum: CrateNum) -> Vec<(DefPathHash, DefId)>; + fn num_def_ids(&self, cnum: CrateNum) -> usize; } pub type CrateStoreDyn = dyn CrateStore + sync::Sync; diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index b2db09cbc8065..9162711e49e32 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1343,6 +1343,12 @@ impl<'tcx> TyCtxt<'tcx> { self.queries.on_disk_cache.as_ref().map(|c| c.serialize(self, encoder)).unwrap_or(Ok(())) } + pub fn build_debug_def_path_hash_map(self) { + if let Some(cache) = &self.queries.on_disk_cache { + cache.build_debug_def_path_hash_map(self); + } + } + /// If `true`, we should use the MIR-based borrowck, but also /// fall back on the AST borrowck if the MIR-based one errors. pub fn migrate_borrowck(self) -> bool { diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index 8a1165bbd647a..78a81b5c3f67d 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -8,6 +8,7 @@ use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder, Finger use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell}; use rustc_data_structures::thin_vec::ThinVec; +use rustc_data_structures::unhash::UnhashMap; use rustc_errors::Diagnostic; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathHash; @@ -108,6 +109,19 @@ pub struct OnDiskCache<'sess> { // may no longer exist in the current compilation session, so // we use `Option` so that we can cache a lookup failure. def_path_hash_to_def_id_cache: Lock>>, + + // A map from a `DefPathHash` to its corresponding `DefId`, for all + // known `DefId`s (both foreign and local). Building this map takes + // a significant amount of time, so it is only initialized when + // needed by certain `-Z` flags (currently `-Z dump-dep-graph`). + // When this `OnceCell` is not initialized, the other fields of + // this struct (e.g. `foreign_def_path_hahses`) are used to map + // `DefPathHashes` to `DefId`s + // + // This field should *not* be used directly - the `def_path_hash_to_def_id` + // function should be used to map a `DefPathHash` to its corresponding + // `DefId` + debug_def_path_hash_to_def_id: OnceCell>, } // This type is used only for serialization and deserialization. @@ -215,6 +229,7 @@ impl<'sess> OnDiskCache<'sess> { latest_foreign_def_path_hashes: Default::default(), local_def_path_hash_to_def_id: make_local_def_path_hash_map(definitions), def_path_hash_to_def_id_cache: Default::default(), + debug_def_path_hash_to_def_id: OnceCell::new(), } } @@ -237,6 +252,7 @@ impl<'sess> OnDiskCache<'sess> { latest_foreign_def_path_hashes: Default::default(), local_def_path_hash_to_def_id: Default::default(), def_path_hash_to_def_id_cache: Default::default(), + debug_def_path_hash_to_def_id: OnceCell::new(), } } @@ -474,6 +490,20 @@ impl<'sess> OnDiskCache<'sess> { .insert(hash, RawDefId { krate: def_id.krate.as_u32(), index: def_id.index.as_u32() }); } + pub fn build_debug_def_path_hash_map(&self, tcx: TyCtxt<'tcx>) { + let crates = tcx.cstore.crates_untracked(); + + let capacity = tcx.definitions.def_path_table().num_def_ids() + + crates.iter().map(|cnum| tcx.cstore.num_def_ids(*cnum)).sum::(); + let mut map = UnhashMap::with_capacity_and_hasher(capacity, Default::default()); + + map.extend(tcx.definitions.def_path_table().all_def_path_hashes_and_def_ids(LOCAL_CRATE)); + for cnum in &crates { + map.extend(tcx.cstore.debug_all_def_path_hashes_and_def_ids(*cnum).into_iter()); + } + self.debug_def_path_hash_to_def_id.set(map).unwrap(); + } + /// If the given `dep_node`'s hash still exists in the current compilation, /// and its current `DefId` is foreign, calls `store_foreign_def_id` with it. /// @@ -625,6 +655,14 @@ impl<'sess> OnDiskCache<'sess> { Entry::Occupied(e) => *e.get(), Entry::Vacant(e) => { debug!("def_path_hash_to_def_id({:?})", hash); + + if let Some(debug_map) = self.debug_def_path_hash_to_def_id.get() { + if let Some(def_id) = debug_map.get(&hash).copied() { + e.insert(Some(def_id)); + return Some(def_id); + } + } + // Check if the `DefPathHash` corresponds to a definition in the current // crate if let Some(def_id) = self.local_def_path_hash_to_def_id.get(&hash).cloned() { diff --git a/src/test/run-make/dump-dep-graph/Makefile b/src/test/run-make/dump-dep-graph/Makefile new file mode 100644 index 0000000000000..d82aa544123c6 --- /dev/null +++ b/src/test/run-make/dump-dep-graph/Makefile @@ -0,0 +1,15 @@ +include ../../run-make-fulldeps/tools.mk + +# Tests that the dep graph contains printed def paths, +# instead of just hashes + +all: main.rs + cp main.rs $(TMPDIR)/ + cd $(TMPDIR) + $(RUSTC) -Z dump-dep-graph $< + # Make sure that we can find a local function + # (my_function) and something from a foreign crate + # (compiler_builtins) in the dep graph + grep my_function dep_graph.txt + grep compiler_builtins dep_graph.txt + rm dep_graph.txt dep_graph.dot diff --git a/src/test/run-make/dump-dep-graph/main.rs b/src/test/run-make/dump-dep-graph/main.rs new file mode 100644 index 0000000000000..aacb2821daaa8 --- /dev/null +++ b/src/test/run-make/dump-dep-graph/main.rs @@ -0,0 +1,2 @@ +fn my_function() {} +fn main() {}