diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs index 511a77bf830e5..1f4318fa53751 100644 --- a/src/librustc/middle/exported_symbols.rs +++ b/src/librustc/middle/exported_symbols.rs @@ -1,9 +1,7 @@ -use crate::ich::StableHashingContext; use crate::ty::subst::SubstsRef; -use crate::ty::{self, TyCtxt}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use crate::ty::{self, Ty, TyCtxt}; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -use std::mem; +use rustc_macros::HashStable; /// The SymbolExportLevel of a symbols specifies from which kinds of crates /// the symbol will be exported. `C` symbols will be exported from any @@ -23,10 +21,11 @@ impl SymbolExportLevel { } } -#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable)] +#[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable, HashStable)] pub enum ExportedSymbol<'tcx> { NonGeneric(DefId), Generic(DefId, SubstsRef<'tcx>), + DropGlue(Ty<'tcx>), NoDefId(ty::SymbolName), } @@ -39,6 +38,9 @@ impl<'tcx> ExportedSymbol<'tcx> { ExportedSymbol::Generic(def_id, substs) => { tcx.symbol_name(ty::Instance::new(def_id, substs)) } + ExportedSymbol::DropGlue(ty) => { + tcx.symbol_name(ty::Instance::resolve_drop_in_place(tcx, ty)) + } ExportedSymbol::NoDefId(symbol_name) => symbol_name, } } @@ -51,21 +53,3 @@ pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String { tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex() ) } - -impl<'a, 'tcx> HashStable> for ExportedSymbol<'tcx> { - fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - ExportedSymbol::NonGeneric(def_id) => { - def_id.hash_stable(hcx, hasher); - } - ExportedSymbol::Generic(def_id, substs) => { - def_id.hash_stable(hcx, hasher); - substs.hash_stable(hcx, hasher); - } - ExportedSymbol::NoDefId(symbol_name) => { - symbol_name.hash_stable(hcx, hasher); - } - } - } -} diff --git a/src/librustc/query/mod.rs b/src/librustc/query/mod.rs index deb2d6ac630ac..37d5e23535b81 100644 --- a/src/librustc/query/mod.rs +++ b/src/librustc/query/mod.rs @@ -776,13 +776,47 @@ rustc_queries! { } Codegen { + /// 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`, or, even + /// better, `Instance::upstream_monomorphization()`. query upstream_monomorphizations( k: CrateNum ) -> &'tcx DefIdMap, CrateNum>> { desc { "collecting available upstream monomorphizations `{:?}`", k } } + + /// 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(_: DefId) -> Option<&'tcx FxHashMap, CrateNum>> {} + + /// Returns the upstream crate that exports drop-glue for the given + /// type (`substs` 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(substs: SubstsRef<'tcx>) -> Option { + desc { "available upstream drop-glue for `{:?}`", substs } + no_force + } } Other { diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index c4770184612cb..51a18f8eae274 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -4,7 +4,7 @@ use crate::traits; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::{self, SubstsRef, Ty, TyCtxt, TypeFoldable}; use rustc_hir::def::Namespace; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{CrateNum, DefId}; use rustc_macros::HashStable; use rustc_target::spec::abi::Abi; @@ -91,6 +91,40 @@ impl<'tcx> Instance<'tcx> { let ty = tcx.type_of(self.def.def_id()); tcx.subst_and_normalize_erasing_regions(self.substs, param_env, &ty) } + + /// Finds a crate that contains a monomorphization of this instance that + /// can be linked to from the local crate. A return value of `None` means + /// no upstream crate provides such an exported monomorphization. + /// + /// This method already takes into account the global `-Zshare-generics` + /// setting, always returning `None` if `share-generics` is off. + pub fn upstream_monomorphization(&self, tcx: TyCtxt<'tcx>) -> Option { + // If we are not in share generics mode, we don't link to upstream + // monomorphizations but always instantiate our own internal versions + // instead. + if !tcx.sess.opts.share_generics() { + return None; + } + + // If this is an item that is defined in the local crate, no upstream + // crate can know about it/provide a monomorphization. + if self.def_id().is_local() { + return None; + } + + // If this a non-generic instance, it cannot be a shared monomorphization. + if self.substs.non_erasable_generics().next().is_none() { + return None; + } + + match self.def { + InstanceDef::Item(def_id) => tcx + .upstream_monomorphizations_for(def_id) + .and_then(|monos| monos.get(&self.substs).cloned()), + InstanceDef::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.substs), + _ => None, + } + } } impl<'tcx> InstanceDef<'tcx> { diff --git a/src/librustc/ty/query/keys.rs b/src/librustc/ty/query/keys.rs index cbf335ad607ef..c1c88e96f94b5 100644 --- a/src/librustc/ty/query/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -116,6 +116,15 @@ impl Key for (DefId, SimplifiedType) { } } +impl<'tcx> Key for SubstsRef<'tcx> { + fn query_crate(&self) -> CrateNum { + LOCAL_CRATE + } + fn default_span(&self, _: TyCtxt<'_>) -> Span { + DUMMY_SP + } +} + impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { fn query_crate(&self) -> CrateNum { self.0.krate diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs index 78dd6fc8ffe75..04d92142266ee 100644 --- a/src/librustc_codegen_llvm/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -130,12 +130,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value } else { // This is a monomorphization of a generic function // defined in an upstream crate. - if cx - .tcx - .upstream_monomorphizations_for(instance_def_id) - .map(|set| set.contains_key(instance.substs)) - .unwrap_or(false) - { + if instance.upstream_monomorphization(tcx).is_some() { // This is instantiated in another crate. It cannot // be `hidden`. } else { diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/src/librustc_codegen_ssa/back/symbol_export.rs index 7e888a271e316..a6cd0c09684dd 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -255,14 +255,13 @@ fn exported_symbols_provider_local( symbols.push((symbol, SymbolExportLevel::Rust)); } } - MonoItem::Fn(Instance { def: InstanceDef::DropGlue(def_id, Some(ty)), substs }) => { + MonoItem::Fn(Instance { def: InstanceDef::DropGlue(_, Some(ty)), substs }) => { // A little sanity-check debug_assert_eq!( substs.non_erasable_generics().next(), Some(GenericArgKind::Type(ty)) ); - let symbol = ExportedSymbol::Generic(def_id, substs); - symbols.push((symbol, SymbolExportLevel::Rust)); + symbols.push((ExportedSymbol::DropGlue(ty), SymbolExportLevel::Rust)); } _ => { // Any other symbols don't qualify for sharing @@ -298,24 +297,41 @@ fn upstream_monomorphizations_provider( cnum_stable_ids }; + let drop_in_place_fn_def_id = tcx.lang_items().drop_in_place_fn(); + for &cnum in cnums.iter() { for (exported_symbol, _) in tcx.exported_symbols(cnum).iter() { - if let &ExportedSymbol::Generic(def_id, substs) = exported_symbol { - let substs_map = instances.entry(def_id).or_default(); - - match substs_map.entry(substs) { - Occupied(mut e) => { - // If there are multiple monomorphizations available, - // we select one deterministically. - let other_cnum = *e.get(); - if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] { - e.insert(cnum); - } + let (def_id, substs) = match *exported_symbol { + ExportedSymbol::Generic(def_id, substs) => (def_id, substs), + ExportedSymbol::DropGlue(ty) => { + if let Some(drop_in_place_fn_def_id) = drop_in_place_fn_def_id { + (drop_in_place_fn_def_id, tcx.intern_substs(&[ty.into()])) + } else { + // `drop_in_place` in place does not exist, don't try + // to use it. + continue; } - Vacant(e) => { + } + ExportedSymbol::NonGeneric(..) | ExportedSymbol::NoDefId(..) => { + // These are no monomorphizations + continue; + } + }; + + let substs_map = instances.entry(def_id).or_default(); + + match substs_map.entry(substs) { + Occupied(mut e) => { + // If there are multiple monomorphizations available, + // we select one deterministically. + let other_cnum = *e.get(); + if cnum_stable_ids[other_cnum] > cnum_stable_ids[cnum] { e.insert(cnum); } } + Vacant(e) => { + e.insert(cnum); + } } } } @@ -331,6 +347,17 @@ fn upstream_monomorphizations_for_provider( tcx.upstream_monomorphizations(LOCAL_CRATE).get(&def_id) } +fn upstream_drop_glue_for_provider<'tcx>( + tcx: TyCtxt<'tcx>, + substs: SubstsRef<'tcx>, +) -> Option { + if let Some(def_id) = tcx.lang_items().drop_in_place_fn() { + tcx.upstream_monomorphizations_for(def_id).and_then(|monos| monos.get(&substs).cloned()) + } else { + None + } +} + fn is_unreachable_local_definition_provider(tcx: TyCtxt<'_>, def_id: DefId) -> bool { if let Some(hir_id) = tcx.hir().as_local_hir_id(def_id) { !tcx.reachable_set(LOCAL_CRATE).contains(&hir_id) @@ -345,6 +372,7 @@ pub fn provide(providers: &mut Providers<'_>) { providers.exported_symbols = exported_symbols_provider_local; providers.upstream_monomorphizations = upstream_monomorphizations_provider; providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; + providers.upstream_drop_glue_for = upstream_drop_glue_for_provider; } pub fn provide_extern(providers: &mut Providers<'_>) { @@ -405,6 +433,11 @@ pub fn symbol_name_for_instance_in_crate<'tcx>( Instance::new(def_id, substs), instantiating_crate, ), + ExportedSymbol::DropGlue(ty) => symbol_names::symbol_name_for_instance_in_crate( + tcx, + Instance::resolve_drop_in_place(tcx, ty), + instantiating_crate, + ), ExportedSymbol::NoDefId(symbol_name) => symbol_name.to_string(), } } diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs index 96a74f96fcf60..6713459f627ef 100644 --- a/src/librustc_codegen_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -126,29 +126,10 @@ fn symbol_name_provider(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> ty::Symb // This closure determines the instantiating crate for instances that // need an instantiating-crate-suffix for their symbol name, in order // to differentiate between local copies. - // - // For generics we might find re-usable upstream instances. For anything - // else we rely on their being a local copy available. - if is_generic(instance.substs) { - let def_id = instance.def_id(); - - if !def_id.is_local() && tcx.sess.opts.share_generics() { - // If we are re-using a monomorphization from another crate, - // we have to compute the symbol hash accordingly. - let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id); - - upstream_monomorphizations - .and_then(|monos| monos.get(&instance.substs).cloned()) - // If there is no instance available upstream, there'll be - // one in the current crate. - .unwrap_or(LOCAL_CRATE) - } else { - // For generic functions defined in the current crate, there - // can be no upstream instances. Also, if we don't share - // generics, we'll instantiate a local copy too. - LOCAL_CRATE - } + // For generics we might find re-usable upstream instances. If there + // is one, we rely on the symbol being instantiated locally. + instance.upstream_monomorphization(tcx).unwrap_or(LOCAL_CRATE) } else { // For non-generic things that need to avoid naming conflicts, we // always instantiate a copy in the local crate. diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 91e685babbcdd..dd2071a6c596a 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -737,9 +737,7 @@ fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx return true; } - if tcx.is_reachable_non_generic(def_id) - || is_available_upstream_generic(tcx, def_id, instance.substs) - { + if tcx.is_reachable_non_generic(def_id) || instance.upstream_monomorphization(tcx).is_some() { // We can link to the item in question, no instance needed // in this crate. return false; @@ -750,34 +748,6 @@ fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx } return true; - - fn is_available_upstream_generic<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, - substs: SubstsRef<'tcx>, - ) -> bool { - debug_assert!(!def_id.is_local()); - - // If we are not in share generics mode, we don't link to upstream - // monomorphizations but always instantiate our own internal versions - // instead. - if !tcx.sess.opts.share_generics() { - return false; - } - - // If this instance has non-erasable parameters, it cannot be a shared - // monomorphization. Non-generic instances are already handled above - // by `is_reachable_non_generic()`. - if substs.non_erasable_generics().next().is_none() { - return false; - } - - // Take a look at the available monomorphizations listed in the metadata - // of upstream crates. - tcx.upstream_monomorphizations_for(def_id) - .map(|set| set.contains_key(substs)) - .unwrap_or(false) - } } /// For a given pair of source and target type that occur in an unsizing coercion,