diff --git a/Cargo.lock b/Cargo.lock index 9b2bcfd1e8b8c..8c3fb7fc3d4a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4244,6 +4244,7 @@ dependencies = [ "rustc_expand", "rustc_feature", "rustc_fs_util", + "rustc_hashes", "rustc_hir", "rustc_hir_pretty", "rustc_incremental", diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 014fd5cf3a0e5..6b4f8ddf8be3f 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -1,8 +1,7 @@ -use std::collections::hash_map::Entry::*; - use rustc_abi::{CanonAbi, X86Call}; use rustc_ast::expand::allocator::{AllocatorKind, NO_ALLOC_SHIM_IS_UNSTABLE, global_fn_name}; -use rustc_data_structures::unord::UnordMap; +use rustc_data_structures::fx::FxIndexMap; +use rustc_hashes::Hash128; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE, LocalDefId}; use rustc_middle::bug; @@ -395,89 +394,32 @@ fn exported_generic_symbols_provider_local<'tcx>( tcx.arena.alloc_from_iter(symbols) } -fn upstream_monomorphizations_provider( +fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + !tcx.reachable_set(()).contains(&def_id) +} + +fn upstream_monomorphization_hashes_provider( tcx: TyCtxt<'_>, (): (), -) -> DefIdMap, CrateNum>> { - let cnums = tcx.crates(()); - - let mut instances: DefIdMap> = Default::default(); - - let drop_glue_fn_def_id = tcx.lang_items().drop_glue_fn(); - let async_drop_in_place_fn_def_id = tcx.lang_items().async_drop_in_place_fn(); - - for &cnum in cnums.iter() { - for (exported_symbol, _) in tcx.exported_generic_symbols(cnum).iter() { - let (def_id, args) = match *exported_symbol { - ExportedSymbol::Generic(def_id, args) => (def_id, args), - ExportedSymbol::DropGlue(ty) => { - if let Some(drop_in_place_fn_def_id) = drop_glue_fn_def_id { - (drop_in_place_fn_def_id, tcx.mk_args(&[ty.into()])) - } else { - // `drop_glue` does not exist, don't try to use it. - continue; - } - } - ExportedSymbol::AsyncDropGlueCtorShim(ty) => { - if let Some(async_drop_in_place_fn_def_id) = async_drop_in_place_fn_def_id { - (async_drop_in_place_fn_def_id, tcx.mk_args(&[ty.into()])) - } else { - continue; - } - } - ExportedSymbol::AsyncDropGlue(def_id, ty) => (def_id, tcx.mk_args(&[ty.into()])), - ExportedSymbol::NonGeneric(..) - | ExportedSymbol::ThreadLocalShim(..) - | ExportedSymbol::NoDefId(..) => unreachable!("{exported_symbol:?}"), - }; - - let args_map = instances.entry(def_id).or_default(); - - match args_map.entry(args) { - Occupied(mut e) => { - // If there are multiple monomorphizations available, - // we select one deterministically. - let other_cnum = *e.get(); - if tcx.stable_crate_id(other_cnum) > tcx.stable_crate_id(cnum) { - e.insert(cnum); - } - } - Vacant(e) => { - e.insert(cnum); - } - } +) -> FxIndexMap> { + let mut map: FxIndexMap> = Default::default(); + for &cnum in tcx.crates(()) { + for &hash in tcx.exported_generic_symbol_hashes(cnum) { + map.entry(hash).or_default().push(cnum); } } - - instances + // Sort each candidate list by StableCrateId for determinism. + for candidates in map.values_mut() { + candidates.sort_by_key(|&cnum| tcx.stable_crate_id(cnum)); + } + map } -fn upstream_monomorphizations_for_provider( +fn upstream_monomorphization_for_hash_provider( tcx: TyCtxt<'_>, - def_id: DefId, -) -> Option<&UnordMap, CrateNum>> { - assert!(!def_id.is_local()); - tcx.upstream_monomorphizations(()).get(&def_id) -} - -fn upstream_drop_glue_for_provider<'tcx>( - tcx: TyCtxt<'tcx>, - args: GenericArgsRef<'tcx>, -) -> Option { - let def_id = tcx.lang_items().drop_glue_fn()?; - tcx.upstream_monomorphizations_for(def_id)?.get(&args).cloned() -} - -fn upstream_async_drop_glue_for_provider<'tcx>( - tcx: TyCtxt<'tcx>, - args: GenericArgsRef<'tcx>, -) -> Option { - let def_id = tcx.lang_items().async_drop_in_place_fn()?; - tcx.upstream_monomorphizations_for(def_id)?.get(&args).cloned() -} - -fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - !tcx.reachable_set(()).contains(&def_id) + hash: Hash128, +) -> Option<&smallvec::SmallVec<[CrateNum; 1]>> { + tcx.upstream_monomorphization_hashes(()).get(&hash) } pub(crate) fn provide(providers: &mut Providers) { @@ -485,14 +427,12 @@ pub(crate) fn provide(providers: &mut Providers) { providers.queries.is_reachable_non_generic = is_reachable_non_generic_provider_local; providers.queries.exported_non_generic_symbols = exported_non_generic_symbols_provider_local; providers.queries.exported_generic_symbols = exported_generic_symbols_provider_local; - providers.queries.upstream_monomorphizations = upstream_monomorphizations_provider; providers.queries.is_unreachable_local_definition = is_unreachable_local_definition_provider; - providers.queries.upstream_drop_glue_for = upstream_drop_glue_for_provider; - providers.queries.upstream_async_drop_glue_for = upstream_async_drop_glue_for_provider; + providers.queries.upstream_monomorphization_hashes = upstream_monomorphization_hashes_provider; + providers.queries.upstream_monomorphization_for_hash = + upstream_monomorphization_for_hash_provider; providers.queries.wasm_import_module_map = wasm_import_module_map; providers.extern_queries.is_reachable_non_generic = is_reachable_non_generic_provider_extern; - providers.extern_queries.upstream_monomorphizations_for = - upstream_monomorphizations_for_provider; } pub(crate) fn allocator_shim_symbols( diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml index 3a70ee130c27b..83f391a818c4a 100644 --- a/compiler/rustc_metadata/Cargo.toml +++ b/compiler/rustc_metadata/Cargo.toml @@ -16,6 +16,7 @@ rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } rustc_feature = { path = "../rustc_feature" } rustc_fs_util = { path = "../rustc_fs_util" } +rustc_hashes = { path = "../rustc_hashes" } rustc_hir = { path = "../rustc_hir" } rustc_hir_pretty = { path = "../rustc_hir_pretty" } rustc_incremental = { path = "../rustc_incremental" } diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 230ce5686e979..9660569ca4a21 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -1527,6 +1527,15 @@ impl CrateMetadata { tcx.arena.alloc_from_iter(self.root.exported_generic_symbols.decode((self, tcx))) } + fn exported_generic_symbol_hashes<'tcx>( + &self, + tcx: TyCtxt<'tcx>, + ) -> &'tcx [rustc_hashes::Hash128] { + let table: exported_symbol_hash_map::ExportedSymbolHashTableRef = + self.root.exported_generic_symbol_hashes.decode(&self.blob); + tcx.arena.alloc_from_iter(table.keys()) + } + fn get_macro(&self, tcx: TyCtxt<'_>, id: DefIndex) -> ast::MacroDef { match self.def_kind(id) { DefKind::Macro(_) => { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index cbd6afd68473a..d347c7e17d867 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -405,6 +405,7 @@ provide! { tcx, def_id, other, cdata, } exported_non_generic_symbols => { cdata.exported_non_generic_symbols(tcx) } exported_generic_symbols => { cdata.exported_generic_symbols(tcx) } + exported_generic_symbol_hashes => { cdata.exported_generic_symbol_hashes(tcx) } crate_extern_paths => { cdata.source().paths().cloned().collect() } expn_that_defined => { cdata.get_expn_that_defined(tcx, def_id.index) } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index a0db004b7f4c4..98b2ddb3282f6 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -701,6 +701,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { ) }); + let exported_generic_symbol_hashes = stat!("exported-symbol-hashes", || { + self.encode_exported_generic_symbol_hashes(tcx.exported_generic_symbols(LOCAL_CRATE)) + }); + // Encode the hygiene data. // IMPORTANT: this *must* be the last thing that we encode (other than `SourceMap`). The // process of encoding other items (e.g. `optimized_mir`) may cause us to load data from @@ -768,6 +772,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { stable_order_of_exportable_impls, exported_non_generic_symbols, exported_generic_symbols, + exported_generic_symbol_hashes, interpret_alloc_index, tables, syntax_contexts, @@ -2269,6 +2274,30 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy_array(exported_symbols.iter().cloned()) } + fn encode_exported_generic_symbol_hashes( + &mut self, + exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportInfo)], + ) -> LazyValue { + use exported_symbol_hash_map::{ExportedSymbolHashTable, ExportedSymbolHashTableRef}; + use rustc_data_structures::stable_hash::{StableHash, StableHasher}; + + let tcx = self.tcx; + let mut table = ExportedSymbolHashTable::with_capacity(exported_symbols.len(), 87); + + for (sym, _) in exported_symbols { + if let Some(instance) = sym.to_instance(tcx) { + let hash = tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + instance.stable_hash(&mut hcx, &mut hasher); + hasher.finish() + }); + table.insert(&hash, &()); + } + } + + self.lazy(ExportedSymbolHashTableRef::Owned(table)) + } + fn encode_dylib_dependency_formats(&mut self) -> LazyArray> { empty_proc_macro!(self); let formats = self.tcx.dependency_formats(()); diff --git a/compiler/rustc_metadata/src/rmeta/exported_symbol_hash_map.rs b/compiler/rustc_metadata/src/rmeta/exported_symbol_hash_map.rs new file mode 100644 index 0000000000000..c067902f2ebb4 --- /dev/null +++ b/compiler/rustc_metadata/src/rmeta/exported_symbol_hash_map.rs @@ -0,0 +1,87 @@ +use rustc_data_structures::owned_slice::OwnedSlice; +use rustc_hashes::Hash128; +use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; + +use crate::rmeta::EncodeContext; +use crate::rmeta::decoder::BlobDecodeContext; + +#[derive(Clone, Default)] +pub(crate) struct ExportedSymbolHashConfig; + +impl odht::Config for ExportedSymbolHashConfig { + type Key = Hash128; + type Value = (); + + type EncodedKey = [u8; 16]; + type EncodedValue = [u8; 0]; + + type H = odht::UnHashFn; + + #[inline] + fn encode_key(k: &Hash128) -> [u8; 16] { + k.as_u128().to_le_bytes() + } + + #[inline] + fn encode_value(_v: &()) -> [u8; 0] { + [] + } + + #[inline] + fn decode_key(k: &[u8; 16]) -> Hash128 { + Hash128::new(u128::from_le_bytes(*k)) + } + + #[inline] + fn decode_value(_v: &[u8; 0]) {} +} + +pub(crate) type ExportedSymbolHashTable = odht::HashTableOwned; + +pub(crate) enum ExportedSymbolHashTableRef { + /// Zero-copy view into metadata bytes. + OwnedFromMetadata(odht::HashTable), + /// Locally built table, used during encoding. + Owned(ExportedSymbolHashTable), +} + +impl ExportedSymbolHashTableRef { + pub(crate) fn keys(&self) -> Vec { + match self { + Self::OwnedFromMetadata(table) => table.iter().map(|(k, ())| k).collect(), + Self::Owned(table) => table.iter().map(|(k, ())| k).collect(), + } + } +} + +impl<'a, 'tcx> Encodable> for ExportedSymbolHashTableRef { + fn encode(&self, e: &mut EncodeContext<'a, 'tcx>) { + let raw_bytes = match self { + ExportedSymbolHashTableRef::Owned(table) => table.raw_bytes(), + ExportedSymbolHashTableRef::OwnedFromMetadata(_) => { + panic!( + "ExportedSymbolHashTableRef::OwnedFromMetadata variant \ + only exists for deserialization" + ) + } + }; + e.emit_usize(raw_bytes.len()); + e.emit_raw_bytes(raw_bytes); + } +} + +impl<'a> Decodable> for ExportedSymbolHashTableRef { + fn decode(d: &mut BlobDecodeContext<'a>) -> ExportedSymbolHashTableRef { + let len = d.read_usize(); + let pos = d.position(); + let o = d.blob().bytes().clone().slice(|blob| &blob[pos..pos + len]); + + // Advance the decoder's position past the raw bytes we just sliced. + let _ = d.read_raw_bytes(len); + + let inner = odht::HashTable::from_raw_bytes(o).unwrap_or_else(|e| { + panic!("decode error for ExportedSymbolHashTable: {e}"); + }); + ExportedSymbolHashTableRef::OwnedFromMetadata(inner) + } +} diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index a3645a5556bf3..303454ce7c6ec 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -6,6 +6,7 @@ pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob, TargetModifie use def_path_hash_map::DefPathHashMapRef; use encoder::EncodeContext; pub use encoder::{EncodedMetadata, encode_metadata, rendered_const}; +use exported_symbol_hash_map::ExportedSymbolHashTableRef; pub(crate) use parameterized::ParameterizedOverTcx; use rustc_abi::{FieldIdx, ReprOptions, VariantIdx}; use rustc_ast as ast; @@ -50,6 +51,7 @@ use crate::eii::EiiMapEncodedKeyValue; mod decoder; mod def_path_hash_map; mod encoder; +mod exported_symbol_hash_map; mod parameterized; mod table; @@ -277,6 +279,7 @@ pub(crate) struct CrateRoot { stable_order_of_exportable_impls: LazyArray<(DefIndex, usize)>, exported_non_generic_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>, exported_generic_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>, + exported_generic_symbol_hashes: LazyValue, syntax_contexts: SyntaxContextTable, expn_data: ExpnDataTable, diff --git a/compiler/rustc_metadata/src/rmeta/parameterized.rs b/compiler/rustc_metadata/src/rmeta/parameterized.rs index 1531584e99788..0ac63bc77cab4 100644 --- a/compiler/rustc_metadata/src/rmeta/parameterized.rs +++ b/compiler/rustc_metadata/src/rmeta/parameterized.rs @@ -73,6 +73,7 @@ trivially_parameterized_over_tcx! { crate::rmeta::RawDefId, crate::rmeta::TraitImpls, crate::rmeta::VariantData, + crate::rmeta::exported_symbol_hash_map::ExportedSymbolHashTableRef, rustc_abi::ReprOptions, rustc_ast::DelimArgs, rustc_hir::Attribute, diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index fb770076f0a26..728eadf33b46d 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -1,7 +1,7 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_macros::{Decodable, Encodable, StableHash, TyDecodable, TyEncodable}; -use crate::ty::{self, GenericArgsRef, Ty, TyCtxt}; +use crate::ty::{self, GenericArgsRef, Instance, InstanceKind, Ty, TyCtxt}; /// The SymbolExportLevel of a symbols specifies from which kinds of crates /// the symbol will be exported. `C` symbols will be exported from any @@ -57,6 +57,39 @@ pub enum ExportedSymbol<'tcx> { } impl<'tcx> ExportedSymbol<'tcx> { + /// Convert to the corresponding [`Instance`], if this is a generic symbol. + /// + /// Returns `None` for `NonGeneric`, `ThreadLocalShim`, `NoDefId`, and when + /// required lang items are unavailable. + pub fn to_instance(&self, tcx: TyCtxt<'tcx>) -> Option> { + match *self { + ExportedSymbol::Generic(def_id, args) => { + Some(Instance { def: InstanceKind::Item(def_id), args }) + } + ExportedSymbol::DropGlue(ty) => { + let def_id = tcx.lang_items().drop_glue_fn()?; + Some(Instance { + def: InstanceKind::DropGlue(def_id, Some(ty)), + args: tcx.mk_args(&[ty.into()]), + }) + } + ExportedSymbol::AsyncDropGlueCtorShim(ty) => { + let def_id = tcx.lang_items().async_drop_in_place_fn()?; + Some(Instance { + def: InstanceKind::AsyncDropGlueCtorShim(def_id, ty), + args: tcx.mk_args(&[ty.into()]), + }) + } + ExportedSymbol::AsyncDropGlue(def_id, ty) => Some(Instance { + def: InstanceKind::AsyncDropGlue(def_id, ty), + args: tcx.mk_args(&[ty.into()]), + }), + ExportedSymbol::NonGeneric(..) + | ExportedSymbol::ThreadLocalShim(..) + | ExportedSymbol::NoDefId(..) => None, + } + } + /// This is the symbol name of an instance if it is instantiated in the /// local crate. pub fn symbol_name_for_local_instance(&self, tcx: TyCtxt<'tcx>) -> ty::SymbolName<'tcx> { diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index a9fc5dcac8f29..d569e3054b8a2 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -61,6 +61,7 @@ use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_errors::{ErrorGuaranteed, catch_fatal_errors}; +use rustc_hashes::Hash128; use rustc_hir as hir; use rustc_hir::attrs::{EiiDecl, EiiImpl, StrippedCfgItem}; use rustc_hir::def::{DefKind, DocLinkResMap}; @@ -1938,73 +1939,27 @@ rustc_queries! { } } - /// The entire set of monomorphizations the local crate can safely - /// link to because they are exported from upstream crates. Do - /// not depend on this directly, as its value changes anytime - /// a monomorphization gets added or removed in any upstream - /// crate. Instead use the narrower `upstream_monomorphizations_for`, - /// `upstream_drop_glue_for`, `upstream_async_drop_glue_for`, or, - /// even better, `Instance::upstream_monomorphization()`. - query upstream_monomorphizations(_: ()) -> &'tcx DefIdMap, CrateNum>> { - arena_cache - desc { "collecting available upstream monomorphizations" } + /// Set of all fingerprints of generic items exported by `cnum`. + query exported_generic_symbol_hashes(cnum: CrateNum) -> &'tcx [Hash128] { + desc { "getting exported generic symbol hashes for crate `{}`", cnum } + separate_provide_extern } - /// Returns the set of upstream monomorphizations available for the - /// generic function identified by the given `def_id`. The query makes - /// sure to make a stable selection if the same monomorphization is - /// available in multiple upstream crates. - /// - /// You likely want to call `Instance::upstream_monomorphization()` - /// instead of invoking this query directly. - query upstream_monomorphizations_for(def_id: DefId) - -> Option<&'tcx UnordMap, CrateNum>> + /// Returns a map from an monomorphized item hash to all crates containing it. As with anything hash-based, there may be collisions. + query upstream_monomorphization_hashes(_: ()) + -> &'tcx FxIndexMap> { - desc { - "collecting available upstream monomorphizations for `{}`", - tcx.def_path_str(def_id), - } - separate_provide_extern + arena_cache + desc { "collecting available upstream monomorphization hashes" } } - /// Returns the upstream crate that exports drop-glue for the given - /// type (`args` is expected to be a single-item list containing the - /// type one wants drop-glue for). - /// - /// This is a subset of `upstream_monomorphizations_for` in order to - /// increase dep-tracking granularity. Otherwise adding or removing any - /// type with drop-glue in any upstream crate would invalidate all - /// functions calling drop-glue of an upstream type. - /// - /// You likely want to call `Instance::upstream_monomorphization()` - /// instead of invoking this query directly. - /// - /// NOTE: This query could easily be extended to also support other - /// common functions that have are large set of monomorphizations - /// (like `Clone::clone` for example). - query upstream_drop_glue_for(args: GenericArgsRef<'tcx>) -> Option { - desc { "available upstream drop-glue for `{:?}`", args } + /// Returns all crates that contain a reusable monomorphization of an item with `hash`. + query upstream_monomorphization_for_hash(hash: Hash128) + -> Option<&'tcx smallvec::SmallVec<[CrateNum; 1]>> + { + desc { "looking up upstream monomorphization candidates by hash" } } - /// Returns the upstream crate that exports async-drop-glue for - /// the given type (`args` is expected to be a single-item list - /// containing the type one wants async-drop-glue for). - /// - /// This is a subset of `upstream_monomorphizations_for` in order - /// to increase dep-tracking granularity. Otherwise adding or - /// removing any type with async-drop-glue in any upstream crate - /// would invalidate all functions calling async-drop-glue of an - /// upstream type. - /// - /// You likely want to call `Instance::upstream_monomorphization()` - /// instead of invoking this query directly. - /// - /// NOTE: This query could easily be extended to also support other - /// common functions that have are large set of monomorphizations - /// (like `Clone::clone` for example). - query upstream_async_drop_glue_for(args: GenericArgsRef<'tcx>) -> Option { - desc { "available upstream async-drop-glue for `{:?}`", args } - } /// Returns a list of all `extern` blocks of a crate. query foreign_modules(_: CrateNum) -> &'tcx FxIndexMap { diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 569c30a6067a9..b728122d1aa1e 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -7,6 +7,7 @@ use std::hash::Hash; use rustc_ast::tokenstream::TokenStream; use rustc_data_structures::sso::SsoHashSet; use rustc_data_structures::stable_hash::StableHash; +use rustc_hashes::Hash128; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE, LocalDefId, LocalModDefId}; use rustc_hir::hir_id::OwnerId; use rustc_span::{DUMMY_SP, Ident, LocalExpnId, Span, Symbol}; @@ -286,6 +287,12 @@ impl QueryKey for Symbol { } } +impl QueryKey for Hash128 { + fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl QueryKey for Option { fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 1d761c2f43b3d..a5353cae46ff5 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -1,7 +1,9 @@ use std::{assert_matches, fmt}; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::stable_hash::{StableHash, StableHasher}; use rustc_errors::ErrorGuaranteed; +use rustc_hashes::Hash128; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Namespace}; use rustc_hir::def_id::{CrateNum, DefId}; @@ -222,15 +224,28 @@ impl<'tcx> Instance<'tcx> { } match self.def { - InstanceKind::Item(def) => tcx - .upstream_monomorphizations_for(def) - .and_then(|monos| monos.get(&self.args).cloned()), - InstanceKind::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.args), + InstanceKind::Item(_) + | InstanceKind::DropGlue(_, Some(_)) + | InstanceKind::AsyncDropGlueCtorShim(_, _) => { + let hash: Hash128 = tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + self.stable_hash(&mut hcx, &mut hasher); + hasher.finish() + }); + let candidates = tcx.upstream_monomorphization_for_hash(hash)?; + // Candidates are sorted by StableCrateId. First verified match wins. + for &cnum in candidates.iter() { + for (sym, _) in tcx.exported_generic_symbols(cnum).iter() { + if sym.to_instance(tcx).as_ref() == Some(self) { + return Some(cnum); + } + } + } + None + } InstanceKind::AsyncDropGlue(_, _) => None, InstanceKind::FutureDropPollShim(_, _, _) => None, - InstanceKind::AsyncDropGlueCtorShim(_, _) => { - tcx.upstream_async_drop_glue_for(self.args) - } + _ => None, } }