diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index d1f3736556c5d..7c5318a96f5ac 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -561,6 +561,7 @@ define_dep_nodes!( <'tcx> [] ImplParent(DefId), [] TraitOfItem(DefId), [] IsReachableNonGeneric(DefId), + [] IsUnreachableLocalDefinition(DefId), [] IsMirAvailable(DefId), [] ItemAttrs(DefId), [] TransFnAttrs(DefId), @@ -648,8 +649,6 @@ define_dep_nodes!( <'tcx> [] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> }, - [] GetSymbolExportLevel(DefId), - [] WasmCustomSections(CrateNum), [input] Features, @@ -657,6 +656,9 @@ define_dep_nodes!( <'tcx> [] ProgramClausesFor(DefId), [] WasmImportModuleMap(CrateNum), [] ForeignModules(CrateNum), + + [] UpstreamMonomorphizations(CrateNum), + [] UpstreamMonomorphizationsFor(DefId), ); trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug { diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index da1a2592f14db..f86913490258e 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -53,8 +53,21 @@ for &'gcx ty::Slice } } -impl<'a, 'gcx> HashStable> -for ty::subst::Kind<'gcx> { +impl<'a, 'gcx, T> ToStableHashKey> for &'gcx ty::Slice + where T: HashStable> +{ + type KeyType = Fingerprint; + + #[inline] + fn to_stable_hash_key(&self, hcx: &StableHashingContext<'a>) -> Fingerprint { + let mut hasher = StableHasher::new(); + let mut hcx: StableHashingContext<'a> = hcx.clone(); + self.hash_stable(&mut hcx, &mut hasher); + hasher.finish() + } +} + +impl<'a, 'gcx> HashStable> for ty::subst::Kind<'gcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { @@ -67,6 +80,7 @@ for ty::subst::UnpackedKind<'gcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); match self { ty::subst::UnpackedKind::Lifetime(lt) => lt.hash_stable(hcx, hasher), ty::subst::UnpackedKind::Type(ty) => ty.hash_stable(hcx, hasher), diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs index b1418792490fc..01783eb0ff65f 100644 --- a/src/librustc/middle/exported_symbols.rs +++ b/src/librustc/middle/exported_symbols.rs @@ -9,8 +9,13 @@ // except according to those terms. use hir::def_id::{DefId, LOCAL_CRATE}; +use ich::StableHashingContext; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable, + StableHasherResult}; use std::cmp; +use std::mem; use ty; +use ty::subst::Substs; /// The SymbolExportLevel of a symbols specifies from which kinds of crates /// the symbol will be exported. `C` symbols will be exported from any @@ -40,56 +45,89 @@ impl SymbolExportLevel { } #[derive(Eq, PartialEq, Debug, Copy, Clone, RustcEncodable, RustcDecodable)] -pub enum ExportedSymbol { +pub enum ExportedSymbol<'tcx> { NonGeneric(DefId), + Generic(DefId, &'tcx Substs<'tcx>), NoDefId(ty::SymbolName), } -impl ExportedSymbol { - pub fn symbol_name(&self, tcx: ty::TyCtxt) -> ty::SymbolName { +impl<'tcx> ExportedSymbol<'tcx> { + pub fn symbol_name(&self, + tcx: ty::TyCtxt<'_, 'tcx, '_>) + -> ty::SymbolName { match *self { ExportedSymbol::NonGeneric(def_id) => { tcx.symbol_name(ty::Instance::mono(tcx, def_id)) } + ExportedSymbol::Generic(def_id, substs) => { + tcx.symbol_name(ty::Instance::new(def_id, substs)) + } ExportedSymbol::NoDefId(symbol_name) => { symbol_name } } } - pub fn compare_stable(&self, tcx: ty::TyCtxt, other: &ExportedSymbol) -> cmp::Ordering { + pub fn compare_stable(&self, + tcx: ty::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::NoDefId(_) => { - cmp::Ordering::Less - } + 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(..) => match *other { + ExportedSymbol::NonGeneric(_) => { + cmp::Ordering::Greater + } + ExportedSymbol::Generic(..) => { + self.symbol_name(tcx).cmp(&other.symbol_name(tcx)) + } + ExportedSymbol::NoDefId(_) => { + cmp::Ordering::Less } } - ExportedSymbol::NoDefId(self_symbol_name) => { - match *other { - ExportedSymbol::NonGeneric(_) => { - cmp::Ordering::Greater - } - ExportedSymbol::NoDefId(ref other_symbol_name) => { - self_symbol_name.cmp(other_symbol_name) - } + 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) } } } } } -impl_stable_hash_for!(enum self::ExportedSymbol { - NonGeneric(def_id), - NoDefId(symbol_name) -}); - pub fn metadata_symbol_name(tcx: ty::TyCtxt) -> String { format!("rust_metadata_{}_{}", tcx.original_crate_name(LOCAL_CRATE), tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex()) } + +impl<'a, 'gcx> HashStable> for ExportedSymbol<'gcx> { + 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/session/config.rs b/src/librustc/session/config.rs index 59d1a298eaa69..312df69d3188f 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -1304,6 +1304,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "embed LLVM bitcode in object files"), strip_debuginfo_if_disabled: Option = (None, parse_opt_bool, [TRACKED], "tell the linker to strip debuginfo when building without debuginfo enabled."), + share_generics: Option = (None, parse_opt_bool, [TRACKED], + "make the current crate share its generic instantiations"), } pub fn default_lib_output() -> CrateType { diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3326af21bd604..69b33efdb3542 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -14,7 +14,8 @@ use dep_graph::DepGraph; use dep_graph::{DepNode, DepConstructor}; use errors::DiagnosticBuilder; use session::Session; -use session::config::{BorrowckMode, OutputFilenames}; +use session::config::{BorrowckMode, OutputFilenames, OptLevel}; +use session::config::CrateType::*; use middle; use hir::{TraitCandidate, HirId, ItemLocalId}; use hir::def::{Def, Export}; @@ -1499,6 +1500,40 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.sess.opts.debugging_opts.mir_emit_validate > 0 || self.use_mir() } + + #[inline] + pub fn share_generics(self) -> bool { + match self.sess.opts.debugging_opts.share_generics { + Some(setting) => setting, + None => { + self.sess.opts.incremental.is_some() || + match self.sess.opts.optimize { + OptLevel::No | + OptLevel::Less | + OptLevel::Size | + OptLevel::SizeMin => true, + OptLevel::Default | + OptLevel::Aggressive => false, + } + } + } + } + + #[inline] + pub fn local_crate_exports_generics(self) -> bool { + debug_assert!(self.share_generics()); + + self.sess.crate_types.borrow().iter().any(|crate_type| { + match crate_type { + CrateTypeExecutable | + CrateTypeStaticlib | + CrateTypeProcMacro | + CrateTypeCdylib => false, + CrateTypeRlib | + CrateTypeDylib => true, + } + }) + } } impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index a08cd57b1f7e2..16866636cd90a 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -131,6 +131,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::coherent_trait<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::upstream_monomorphizations<'tcx> { + fn describe(_: TyCtxt, k: CrateNum) -> String { + format!("collecting available upstream monomorphizations `{:?}`", k) + } +} + impl<'tcx> QueryDescription<'tcx> for queries::crate_inherent_impls<'tcx> { fn describe(_: TyCtxt, k: CrateNum) -> String { format!("all inherent impls defined in crate `{:?}`", k) diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index a992b8acb8b21..5a23a3b952a42 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -319,9 +319,15 @@ define_maps! { <'tcx> // // Does not include external symbols that don't have a corresponding DefId, // like the compiler-generated `main` function and so on. - [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) -> Lrc, + [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) + -> Lrc>, [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool, + [] fn is_unreachable_local_definition: IsUnreachableLocalDefinition(DefId) -> bool, + [] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum) + -> Lrc, CrateNum>>>>, + [] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId) + -> Option, CrateNum>>>, [] fn native_libraries: NativeLibraries(CrateNum) -> Lrc>, @@ -381,11 +387,10 @@ define_maps! { <'tcx> [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc>, [] fn exported_symbols: ExportedSymbols(CrateNum) - -> Arc>, + -> Arc, SymbolExportLevel)>>, [] fn collect_and_partition_translation_items: collect_and_partition_translation_items_node(CrateNum) -> (Arc, Arc>>>), - [] fn symbol_export_level: GetSymbolExportLevel(DefId) -> SymbolExportLevel, [] fn is_translated_item: IsTranslatedItem(DefId) -> bool, [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs index bc5a14c96f004..65571aa6a692d 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/maps/plumbing.rs @@ -1003,6 +1003,9 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::ImplParent => { force!(impl_parent, def_id!()); } DepKind::TraitOfItem => { force!(trait_of_item, def_id!()); } DepKind::IsReachableNonGeneric => { force!(is_reachable_non_generic, def_id!()); } + DepKind::IsUnreachableLocalDefinition => { + force!(is_unreachable_local_definition, def_id!()); + } DepKind::IsMirAvailable => { force!(is_mir_available, def_id!()); } DepKind::ItemAttrs => { force!(item_attrs, def_id!()); } DepKind::TransFnAttrs => { force!(trans_fn_attrs, def_id!()); } @@ -1087,13 +1090,19 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); } - DepKind::GetSymbolExportLevel => { force!(symbol_export_level, def_id!()); } DepKind::Features => { force!(features_query, LOCAL_CRATE); } DepKind::ProgramClausesFor => { force!(program_clauses_for, def_id!()); } DepKind::WasmCustomSections => { force!(wasm_custom_sections, krate!()); } DepKind::WasmImportModuleMap => { force!(wasm_import_module_map, krate!()); } DepKind::ForeignModules => { force!(foreign_modules, krate!()); } + + DepKind::UpstreamMonomorphizations => { + force!(upstream_monomorphizations, krate!()); + } + DepKind::UpstreamMonomorphizationsFor => { + force!(upstream_monomorphizations_for, def_id!()); + } } true diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs index f63edf07fa8ba..51088563c7b9c 100644 --- a/src/librustc_metadata/cstore_impl.rs +++ b/src/librustc_metadata/cstore_impl.rs @@ -186,9 +186,9 @@ provide! { <'tcx> tcx, def_id, other, cdata, let reachable_non_generics = tcx .exported_symbols(cdata.cnum) .iter() - .filter_map(|&(exported_symbol, _)| { + .filter_map(|&(exported_symbol, export_level)| { if let ExportedSymbol::NonGeneric(def_id) = exported_symbol { - return Some(def_id) + return Some((def_id, export_level)) } else { None } @@ -268,7 +268,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, return Arc::new(Vec::new()) } - Arc::new(cdata.exported_symbols()) + Arc::new(cdata.exported_symbols(tcx)) } wasm_custom_sections => { Lrc::new(cdata.wasm_custom_sections()) } diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs index e938d5c1a97fe..42e208ded49fd 100644 --- a/src/librustc_metadata/decoder.rs +++ b/src/librustc_metadata/decoder.rs @@ -1065,11 +1065,13 @@ impl<'a, 'tcx> CrateMetadata { arg_names.decode(self).collect() } - pub fn exported_symbols(&self) -> Vec<(ExportedSymbol, SymbolExportLevel)> { - self.root - .exported_symbols - .decode(self) - .collect() + pub fn exported_symbols(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>) + -> Vec<(ExportedSymbol<'tcx>, SymbolExportLevel)> { + let lazy_seq: LazySeq<(ExportedSymbol<'tcx>, SymbolExportLevel)> = + LazySeq::with_position_and_length(self.root.exported_symbols.position, + self.root.exported_symbols.len); + lazy_seq.decode((self, tcx)).collect() } pub fn wasm_custom_sections(&self) -> Vec { diff --git a/src/librustc_metadata/encoder.rs b/src/librustc_metadata/encoder.rs index 0da6fc5b9eda1..1b208a512e2a4 100644 --- a/src/librustc_metadata/encoder.rs +++ b/src/librustc_metadata/encoder.rs @@ -1444,13 +1444,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { // definition (as that's not defined in this crate). fn encode_exported_symbols(&mut self, exported_symbols: &[(ExportedSymbol, SymbolExportLevel)]) - -> LazySeq<(ExportedSymbol, SymbolExportLevel)> { - + -> EncodedExportedSymbols { // The metadata symbol name is special. It should not show up in // downstream crates. let metadata_symbol_name = SymbolName::new(&metadata_symbol_name(self.tcx)); - self.lazy_seq(exported_symbols + let lazy_seq = self.lazy_seq(exported_symbols .iter() .filter(|&&(ref exported_symbol, _)| { match *exported_symbol { @@ -1460,7 +1459,12 @@ impl<'a, 'b: 'a, 'tcx: 'b> IsolatedEncoder<'a, 'b, 'tcx> { _ => true, } }) - .cloned()) + .cloned()); + + EncodedExportedSymbols { + len: lazy_seq.len, + position: lazy_seq.position, + } } fn encode_wasm_custom_sections(&mut self, statics: &[DefId]) -> LazySeq { diff --git a/src/librustc_metadata/schema.rs b/src/librustc_metadata/schema.rs index a7ee0e7e9a961..e3986bb7d91f9 100644 --- a/src/librustc_metadata/schema.rs +++ b/src/librustc_metadata/schema.rs @@ -15,7 +15,6 @@ use rustc::hir; use rustc::hir::def::{self, CtorKind}; use rustc::hir::def_id::{DefIndex, DefId, CrateNum}; use rustc::ich::StableHashingContext; -use rustc::middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}; use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary, ForeignModule}; use rustc::middle::lang_items; use rustc::mir; @@ -206,7 +205,7 @@ pub struct CrateRoot { pub codemap: LazySeq, pub def_path_table: Lazy, pub impls: LazySeq, - pub exported_symbols: LazySeq<(ExportedSymbol, SymbolExportLevel)>, + pub exported_symbols: EncodedExportedSymbols, pub wasm_custom_sections: LazySeq, pub index: LazySeq, @@ -531,3 +530,9 @@ impl_stable_hash_for!(struct GeneratorData<'tcx> { layout }); // Tags used for encoding Spans: pub const TAG_VALID_SPAN: u8 = 0; pub const TAG_INVALID_SPAN: u8 = 1; + +#[derive(RustcEncodable, RustcDecodable)] +pub struct EncodedExportedSymbols { + pub position: usize, + pub len: usize, +} diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 446ef6bd32876..ef018237dbad9 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -569,7 +569,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { ty::TyClosure(def_id, substs) => { let instance = monomorphize::resolve_closure( self.tcx, def_id, substs, ty::ClosureKind::FnOnce); - self.output.push(create_fn_mono_item(instance)); + if should_monomorphize_locally(self.tcx, &instance) { + self.output.push(create_fn_mono_item(instance)); + } } _ => bug!(), } @@ -731,14 +733,16 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: ty::InstanceDef::Intrinsic(_) | ty::InstanceDef::CloneShim(..) => return true }; - match tcx.hir.get_if_local(def_id) { + + return match tcx.hir.get_if_local(def_id) { Some(hir_map::NodeForeignItem(..)) => { false // foreign items are linked against, not translated. } Some(_) => true, None => { if tcx.is_reachable_non_generic(def_id) || - tcx.is_foreign_item(def_id) + tcx.is_foreign_item(def_id) || + is_available_upstream_generic(tcx, def_id, instance.substs) { // We can link to the item in question, no instance needed // in this crate @@ -750,6 +754,33 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: true } } + }; + + fn is_available_upstream_generic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'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.share_generics() { + return false + } + + // If this instance has no type parameters, it cannot be a shared + // monomorphization. Non-generic instances are already handled above + // by `is_reachable_non_generic()` + if substs.types().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) } } diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs index 3789342b3891d..da4cb4ec78904 100644 --- a/src/librustc_mir/monomorphize/partitioning.rs +++ b/src/librustc_mir/monomorphize/partitioning.rs @@ -302,6 +302,13 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let is_incremental_build = tcx.sess.opts.incremental.is_some(); let mut internalization_candidates = FxHashSet(); + // Determine if monomorphizations instantiated in this crate will be made + // available to downstream crates. This depends on whether we are in + // share-generics mode and whether the current crate can even have + // downstream crates. + let export_generics = tcx.share_generics() && + tcx.local_crate_exports_generics(); + for trans_item in trans_items { match trans_item.instantiation_mode(tcx) { InstantiationMode::GloballyShared { .. } => {} @@ -325,13 +332,27 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .or_insert_with(make_codegen_unit); let mut can_be_internalized = true; - let default_visibility = |id: DefId| { - if tcx.sess.target.target.options.default_hidden_visibility && - tcx.symbol_export_level(id) != SymbolExportLevel::C - { - Visibility::Hidden - } else { + let default_visibility = |id: DefId, is_generic: bool| { + if !tcx.sess.target.target.options.default_hidden_visibility { + return Visibility::Default + } + + // Generic functions never have export level C + if is_generic { + return Visibility::Hidden + } + + // Things with export level C don't get instantiated in downstream + // crates + if !id.is_local() { + return Visibility::Hidden + } + + if let Some(&SymbolExportLevel::C) = tcx.reachable_non_generics(id.krate) + .get(&id) { Visibility::Default + } else { + Visibility::Hidden } }; let (linkage, mut visibility) = match trans_item.explicit_linkage(tcx) { @@ -341,6 +362,11 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, MonoItem::Fn(ref instance) => { let visibility = match instance.def { InstanceDef::Item(def_id) => { + let is_generic = instance.substs + .types() + .next() + .is_some(); + // The `start_fn` lang item is actually a // monomorphized instance of a function in the // standard library, used for the `main` @@ -363,14 +389,46 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, can_be_internalized = false; Visibility::Hidden } else if def_id.is_local() { - if tcx.is_reachable_non_generic(def_id) { + if is_generic { + if export_generics { + if tcx.is_unreachable_local_definition(def_id) { + // This instance cannot be used + // from another crate. + Visibility::Hidden + } else { + // This instance might be useful in + // a downstream crate. + can_be_internalized = false; + default_visibility(def_id, true) + } + } else { + // We are not exporting generics or + // the definition is not reachable + // for downstream crates, we can + // internalize its instantiations. + Visibility::Hidden + } + } else { + // This isn't a generic function. + if tcx.is_reachable_non_generic(def_id) { + can_be_internalized = false; + debug_assert!(!is_generic); + default_visibility(def_id, false) + } else { + Visibility::Hidden + } + } + } else { + // This is an upstream DefId. + if export_generics && is_generic { + // If it is a upstream monomorphization + // and we export generics, we must make + // it available to downstream crates. can_be_internalized = false; - default_visibility(def_id) + default_visibility(def_id, true) } else { Visibility::Hidden } - } else { - Visibility::Hidden } } InstanceDef::FnPtrShim(..) | @@ -387,7 +445,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, MonoItem::Static(def_id) => { let visibility = if tcx.is_reachable_non_generic(def_id) { can_be_internalized = false; - default_visibility(def_id) + default_visibility(def_id, false) } else { Visibility::Hidden }; @@ -397,7 +455,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let def_id = tcx.hir.local_def_id(node_id); let visibility = if tcx.is_reachable_non_generic(def_id) { can_be_internalized = false; - default_visibility(def_id) + default_visibility(def_id, false) } else { Visibility::Hidden }; diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs index d205e6ca4eda6..acd2a7657307c 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_trans/back/symbol_export.rs @@ -14,14 +14,17 @@ use std::sync::Arc; use monomorphize::Instance; use rustc::hir; use rustc::hir::TransFnAttrFlags; -use rustc::hir::def_id::CrateNum; -use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; +use rustc::ich::Fingerprint; use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name}; use rustc::session::config; use rustc::ty::{TyCtxt, SymbolName}; use rustc::ty::maps::Providers; -use rustc::util::nodemap::{FxHashMap, DefIdSet}; +use rustc::ty::subst::Substs; +use rustc::util::nodemap::{FxHashMap, DefIdMap}; use rustc_allocator::ALLOCATOR_METHODS; +use rustc_data_structures::indexed_vec::IndexVec; +use std::collections::hash_map::Entry::*; pub type ExportedSymbols = FxHashMap< CrateNum, @@ -56,51 +59,12 @@ pub fn crates_export_threshold(crate_types: &[config::CrateType]) fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum) - -> Lrc + -> Lrc> { assert_eq!(cnum, LOCAL_CRATE); if !tcx.sess.opts.output_types.should_trans() { - return Lrc::new(DefIdSet()) - } - - let export_threshold = threshold(tcx); - - // We already collect all potentially reachable non-generic items for - // `exported_symbols`. Now we just filter them down to what is actually - // exported for the given crate we are compiling. - let reachable_non_generics = tcx - .exported_symbols(LOCAL_CRATE) - .iter() - .filter_map(|&(exported_symbol, level)| { - if let ExportedSymbol::NonGeneric(def_id) = exported_symbol { - if level.is_below_threshold(export_threshold) { - return Some(def_id) - } - } - - None - }) - .collect(); - - Lrc::new(reachable_non_generics) -} - -fn is_reachable_non_generic_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) - -> bool { - tcx.reachable_non_generics(def_id.krate).contains(&def_id) -} - -fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - cnum: CrateNum) - -> Arc> -{ - assert_eq!(cnum, LOCAL_CRATE); - - if !tcx.sess.opts.output_types.should_trans() { - return Arc::new(vec![]) + return Lrc::new(DefIdMap()) } // Check to see if this crate is a "special runtime crate". These @@ -113,7 +77,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let special_runtime_crate = tcx.is_panic_runtime(LOCAL_CRATE) || tcx.is_compiler_builtins(LOCAL_CRATE); - let reachable_non_generics: DefIdSet = tcx.reachable_set(LOCAL_CRATE).0 + let mut reachable_non_generics: DefIdMap<_> = tcx.reachable_set(LOCAL_CRATE).0 .iter() .filter_map(|&node_id| { // We want to ignore some FFI functions that are not exposed from @@ -166,11 +130,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _ => None } }) - .collect(); - - let mut symbols: Vec<_> = reachable_non_generics - .iter() - .map(|&def_id| { + .map(|def_id| { let export_level = if special_runtime_crate { let name = tcx.symbol_name(Instance::mono(tcx, def_id)); // We can probably do better here by just ensuring that @@ -188,24 +148,63 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, SymbolExportLevel::Rust } } else { - tcx.symbol_export_level(def_id) + symbol_export_level(tcx, def_id) }; debug!("EXPORTED SYMBOL (local): {} ({:?})", tcx.symbol_name(Instance::mono(tcx, def_id)), export_level); - (ExportedSymbol::NonGeneric(def_id), export_level) + (def_id, export_level) }) .collect(); if let Some(id) = tcx.sess.derive_registrar_fn.get() { let def_id = tcx.hir.local_def_id(id); - symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C)); + reachable_non_generics.insert(def_id, SymbolExportLevel::C); } if let Some(id) = tcx.sess.plugin_registrar_fn.get() { let def_id = tcx.hir.local_def_id(id); - symbols.push((ExportedSymbol::NonGeneric(def_id), SymbolExportLevel::C)); + reachable_non_generics.insert(def_id, SymbolExportLevel::C); + } + + Lrc::new(reachable_non_generics) +} + +fn is_reachable_non_generic_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> bool { + let export_threshold = threshold(tcx); + + if let Some(&level) = tcx.reachable_non_generics(def_id.krate).get(&def_id) { + level.is_below_threshold(export_threshold) + } else { + false } +} + +fn is_reachable_non_generic_provider_extern<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> bool { + tcx.reachable_non_generics(def_id.krate).contains_key(&def_id) +} + +fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum) + -> Arc, + SymbolExportLevel)>> +{ + assert_eq!(cnum, LOCAL_CRATE); + + if !tcx.sess.opts.output_types.should_trans() { + return Arc::new(vec![]) + } + + let mut symbols: Vec<_> = tcx.reachable_non_generics(LOCAL_CRATE) + .iter() + .map(|(&def_id, &level)| { + (ExportedSymbol::NonGeneric(def_id), level) + }) + .collect(); if let Some(_) = *tcx.sess.entry_fn.borrow() { let symbol_name = "main".to_string(); @@ -244,6 +243,46 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, symbols.push((exported_symbol, SymbolExportLevel::Rust)); } + if tcx.share_generics() && tcx.local_crate_exports_generics() { + use rustc::mir::mono::{Linkage, Visibility, MonoItem}; + use rustc::ty::InstanceDef; + + // Normally, we require that shared monomorphizations are not hidden, + // because if we want to re-use a monomorphization from a Rust dylib, it + // needs to be exported. + // However, on platforms that don't allow for Rust dylibs, having + // external linkage is enough for monomorphization to be linked to. + let need_visibility = tcx.sess.target.target.options.dynamic_linking && + !tcx.sess.target.target.options.only_cdylib; + + let (_, cgus) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); + + for (mono_item, &(linkage, visibility)) in cgus.iter() + .flat_map(|cgu| cgu.items().iter()) { + if linkage != Linkage::External { + // We can only re-use things with external linkage, otherwise + // we'll get a linker error + continue + } + + if need_visibility && visibility == Visibility::Hidden { + // If we potentially share things from Rust dylibs, they must + // not be hidden + continue + } + + if let &MonoItem::Fn(Instance { + def: InstanceDef::Item(def_id), + substs, + }) = mono_item { + if substs.types().next().is_some() { + symbols.push((ExportedSymbol::Generic(def_id, substs), + SymbolExportLevel::Rust)); + } + } + } + } + // Sort so we get a stable incr. comp. hash. symbols.sort_unstable_by(|&(ref symbol1, ..), &(ref symbol2, ..)| { symbol1.compare_stable(tcx, symbol2) @@ -252,19 +291,93 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, Arc::new(symbols) } +fn upstream_monomorphizations_provider<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + cnum: CrateNum) + -> Lrc, CrateNum>>>> +{ + debug_assert!(cnum == LOCAL_CRATE); + + let cnums = tcx.all_crate_nums(LOCAL_CRATE); + + let mut instances = DefIdMap(); + + let cnum_stable_ids: IndexVec = { + let mut cnum_stable_ids = IndexVec::from_elem_n(Fingerprint::ZERO, + cnums.len() + 1); + + for &cnum in cnums.iter() { + cnum_stable_ids[cnum] = tcx.def_path_hash(DefId { + krate: cnum, + index: CRATE_DEF_INDEX, + }).0; + } + + cnum_stable_ids + }; + + for &cnum in cnums.iter() { + for &(ref 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_insert_with(|| FxHashMap()); + + 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); + } + } + } + } + } + + Lrc::new(instances.into_iter() + .map(|(key, value)| (key, Lrc::new(value))) + .collect()) +} + +fn upstream_monomorphizations_for_provider<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId) + -> Option, CrateNum>>> +{ + debug_assert!(!def_id.is_local()); + tcx.upstream_monomorphizations(LOCAL_CRATE) + .get(&def_id) + .cloned() +} + +fn is_unreachable_local_definition_provider(tcx: TyCtxt, def_id: DefId) -> bool { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + !tcx.reachable_set(LOCAL_CRATE).0.contains(&node_id) + } else { + bug!("is_unreachable_local_definition called with non-local DefId: {:?}", + def_id) + } +} + pub fn provide(providers: &mut Providers) { providers.reachable_non_generics = reachable_non_generics_provider; - providers.is_reachable_non_generic = is_reachable_non_generic_provider; + providers.is_reachable_non_generic = is_reachable_non_generic_provider_local; providers.exported_symbols = exported_symbols_provider_local; - providers.symbol_export_level = symbol_export_level_provider; + providers.upstream_monomorphizations = upstream_monomorphizations_provider; + providers.is_unreachable_local_definition = is_unreachable_local_definition_provider; } pub fn provide_extern(providers: &mut Providers) { - providers.is_reachable_non_generic = is_reachable_non_generic_provider; - providers.symbol_export_level = symbol_export_level_provider; + providers.is_reachable_non_generic = is_reachable_non_generic_provider_extern; + providers.upstream_monomorphizations_for = upstream_monomorphizations_for_provider; } -fn symbol_export_level_provider(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { +fn symbol_export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { // We export anything that's not mangled at the "C" layer as it probably has // to do with ABI concerns. We do not, however, apply such treatment to // special symbols in the standard library for various plumbing between diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 1dcf349e23bd8..2c503bdab30a9 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -118,44 +118,84 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, // This is sort of subtle. Inside our codegen unit we started off // compilation by predefining all our own `TransItem` instances. That // is, everything we're translating ourselves is already defined. That - // means that anything we're actually translating ourselves will have - // hit the above branch in `get_declared_value`. As a result, we're - // guaranteed here that we're declaring a symbol that won't get defined, - // or in other words we're referencing a foreign value. + // means that anything we're actually translating in this codegen unit + // will have hit the above branch in `get_declared_value`. As a result, + // we're guaranteed here that we're declaring a symbol that won't get + // defined, or in other words we're referencing a value from another + // codegen unit or even another crate. // // So because this is a foreign value we blanket apply an external // linkage directive because it's coming from a different object file. // The visibility here is where it gets tricky. This symbol could be // referencing some foreign crate or foreign library (an `extern` // block) in which case we want to leave the default visibility. We may - // also, though, have multiple codegen units. - // - // In the situation of multiple codegen units this function may be - // referencing a function from another codegen unit. If we're - // indeed referencing a symbol in another codegen unit then we're in one - // of two cases: - // - // * This is a symbol defined in a foreign crate and we're just - // monomorphizing in another codegen unit. In this case this symbols - // is for sure not exported, so both codegen units will be using - // hidden visibility. Hence, we apply a hidden visibility here. - // - // * This is a symbol defined in our local crate. If the symbol in the - // other codegen unit is also not exported then like with the foreign - // case we apply a hidden visibility. If the symbol is exported from - // the foreign object file, however, then we leave this at the - // default visibility as we'll just import it naturally. + // also, though, have multiple codegen units. It could be a + // monomorphization, in which case its expected visibility depends on + // whether we are sharing generics or not. The important thing here is + // that the visibility we apply to the declaration is the same one that + // has been applied to the definition (wherever that definition may be). unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage); - if cx.tcx.is_translated_item(instance_def_id) { - if instance_def_id.is_local() { - if !cx.tcx.is_reachable_non_generic(instance_def_id) { - llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + let is_generic = instance.substs.types().next().is_some(); + + if is_generic { + // This is a monomorphization. Its expected visibility depends + // on whether we are in share-generics mode. + + if cx.tcx.share_generics() { + // We are in share_generics mode. + + if instance_def_id.is_local() { + // This is a definition from the current crate. If the + // definition is unreachable for downstream crates or + // the current crate does not re-export generics, the + // definition of the instance will have been declared + // as `hidden`. + if cx.tcx.is_unreachable_local_definition(instance_def_id) || + !cx.tcx.local_crate_exports_generics() { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } 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) { + // This is instantiated in another crate. It cannot + // be `hidden`. + } else { + // This is a local instantiation of an upstream definition. + // If the current crate does not re-export it + // (because it is a C library or an executable), it + // will have been declared `hidden`. + if !cx.tcx.local_crate_exports_generics() { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } } } else { + // When not sharing generics, all instances are in the same + // crate and have hidden visibility llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); } + } else { + // This is a non-generic function + if cx.tcx.is_translated_item(instance_def_id) { + // This is a function that is instantiated in the local crate + + if instance_def_id.is_local() { + // This is function that is defined in the local crate. + // If it is not reachable, it is hidden. + if !cx.tcx.is_reachable_non_generic(instance_def_id) { + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } else { + // This is a function from an upstream crate that has + // been instantiated here. These are always hidden. + llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden); + } + } } } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index e8a1eb3071a29..f8f2fdd9320d2 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -33,6 +33,7 @@ #![cfg_attr(stage0, feature(conservative_impl_trait))] #![feature(optin_builtin_traits)] #![feature(inclusive_range_fields)] +#![feature(underscore_lifetimes)] use rustc::dep_graph::WorkProduct; use syntax_pos::symbol::Symbol; diff --git a/src/librustc_trans_utils/symbol_names.rs b/src/librustc_trans_utils/symbol_names.rs index f9f93730255e6..af174f7ce8516 100644 --- a/src/librustc_trans_utils/symbol_names.rs +++ b/src/librustc_trans_utils/symbol_names.rs @@ -100,7 +100,7 @@ use rustc::middle::weak_lang_items; use rustc_mir::monomorphize::Instance; use rustc_mir::monomorphize::item::{MonoItem, MonoItemExt, InstantiationMode}; -use rustc::hir::def_id::DefId; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map as hir_map; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; use rustc::ty::fold::TypeVisitor; @@ -170,32 +170,45 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, assert!(!substs.needs_subst()); substs.visit_with(&mut hasher); - let mut avoid_cross_crate_conflicts = false; - - // If this is an instance of a generic function, we also hash in - // the ID of the instantiating crate. This avoids symbol conflicts - // in case the same instances is emitted in two crates of the same - // project. - if substs.types().next().is_some() { - avoid_cross_crate_conflicts = true; - } - - // If we're dealing with an instance of a function that's inlined from - // another crate but we're marking it as globally shared to our - // compliation (aka we're not making an internal copy in each of our - // codegen units) then this symbol may become an exported (but hidden - // visibility) symbol. This means that multiple crates may do the same - // and we want to be sure to avoid any symbol conflicts here. - match MonoItem::Fn(instance).instantiation_mode(tcx) { - InstantiationMode::GloballyShared { may_conflict: true } => { - avoid_cross_crate_conflicts = true; - } - _ => {} - } + let is_generic = substs.types().next().is_some(); + let avoid_cross_crate_conflicts = + // If this is an instance of a generic function, we also hash in + // the ID of the instantiating crate. This avoids symbol conflicts + // in case the same instances is emitted in two crates of the same + // project. + is_generic || + + // If we're dealing with an instance of a function that's inlined from + // another crate but we're marking it as globally shared to our + // compliation (aka we're not making an internal copy in each of our + // codegen units) then this symbol may become an exported (but hidden + // visibility) symbol. This means that multiple crates may do the same + // and we want to be sure to avoid any symbol conflicts here. + match MonoItem::Fn(instance).instantiation_mode(tcx) { + InstantiationMode::GloballyShared { may_conflict: true } => true, + _ => false, + }; if avoid_cross_crate_conflicts { - hasher.hash(tcx.crate_name.as_str()); - hasher.hash(tcx.sess.local_crate_disambiguator()); + let instantiating_crate = if is_generic { + if !def_id.is_local() && tcx.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(&substs) + .cloned()) + .unwrap_or(LOCAL_CRATE) + } else { + LOCAL_CRATE + } + } else { + LOCAL_CRATE + }; + + hasher.hash(&tcx.original_crate_name(instantiating_crate).as_str()[..]); + hasher.hash(&tcx.crate_disambiguator(instantiating_crate)); } }); diff --git a/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs b/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs new file mode 100644 index 0000000000000..b742da8a9001f --- /dev/null +++ b/src/test/codegen-units/partitioning/auxiliary/shared_generics_aux.rs @@ -0,0 +1,21 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags:-Zshare-generics=yes + +#![crate_type="rlib"] + +pub fn generic_fn(x: T, y: T) -> (T, T) { + (x, y) +} + +pub fn use_generic_fn_f32() -> (f32, f32) { + generic_fn(0.0f32, 1.0f32) +} diff --git a/src/test/codegen-units/partitioning/extern-generic.rs b/src/test/codegen-units/partitioning/extern-generic.rs index bdb31265e2fb2..140b43c85d548 100644 --- a/src/test/codegen-units/partitioning/extern-generic.rs +++ b/src/test/codegen-units/partitioning/extern-generic.rs @@ -11,7 +11,7 @@ // ignore-tidy-linelength // We specify -Z incremental here because we want to test the partitioning for // incremental compilation -// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/extern-generic +// compile-flags:-Zprint-trans-items=eager -Zincremental=tmp/partitioning-tests/extern-generic -Zshare-generics=y #![allow(dead_code)] #![crate_type="lib"] @@ -59,4 +59,4 @@ mod mod3 { // Make sure the two generic functions from the extern crate get instantiated // once for the current crate //~ TRANS_ITEM fn cgu_generic_function::foo[0]<&str> @@ cgu_generic_function.volatile[External] -//~ TRANS_ITEM fn cgu_generic_function::bar[0]<&str> @@ cgu_generic_function.volatile[Internal] +//~ TRANS_ITEM fn cgu_generic_function::bar[0]<&str> @@ cgu_generic_function.volatile[External] diff --git a/src/test/codegen-units/partitioning/shared-generics.rs b/src/test/codegen-units/partitioning/shared-generics.rs new file mode 100644 index 0000000000000..d352609bfcbe4 --- /dev/null +++ b/src/test/codegen-units/partitioning/shared-generics.rs @@ -0,0 +1,30 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// ignore-tidy-linelength +// compile-flags:-Zprint-trans-items=eager -Zshare-generics=yes -Zincremental=tmp/partitioning-tests/shared-generics-exe + +#![crate_type="rlib"] + +// aux-build:shared_generics_aux.rs +extern crate shared_generics_aux; + +//~ TRANS_ITEM fn shared_generics::foo[0] +pub fn foo() { + + //~ TRANS_ITEM fn shared_generics_aux::generic_fn[0] @@ shared_generics_aux.volatile[External] + let _ = shared_generics_aux::generic_fn(0u16, 1u16); + + // 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); +} + +// TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen/local-generics-in-exe-internalized.rs b/src/test/codegen/local-generics-in-exe-internalized.rs new file mode 100644 index 0000000000000..162a025c30217 --- /dev/null +++ b/src/test/codegen/local-generics-in-exe-internalized.rs @@ -0,0 +1,22 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-flags: -C no-prepopulate-passes -Zshare-generics=yes + +// Check that local generics are internalized if they are in the same CGU + +// CHECK: define internal {{.*}} @_ZN34local_generics_in_exe_internalized3foo{{.*}} +pub fn foo(x: T, y: T) -> (T, T) { + (x, y) +} + +fn main() { + let _ = foo(0u8, 1u8); +} diff --git a/src/test/run-make-fulldeps/symbol-visibility/Makefile b/src/test/run-make-fulldeps/symbol-visibility/Makefile index f1ada814bdb80..17d470063fc93 100644 --- a/src/test/run-make-fulldeps/symbol-visibility/Makefile +++ b/src/test/run-make-fulldeps/symbol-visibility/Makefile @@ -23,11 +23,11 @@ COMBINED_CDYLIB_NAME=libcombined_rlib_dylib.dylib endif all: - $(RUSTC) an_rlib.rs - $(RUSTC) a_cdylib.rs - $(RUSTC) a_rust_dylib.rs - $(RUSTC) an_executable.rs - $(RUSTC) a_cdylib.rs --crate-name combined_rlib_dylib --crate-type=rlib,cdylib + $(RUSTC) -Zshare-generics=no an_rlib.rs + $(RUSTC) -Zshare-generics=no a_cdylib.rs + $(RUSTC) -Zshare-generics=no a_rust_dylib.rs + $(RUSTC) -Zshare-generics=no an_executable.rs + $(RUSTC) -Zshare-generics=no a_cdylib.rs --crate-name combined_rlib_dylib --crate-type=rlib,cdylib # Check that a cdylib exports its public #[no_mangle] functions [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_cdylib)" -eq "1" ] @@ -39,10 +39,15 @@ all: # Check that a Rust dylib exports its monomorphic functions [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] + # Check that a Rust dylib does not export generics if -Zshare-generics=no + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "0" ] + # Check that a Rust dylib exports the monomorphic functions from its dependencies [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] + # Check that a Rust dylib does not export generics if -Zshare-generics=no + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "0" ] # Check that an executable does not export any dynamic symbols [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] @@ -57,4 +62,31 @@ all: [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] # Check that a cdylib DOES NOT export any public Rust functions [ "$$($(NM) $(TMPDIR)/$(COMBINED_CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] + + + $(RUSTC) -Zshare-generics=yes an_rlib.rs + $(RUSTC) -Zshare-generics=yes a_cdylib.rs + $(RUSTC) -Zshare-generics=yes a_rust_dylib.rs + $(RUSTC) -Zshare-generics=yes an_executable.rs + + # Check that a cdylib exports its public #[no_mangle] functions + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_cdylib)" -eq "1" ] + # Check that a cdylib exports the public #[no_mangle] functions of dependencies + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] + # Check that a cdylib DOES NOT export any public Rust functions + [ "$$($(NM) $(TMPDIR)/$(CDYLIB_NAME) | grep -c _ZN.*h.*E)" -eq "0" ] + + # Check that a Rust dylib exports its monomorphic functions, including generics this time + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rust_dylib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_rust_function_from_rust_dylib.*E)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rust_dylib.*E)" -eq "1" ] + + # Check that a Rust dylib exports the monomorphic functions from its dependencies + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_c_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c public_rust_function_from_rlib)" -eq "1" ] + [ "$$($(NM) $(TMPDIR)/$(RDYLIB_NAME) | grep -c _ZN.*public_generic_function_from_rlib.*E)" -eq "1" ] + + # Check that an executable does not export any dynamic symbols + [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_c_function_from_rlib)" -eq "0" ] + [ "$$($(NM) $(TMPDIR)/$(EXE_NAME) | grep -c public_rust_function_from_exe)" -eq "0" ] endif diff --git a/src/test/run-make-fulldeps/symbol-visibility/a_rust_dylib.rs b/src/test/run-make-fulldeps/symbol-visibility/a_rust_dylib.rs index b826211c9a42a..99e748ec2efc8 100644 --- a/src/test/run-make-fulldeps/symbol-visibility/a_rust_dylib.rs +++ b/src/test/run-make-fulldeps/symbol-visibility/a_rust_dylib.rs @@ -17,4 +17,9 @@ pub fn public_rust_function_from_rust_dylib() {} // This should be exported #[no_mangle] -pub extern "C" fn public_c_function_from_rust_dylib() {} +pub extern "C" fn public_c_function_from_rust_dylib() { + let _ = public_generic_function_from_rust_dylib(1u16); +} + +// This should be exported if -Zshare-generics=yes +pub fn public_generic_function_from_rust_dylib(x: T) -> T { x } diff --git a/src/test/run-make-fulldeps/symbol-visibility/an_rlib.rs b/src/test/run-make-fulldeps/symbol-visibility/an_rlib.rs index cd19500d14021..a1d73afd30b11 100644 --- a/src/test/run-make-fulldeps/symbol-visibility/an_rlib.rs +++ b/src/test/run-make-fulldeps/symbol-visibility/an_rlib.rs @@ -13,4 +13,10 @@ pub fn public_rust_function_from_rlib() {} #[no_mangle] -pub extern "C" fn public_c_function_from_rlib() {} +pub extern "C" fn public_c_function_from_rlib() { + let _ = public_generic_function_from_rlib(0u64); +} + +pub fn public_generic_function_from_rlib(x: T) -> T { + x +}