diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs index a349b34eb1a0c..1f4318fa53751 100644 --- a/src/librustc/middle/exported_symbols.rs +++ b/src/librustc/middle/exported_symbols.rs @@ -1,10 +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::cmp; -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 @@ -24,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), } @@ -40,46 +38,12 @@ 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, } } - - pub fn compare_stable(&self, tcx: TyCtxt<'tcx>, other: &ExportedSymbol<'tcx>) -> cmp::Ordering { - match *self { - ExportedSymbol::NonGeneric(self_def_id) => match *other { - ExportedSymbol::NonGeneric(other_def_id) => { - tcx.def_path_hash(self_def_id).cmp(&tcx.def_path_hash(other_def_id)) - } - ExportedSymbol::Generic(..) | ExportedSymbol::NoDefId(_) => cmp::Ordering::Less, - }, - ExportedSymbol::Generic(self_def_id, self_substs) => match *other { - ExportedSymbol::NonGeneric(_) => cmp::Ordering::Greater, - ExportedSymbol::Generic(other_def_id, other_substs) => { - // We compare the symbol names because they are cached as query - // results which makes them relatively cheap to access repeatedly. - // - // It might be even faster to build a local cache of stable IDs - // for sorting. Exported symbols are really only sorted once - // in order to make the `exported_symbols` query result stable. - let self_symbol_name = - tcx.symbol_name(ty::Instance::new(self_def_id, self_substs)); - let other_symbol_name = - tcx.symbol_name(ty::Instance::new(other_def_id, other_substs)); - - self_symbol_name.cmp(&other_symbol_name) - } - ExportedSymbol::NoDefId(_) => cmp::Ordering::Less, - }, - ExportedSymbol::NoDefId(self_symbol_name) => match *other { - ExportedSymbol::NonGeneric(_) | ExportedSymbol::Generic(..) => { - cmp::Ordering::Greater - } - ExportedSymbol::NoDefId(ref other_symbol_name) => { - self_symbol_name.cmp(other_symbol_name) - } - }, - } - } } pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String { @@ -89,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/mir/mono.rs b/src/librustc/mir/mono.rs index 51ce575e51f3b..475c77adebd10 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -79,7 +79,7 @@ impl<'tcx> MonoItem<'tcx> { } pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode { - let inline_in_all_cgus = tcx + let generate_cgu_internal_copies = tcx .sess .opts .debugging_opts @@ -93,7 +93,7 @@ impl<'tcx> MonoItem<'tcx> { // If this function isn't inlined or otherwise has explicit // linkage, then we'll be creating a globally shared version. if self.explicit_linkage(tcx).is_some() - || !instance.def.requires_local(tcx) + || !instance.def.generates_cgu_internal_copy(tcx) || Some(instance.def_id()) == entry_def_id { return InstantiationMode::GloballyShared { may_conflict: false }; @@ -102,7 +102,7 @@ impl<'tcx> MonoItem<'tcx> { // At this point we don't have explicit linkage and we're an // inlined function. If we're inlining into all CGUs then we'll // be creating a local copy per CGU - if inline_in_all_cgus { + if generate_cgu_internal_copies { return InstantiationMode::LocalCopy; } 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 1ea695e40b255..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> { @@ -114,7 +148,12 @@ impl<'tcx> InstanceDef<'tcx> { tcx.get_attrs(self.def_id()) } - pub fn is_inline(&self, tcx: TyCtxt<'tcx>) -> bool { + /// Returns `true` if the LLVM version of this instance is unconditionally + /// marked with `inline`. This implies that a copy of this instance is + /// generated in every codegen unit. + /// Note that this is only a hint. See the documentation for + /// `generates_cgu_internal_copy` for more information. + pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool { use crate::hir::map::DefPathData; let def_id = match *self { ty::InstanceDef::Item(def_id) => def_id, @@ -127,8 +166,15 @@ impl<'tcx> InstanceDef<'tcx> { } } - pub fn requires_local(&self, tcx: TyCtxt<'tcx>) -> bool { - if self.is_inline(tcx) { + /// Returns `true` if the machine code for this instance is instantiated in + /// each codegen unit that references it. + /// Note that this is only a hint! The compiler can globally decide to *not* + /// do this in order to speed up compilation. CGU-internal copies are + /// only exist to enable inlining. If inlining is not performed (e.g. at + /// `-Copt-level=0`) then the time for generating them is wasted and it's + /// better to create a single copy with external linkage. + pub fn generates_cgu_internal_copy(&self, tcx: TyCtxt<'tcx>) -> bool { + if self.requires_inline(tcx) { return true; } if let ty::InstanceDef::DropGlue(..) = *self { 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/attributes.rs b/src/librustc_codegen_llvm/attributes.rs index 4ed4e8ac6efab..fc1b365cf90ce 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -246,7 +246,7 @@ pub fn from_fn_attrs( } // FIXME(eddyb) consolidate these two `inline` calls (and avoid overwrites). - if instance.def.is_inline(cx.tcx) { + if instance.def.requires_inline(cx.tcx) { inline(cx, llfn, attributes::InlineAttr::Hint); } 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 d680e14bbbd5b..a6cd0c09684dd 100644 --- a/src/librustc_codegen_ssa/back/symbol_export.rs +++ b/src/librustc_codegen_ssa/back/symbol_export.rs @@ -5,7 +5,7 @@ use rustc::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc::middle::exported_symbols::{metadata_symbol_name, ExportedSymbol, SymbolExportLevel}; use rustc::session::config::{self, Sanitizer}; use rustc::ty::query::Providers; -use rustc::ty::subst::SubstsRef; +use rustc::ty::subst::{GenericArgKind, SubstsRef}; use rustc::ty::Instance; use rustc::ty::{SymbolName, TyCtxt}; use rustc_codegen_utils::symbol_names; @@ -17,8 +17,6 @@ use rustc_hir::Node; use rustc_index::vec::IndexVec; use syntax::expand::allocator::ALLOCATOR_METHODS; -pub type ExportedSymbols = FxHashMap>>; - pub fn threshold(tcx: TyCtxt<'_>) -> SymbolExportLevel { crates_export_threshold(&tcx.sess.crate_types.borrow()) } @@ -96,7 +94,7 @@ fn reachable_non_generics_provider( if !generics.requires_monomorphization(tcx) && // Functions marked with #[inline] are only ever codegened // with "internal" linkage and are never exported. - !Instance::mono(tcx, def_id).def.requires_local(tcx) + !Instance::mono(tcx, def_id).def.generates_cgu_internal_copy(tcx) { Some(def_id) } else { @@ -250,19 +248,30 @@ fn exported_symbols_provider_local( continue; } - if let &MonoItem::Fn(Instance { def: InstanceDef::Item(def_id), substs }) = mono_item { - if substs.non_erasable_generics().next().is_some() { - symbols - .push((ExportedSymbol::Generic(def_id, substs), SymbolExportLevel::Rust)); + match *mono_item { + MonoItem::Fn(Instance { def: InstanceDef::Item(def_id), substs }) => { + if substs.non_erasable_generics().next().is_some() { + let symbol = ExportedSymbol::Generic(def_id, substs); + symbols.push((symbol, SymbolExportLevel::Rust)); + } + } + 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)) + ); + symbols.push((ExportedSymbol::DropGlue(ty), SymbolExportLevel::Rust)); + } + _ => { + // Any other symbols don't qualify for sharing } } } } // Sort so we get a stable incr. comp. hash. - symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| { - symbol1.compare_stable(tcx, symbol2) - }); + symbols.sort_by_cached_key(|s| s.0.symbol_name_for_local_instance(tcx)); Arc::new(symbols) } @@ -288,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); + } } } } @@ -321,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) @@ -335,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<'_>) { @@ -395,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_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index 049faff7c49ee..841827d15fef4 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -2,7 +2,8 @@ use super::command::Command; use super::link::{self, get_linker, remove}; use super::linker::LinkerInfo; use super::lto::{self, SerializedModule}; -use super::symbol_export::{symbol_name_for_instance_in_crate, ExportedSymbols}; +use super::symbol_export::symbol_name_for_instance_in_crate; + use crate::{ CachedModuleCodegen, CodegenResults, CompiledModule, CrateInfo, ModuleCodegen, ModuleKind, RLIB_BYTECODE_EXTENSION, @@ -12,6 +13,7 @@ use crate::traits::*; use jobserver::{Acquired, Client}; use rustc::dep_graph::{WorkProduct, WorkProductFileKind, WorkProductId}; use rustc::middle::cstore::EncodedMetadata; +use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::session::config::{ self, Lto, OutputFilenames, OutputType, Passes, Sanitizer, SwitchWithOptPath, }; @@ -205,6 +207,8 @@ impl Clone for TargetMachineFactory { } } +pub type ExportedSymbols = FxHashMap>>; + /// Additional resources used by optimize_and_codegen (not module specific) #[derive(Clone)] pub struct CodegenContext { 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 f4611c32e0a32..dd2071a6c596a 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -713,7 +713,8 @@ fn visit_instance_use<'tcx>( // need a mono item. fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx>) -> bool { let def_id = match instance.def { - ty::InstanceDef::Item(def_id) => def_id, + ty::InstanceDef::Item(def_id) | ty::InstanceDef::DropGlue(def_id, Some(_)) => def_id, + ty::InstanceDef::VtableShim(..) | ty::InstanceDef::ReifyShim(..) | ty::InstanceDef::ClosureOnceShim { .. } @@ -725,18 +726,18 @@ fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx }; if tcx.is_foreign_item(def_id) { - // We can always link to foreign items. + // Foreign items are always linked against, there's no way of + // instantiating them. return false; } if def_id.is_local() { - // Local items cannot be referred to locally without monomorphizing them locally. + // Local items cannot be referred to locally without + // monomorphizing them locally. 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; @@ -745,35 +746,8 @@ fn should_monomorphize_locally<'tcx>(tcx: TyCtxt<'tcx>, instance: &Instance<'tcx if !tcx.is_mir_available(def_id) { bug!("cannot create local mono-item for {:?}", def_id) } - 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) - } + return true; } /// For a given pair of source and target type that occur in an unsizing coercion, diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 0def51a6a33e5..8bcf420e2aa37 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -324,7 +324,7 @@ fn mono_item_visibility( }; let def_id = match instance.def { - InstanceDef::Item(def_id) => def_id, + InstanceDef::Item(def_id) | InstanceDef::DropGlue(def_id, Some(_)) => def_id, // These are all compiler glue and such, never exported, always hidden. InstanceDef::VtableShim(..) diff --git a/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs b/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs index 9050e8f1671d9..ffbd0dc548449 100644 --- a/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs +++ b/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs @@ -1,4 +1,6 @@ -// compile-flags:-Zshare-generics=yes +// NOTE: We always compile this test with -Copt-level=0 because higher opt-levels +// prevent drop-glue from participating in share-generics. +// compile-flags:-Zshare-generics=yes -Copt-level=0 // no-prefer-dynamic #![crate_type="rlib"] @@ -8,5 +10,17 @@ pub fn generic_fn(x: T, y: T) -> (T, T) { } pub fn use_generic_fn_f32() -> (f32, f32) { + // This line causes drop glue for Foo to be instantiated. We want to make + // sure that this crate exports an instance to be re-used by share-generics. + let _ = Foo(0); + generic_fn(0.0f32, 1.0f32) } + +pub struct Foo(pub u32); + +impl Drop for Foo { + fn drop(&mut self) { + println!("foo"); + } +} diff --git a/src/test/codegen-units/partitioning/shared-generics.rs b/src/test/codegen-units/partitioning/shared-generics.rs index 58e485be00321..47ff94437ff37 100644 --- a/src/test/codegen-units/partitioning/shared-generics.rs +++ b/src/test/codegen-units/partitioning/shared-generics.rs @@ -1,6 +1,8 @@ // ignore-tidy-linelength // no-prefer-dynamic -// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Zincremental=tmp/partitioning-tests/shared-generics-exe +// NOTE: We always compile this test with -Copt-level=0 because higher opt-levels +// prevent drop-glue from participating in share-generics. +// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Zincremental=tmp/partitioning-tests/shared-generics-exe -Copt-level=0 #![crate_type="rlib"] @@ -16,6 +18,10 @@ pub fn foo() { // This should not generate a monomorphization because it's already // available in `shared_generics_aux`. let _ = shared_generics_aux::generic_fn(0.0f32, 3.0f32); -} -// MONO_ITEM drop-glue i8 + // The following line will drop an instance of `Foo`, generating a call to + // Foo's drop-glue function. However, share-generics should take care of + // reusing the drop-glue from the upstream crate, so we do not expect a + // mono item for the drop-glue + let _ = shared_generics_aux::Foo(1); +}