diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index a6581ae605b5..fcfe53d0c851 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -1591,7 +1591,11 @@ pub fn filter_reachable_ids(tcx: TyCtxt, reachable: NodeSet) -> NodeSet { node: hir::ImplItemKind::Method(..), .. }) => { let def_id = tcx.map.local_def_id(id); let generics = tcx.lookup_generics(def_id); - generics.parent_types == 0 && generics.types.is_empty() + let attributes = tcx.get_attrs(def_id); + (generics.parent_types == 0 && generics.types.is_empty()) && + // Functions marked with #[inline] are only ever translated + // with "internal" linkage and are never exported. + !attr::requests_inline(&attributes[..]) } _ => false diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 5a8ab62a2aa2..f193c0482f70 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -401,7 +401,7 @@ fn record_inlining_canditates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, callees: &[TransItem<'tcx>], inlining_map: &mut InliningMap<'tcx>) { let is_inlining_candidate = |trans_item: &TransItem<'tcx>| { - trans_item.is_from_extern_crate() || trans_item.requests_inline(tcx) + trans_item.needs_local_copy(tcx) }; let inlining_candidates = callees.into_iter() diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index a161bd199b1f..798e883c9557 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -261,12 +261,6 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, { let tcx = scx.tcx(); - if let PartitioningStrategy::FixedUnitCount(1) = strategy { - // If there is only a single codegen-unit, we can use a very simple - // scheme and don't have to bother with doing much analysis. - return vec![single_codegen_unit(tcx, trans_items, reachable)]; - } - // In the first step, we place all regular translation items into their // respective 'home' codegen unit. Regular translation items are all // functions and statics defined in the local crate. @@ -320,7 +314,7 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>, let mut codegen_units = FnvHashMap(); for trans_item in trans_items { - let is_root = !trans_item.is_instantiated_only_on_demand(); + let is_root = !trans_item.is_instantiated_only_on_demand(tcx); if is_root { let characteristic_def_id = characteristic_def_id_of_trans_item(scx, trans_item); @@ -454,7 +448,6 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit // reliably in that case. new_codegen_unit.items.insert(trans_item, llvm::InternalLinkage); } else { - assert!(trans_item.is_instantiated_only_on_demand()); // We can't be sure if this will also be instantiated // somewhere else, so we add an instance here with // InternalLinkage so we don't get any conflicts. @@ -550,68 +543,6 @@ fn compute_codegen_unit_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, return token::intern_and_get_ident(&mod_path[..]); } -fn single_codegen_unit<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trans_items: I, - reachable: &NodeSet) - -> CodegenUnit<'tcx> - where I: Iterator> -{ - let mut items = FnvHashMap(); - - for trans_item in trans_items { - let linkage = trans_item.explicit_linkage(tcx).unwrap_or_else(|| { - match trans_item { - TransItem::Static(node_id) => { - if reachable.contains(&node_id) { - llvm::ExternalLinkage - } else { - llvm::PrivateLinkage - } - } - TransItem::DropGlue(_) => { - llvm::InternalLinkage - } - TransItem::Fn(instance) => { - if trans_item.is_generic_fn() { - // FIXME(mw): Assigning internal linkage to all - // monomorphizations is potentially a waste of space - // since monomorphizations could be shared between - // crates. The main reason for making them internal is - // a limitation in MingW's binutils that cannot deal - // with COFF object that have more than 2^15 sections, - // which is something that can happen for large programs - // when every function gets put into its own COMDAT - // section. - llvm::InternalLinkage - } else if trans_item.is_from_extern_crate() { - // FIXME(mw): It would be nice if we could mark these as - // `AvailableExternallyLinkage`, since they should have - // been instantiated in the extern crate. But this - // sometimes leads to crashes on Windows because LLVM - // does not handle exception handling table instantiation - // reliably in that case. - llvm::InternalLinkage - } else if reachable.contains(&tcx.map - .as_local_node_id(instance.def) - .unwrap()) { - llvm::ExternalLinkage - } else { - // Functions that are not visible outside this crate can - // be marked as internal. - llvm::InternalLinkage - } - } - } - }); - - items.insert(trans_item, linkage); - } - - CodegenUnit::new( - numbered_codegen_unit_name(&tcx.crate_name[..], 0), - items) -} - fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString { token::intern_and_get_ident(&format!("{}{}{}", crate_name, diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs index 44e613c4c2b0..bde393b77e16 100644 --- a/src/librustc_trans/trans_item.rs +++ b/src/librustc_trans/trans_item.rs @@ -241,19 +241,6 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { - match *self { - TransItem::Fn(ref instance) => { - instance.substs.types().next().is_some() || { - let attributes = tcx.get_attrs(instance.def); - attr::requests_inline(&attributes[..]) - } - } - TransItem::DropGlue(..) => true, - TransItem::Static(..) => false, - } - } - pub fn is_from_extern_crate(&self) -> bool { match *self { TransItem::Fn(ref instance) => !instance.def.is_local(), @@ -262,10 +249,14 @@ impl<'a, 'tcx> TransItem<'tcx> { } } - pub fn is_instantiated_only_on_demand(&self) -> bool { + /// True if the translation item should only be translated to LLVM IR if + /// it is referenced somewhere (like inline functions, for example). + pub fn is_instantiated_only_on_demand(&self, tcx: TyCtxt) -> bool { match *self { TransItem::Fn(ref instance) => { - !instance.def.is_local() || instance.substs.types().next().is_some() + !instance.def.is_local() || + instance.substs.types().next().is_some() || + attr::requests_inline(&tcx.get_attrs(instance.def)[..]) } TransItem::DropGlue(..) => true, TransItem::Static(..) => false, @@ -282,6 +273,18 @@ impl<'a, 'tcx> TransItem<'tcx> { } } + /// Returns true if there has to be a local copy of this TransItem in every + /// codegen unit that references it (as with inlined functions, for example) + pub fn needs_local_copy(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + // Currently everything that is instantiated only on demand is done so + // with "internal" linkage, so we need a copy to be present in every + // codegen unit. + // This is coincidental: We could also instantiate something only if it + // is referenced (e.g. a regular, private function) but place it in its + // own codegen unit with "external" linkage. + self.is_instantiated_only_on_demand(tcx) + } + pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { let def_id = match *self { TransItem::Fn(ref instance) => instance.def,