diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs index 7665b730caddf..65c3aa12ba6c8 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_trans/base.rs @@ -59,7 +59,7 @@ use callee::{Callee, CallArgs, ArgExprs, ArgVals}; use cleanup::{self, CleanupMethods, DropHint}; use closure; use common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_uint, C_integral}; -use collector::{self, TransItem, TransItemState, TransItemCollectionMode}; +use collector::{self, TransItemState, TransItemCollectionMode}; use common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef}; use common::{CrateContext, DropFlagHintsMap, Field, FunctionContext}; use common::{Result, NodeIdAndSpan, VariantInfo}; @@ -80,8 +80,9 @@ use machine::{llalign_of_min, llsize_of, llsize_of_real}; use meth; use mir; use monomorphize::{self, Instance}; -use partitioning::{self, PartitioningStrategy, InstantiationMode, CodegenUnit}; +use partitioning::{self, PartitioningStrategy, CodegenUnit}; use symbol_names_test; +use trans_item::TransItem; use tvec; use type_::Type; use type_of; @@ -2941,8 +2942,8 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a None => TransItemCollectionMode::Lazy }; - let (items, reference_map) = time(time_passes, "translation item collection", || { - collector::collect_crate_translation_items(scx, collection_mode) + let (items, inlining_map) = time(time_passes, "translation item collection", || { + collector::collect_crate_translation_items(&scx, collection_mode) }); let strategy = if scx.sess().opts.debugging_opts.incremental.is_some() { @@ -2955,7 +2956,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a partitioning::partition(scx.tcx(), items.iter().cloned(), strategy, - &reference_map) + &inlining_map) }); if scx.sess().opts.debugging_opts.print_trans_items.is_some() { @@ -2983,18 +2984,17 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a output.push_str(&cgu_name[..]); let linkage_abbrev = match linkage { - InstantiationMode::Def(llvm::ExternalLinkage) => "External", - InstantiationMode::Def(llvm::AvailableExternallyLinkage) => "Available", - InstantiationMode::Def(llvm::LinkOnceAnyLinkage) => "OnceAny", - InstantiationMode::Def(llvm::LinkOnceODRLinkage) => "OnceODR", - InstantiationMode::Def(llvm::WeakAnyLinkage) => "WeakAny", - InstantiationMode::Def(llvm::WeakODRLinkage) => "WeakODR", - InstantiationMode::Def(llvm::AppendingLinkage) => "Appending", - InstantiationMode::Def(llvm::InternalLinkage) => "Internal", - InstantiationMode::Def(llvm::PrivateLinkage) => "Private", - InstantiationMode::Def(llvm::ExternalWeakLinkage) => "ExternalWeak", - InstantiationMode::Def(llvm::CommonLinkage) => "Common", - InstantiationMode::Decl => "Declaration", + llvm::ExternalLinkage => "External", + llvm::AvailableExternallyLinkage => "Available", + llvm::LinkOnceAnyLinkage => "OnceAny", + llvm::LinkOnceODRLinkage => "OnceODR", + llvm::WeakAnyLinkage => "WeakAny", + llvm::WeakODRLinkage => "WeakODR", + llvm::AppendingLinkage => "Appending", + llvm::InternalLinkage => "Internal", + llvm::PrivateLinkage => "Private", + llvm::ExternalWeakLinkage => "ExternalWeak", + llvm::CommonLinkage => "Common", }; output.push_str("["); diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 3fb8605412075..b56027447a094 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -494,7 +494,7 @@ fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, _ => bug!("expected fn item type, found {}", ty) }; - let instance = Instance::mono(ccx.tcx(), def_id); + let instance = Instance::mono(ccx.shared(), def_id); if let Some(&llfn) = ccx.instances().borrow().get(&instance) { return immediate_rvalue(llfn, fn_ptr_ty); } diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index dfab2bdbf644e..d278c3c8320fd 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -188,8 +188,6 @@ //! this is not implemented however: a translation item will be produced //! regardless of whether it is actually needed or not. -use rustc_data_structures::bitvec::BitVector; - use rustc::hir; use rustc::hir::intravisit as hir_visit; @@ -198,27 +196,24 @@ use rustc::hir::def_id::DefId; use rustc::middle::lang_items::{ExchangeFreeFnLangItem, ExchangeMallocFnLangItem}; use rustc::traits; use rustc::ty::subst::{self, Substs, Subst}; -use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; +use rustc::ty::{self, TypeFoldable, TyCtxt}; use rustc::ty::adjustment::CustomCoerceUnsized; use rustc::mir::repr as mir; use rustc::mir::visit as mir_visit; use rustc::mir::visit::Visitor as MirVisitor; -use syntax::ast::{self, NodeId}; +use syntax::abi::Abi; use syntax::codemap::DUMMY_SP; -use syntax::{attr, errors}; -use syntax::parse::token; - -use base::{custom_coerce_unsize_info, llvm_linkage_by_name}; +use syntax::errors; +use base::custom_coerce_unsize_info; use context::SharedCrateContext; use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized}; use glue::{self, DropGlueKind}; -use llvm; use meth; use monomorphize::{self, Instance}; use util::nodemap::{FnvHashSet, FnvHashMap, DefIdMap}; -use std::hash::{Hash, Hasher}; +use trans_item::{TransItem, type_to_string, def_id_to_string}; #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] pub enum TransItemCollectionMode { @@ -226,71 +221,35 @@ pub enum TransItemCollectionMode { Lazy } -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub enum TransItem<'tcx> { - DropGlue(DropGlueKind<'tcx>), - Fn(Instance<'tcx>), - Static(NodeId) -} - -impl<'tcx> Hash for TransItem<'tcx> { - fn hash(&self, s: &mut H) { - match *self { - TransItem::DropGlue(t) => { - 0u8.hash(s); - t.hash(s); - }, - TransItem::Fn(instance) => { - 1u8.hash(s); - instance.def.hash(s); - (instance.substs as *const _ as usize).hash(s); - } - TransItem::Static(node_id) => { - 2u8.hash(s); - node_id.hash(s); - } - }; - } -} - /// Maps every translation item to all translation items it references in its /// body. -pub struct ReferenceMap<'tcx> { - // Maps a source translation item to a range of target translation items. +pub struct InliningMap<'tcx> { + // Maps a source translation item to a range of target translation items + // that are potentially inlined by LLVM into the source. // The two numbers in the tuple are the start (inclusive) and - // end index (exclusive) within the `targets` and the `inlined` vecs. + // end index (exclusive) within the `targets` vecs. index: FnvHashMap, (usize, usize)>, targets: Vec>, - inlined: BitVector } -impl<'tcx> ReferenceMap<'tcx> { +impl<'tcx> InliningMap<'tcx> { - fn new() -> ReferenceMap<'tcx> { - ReferenceMap { + fn new() -> InliningMap<'tcx> { + InliningMap { index: FnvHashMap(), targets: Vec::new(), - inlined: BitVector::new(64 * 256), } } - fn record_references(&mut self, source: TransItem<'tcx>, targets: I) - where I: Iterator, bool)> + fn record_inlining_canditates(&mut self, + source: TransItem<'tcx>, + targets: I) + where I: Iterator> { assert!(!self.index.contains_key(&source)); let start_index = self.targets.len(); - - for (target, inlined) in targets { - let index = self.targets.len(); - self.targets.push(target); - self.inlined.grow(index + 1); - - if inlined { - self.inlined.insert(index); - } - } - + self.targets.extend(targets); let end_index = self.targets.len(); self.index.insert(source, (start_index, end_index)); } @@ -301,28 +260,17 @@ impl<'tcx> ReferenceMap<'tcx> { where F: FnMut(TransItem<'tcx>) { if let Some(&(start_index, end_index)) = self.index.get(&source) { - for index in start_index .. end_index { - if self.inlined.contains(index) { - f(self.targets[index]) - } + for candidate in &self.targets[start_index .. end_index] { + f(*candidate) } } } - - pub fn get_direct_references_from(&self, source: TransItem<'tcx>) -> &[TransItem<'tcx>] - { - if let Some(&(start_index, end_index)) = self.index.get(&source) { - &self.targets[start_index .. end_index] - } else { - &self.targets[0 .. 0] - } - } } pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, mode: TransItemCollectionMode) -> (FnvHashSet>, - ReferenceMap<'tcx>) { + InliningMap<'tcx>) { // We are not tracking dependencies of this pass as it has to be re-executed // every time no matter what. scx.tcx().dep_graph.with_ignore(|| { @@ -331,17 +279,17 @@ pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 't debug!("Building translation item graph, beginning at roots"); let mut visited = FnvHashSet(); let mut recursion_depths = DefIdMap(); - let mut reference_map = ReferenceMap::new(); + let mut inlining_map = InliningMap::new(); for root in roots { collect_items_rec(scx, root, &mut visited, &mut recursion_depths, - &mut reference_map); + &mut inlining_map); } - (visited, reference_map) + (visited, inlining_map) }) } @@ -372,7 +320,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, starting_point: TransItem<'tcx>, visited: &mut FnvHashSet>, recursion_depths: &mut DefIdMap, - reference_map: &mut ReferenceMap<'tcx>) { + inlining_map: &mut InliningMap<'tcx>) { if !visited.insert(starting_point.clone()) { // We've been here already, no need to search again. return; @@ -392,7 +340,26 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, let ty = scx.tcx().lookup_item_type(def_id).ty; let ty = glue::get_drop_glue_type(scx.tcx(), ty); neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty))); + recursion_depth_reset = None; + + // Scan the MIR in order to find function calls, closures, and + // drop-glue + let mir = errors::expect(scx.sess().diagnostic(), scx.get_mir(def_id), + || format!("Could not find MIR for static: {:?}", def_id)); + + let empty_substs = scx.empty_substs_for_def_id(def_id); + let mut visitor = MirNeighborCollector { + scx: scx, + mir: &mir, + output: &mut neighbors, + param_substs: empty_substs + }; + + visitor.visit_mir(&mir); + for promoted in &mir.promoted { + visitor.visit_mir(promoted); + } } TransItem::Fn(instance) => { // Keep track of the monomorphization recursion depth @@ -419,10 +386,10 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, } } - record_references(scx.tcx(), starting_point, &neighbors[..], reference_map); + record_inlining_canditates(scx.tcx(), starting_point, &neighbors[..], inlining_map); for neighbour in neighbors { - collect_items_rec(scx, neighbour, visited, recursion_depths, reference_map); + collect_items_rec(scx, neighbour, visited, recursion_depths, inlining_map); } if let Some((def_id, depth)) = recursion_depth_reset { @@ -432,17 +399,19 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>, debug!("END collect_items_rec({})", starting_point.to_string(scx.tcx())); } -fn record_references<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - caller: TransItem<'tcx>, - callees: &[TransItem<'tcx>], - reference_map: &mut ReferenceMap<'tcx>) { - let iter = callees.into_iter() - .map(|callee| { - let is_inlining_candidate = callee.is_from_extern_crate() || - callee.requests_inline(tcx); - (*callee, is_inlining_candidate) - }); - reference_map.record_references(caller, iter); +fn record_inlining_canditates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + caller: TransItem<'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) + }; + + let inlining_candidates = callees.into_iter() + .map(|x| *x) + .filter(is_inlining_candidate); + + inlining_map.record_inlining_canditates(caller, inlining_candidates); } fn check_recursion_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -527,10 +496,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { .unwrap_or_else(|e| self.scx.sess().fatal(&e)); assert!(can_have_local_instance(self.scx.tcx(), exchange_malloc_fn_def_id)); + let empty_substs = self.scx.empty_substs_for_def_id(exchange_malloc_fn_def_id); let exchange_malloc_fn_trans_item = create_fn_trans_item(self.scx.tcx(), exchange_malloc_fn_def_id, - self.scx.tcx().mk_substs(Substs::empty()), + empty_substs, self.param_substs); self.output.push(exchange_malloc_fn_trans_item); @@ -633,6 +603,49 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { can_have_local_instance(tcx, def_id) } } + + // This takes care of the "drop_in_place" intrinsic for which we otherwise + // we would not register drop-glues. + fn visit_terminator_kind(&mut self, + block: mir::BasicBlock, + kind: &mir::TerminatorKind<'tcx>) { + let tcx = self.scx.tcx(); + match *kind { + mir::TerminatorKind::Call { + func: mir::Operand::Constant(ref constant), + ref args, + .. + } => { + match constant.ty.sty { + ty::TyFnDef(def_id, _, bare_fn_ty) + if is_drop_in_place_intrinsic(tcx, def_id, bare_fn_ty) => { + let operand_ty = self.mir.operand_ty(tcx, &args[0]); + if let ty::TyRawPtr(mt) = operand_ty.sty { + let operand_ty = monomorphize::apply_param_substs(tcx, + self.param_substs, + &mt.ty); + self.output.push(TransItem::DropGlue(DropGlueKind::Ty(operand_ty))); + } else { + bug!("Has the drop_in_place() intrinsic's signature changed?") + } + } + _ => { /* Nothing to do. */ } + } + } + _ => { /* Nothing to do. */ } + } + + self.super_terminator_kind(block, kind); + + fn is_drop_in_place_intrinsic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + def_id: DefId, + bare_fn_ty: &ty::BareFnTy<'tcx>) + -> bool { + (bare_fn_ty.abi == Abi::RustIntrinsic || + bare_fn_ty.abi == Abi::PlatformIntrinsic) && + tcx.item_name(def_id).as_str() == "drop_in_place" + } + } } fn can_have_local_instance<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -667,10 +680,11 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, .unwrap_or_else(|e| scx.sess().fatal(&e)); assert!(can_have_local_instance(scx.tcx(), exchange_free_fn_def_id)); + let fn_substs = scx.empty_substs_for_def_id(exchange_free_fn_def_id); let exchange_free_fn_trans_item = create_fn_trans_item(scx.tcx(), exchange_free_fn_def_id, - scx.tcx().mk_substs(Substs::empty()), + fn_substs, scx.tcx().mk_substs(Substs::empty())); output.push(exchange_free_fn_trans_item); @@ -730,7 +744,6 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, ty::TyRef(..) | ty::TyFnDef(..) | ty::TyFnPtr(_) | - ty::TySlice(_) | ty::TyTrait(_) => { /* nothing to do */ } @@ -756,6 +769,7 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } } ty::TyBox(inner_type) | + ty::TySlice(inner_type) | ty::TyArray(inner_type, _) => { let inner_type = glue::get_drop_glue_type(scx.tcx(), inner_type); if glue::type_needs_drop(scx.tcx(), inner_type) { @@ -777,6 +791,8 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, bug!("encountered unexpected type"); } } + + } fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, @@ -1097,7 +1113,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { debug!("RootCollector: ItemFn({})", def_id_to_string(self.scx.tcx(), def_id)); - let instance = Instance::mono(self.scx.tcx(), def_id); + let instance = Instance::mono(self.scx, def_id); self.output.push(TransItem::Fn(instance)); } } @@ -1134,7 +1150,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> { debug!("RootCollector: MethodImplItem({})", def_id_to_string(self.scx.tcx(), def_id)); - let instance = Instance::mono(self.scx.tcx(), def_id); + let instance = Instance::mono(self.scx, def_id); self.output.push(TransItem::Fn(instance)); } } @@ -1210,334 +1226,6 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -//=----------------------------------------------------------------------------- -// TransItem String Keys -//=----------------------------------------------------------------------------- - -// The code below allows for producing a unique string key for a trans item. -// These keys are used by the handwritten auto-tests, so they need to be -// predictable and human-readable. -// -// Note: A lot of this could looks very similar to what's already in the -// ppaux module. It would be good to refactor things so we only have one -// parameterizable implementation for printing types. - -/// Same as `unique_type_name()` but with the result pushed onto the given -/// `output` parameter. -pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - t: ty::Ty<'tcx>, - output: &mut String) { - match t.sty { - ty::TyBool => output.push_str("bool"), - ty::TyChar => output.push_str("char"), - ty::TyStr => output.push_str("str"), - ty::TyInt(ast::IntTy::Is) => output.push_str("isize"), - ty::TyInt(ast::IntTy::I8) => output.push_str("i8"), - ty::TyInt(ast::IntTy::I16) => output.push_str("i16"), - ty::TyInt(ast::IntTy::I32) => output.push_str("i32"), - ty::TyInt(ast::IntTy::I64) => output.push_str("i64"), - ty::TyUint(ast::UintTy::Us) => output.push_str("usize"), - ty::TyUint(ast::UintTy::U8) => output.push_str("u8"), - ty::TyUint(ast::UintTy::U16) => output.push_str("u16"), - ty::TyUint(ast::UintTy::U32) => output.push_str("u32"), - ty::TyUint(ast::UintTy::U64) => output.push_str("u64"), - ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), - ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), - ty::TyStruct(adt_def, substs) | - ty::TyEnum(adt_def, substs) => { - push_item_name(tcx, adt_def.did, output); - push_type_params(tcx, &substs.types, &[], output); - }, - ty::TyTuple(component_types) => { - output.push('('); - for &component_type in component_types { - push_unique_type_name(tcx, component_type, output); - output.push_str(", "); - } - if !component_types.is_empty() { - output.pop(); - output.pop(); - } - output.push(')'); - }, - ty::TyBox(inner_type) => { - output.push_str("Box<"); - push_unique_type_name(tcx, inner_type, output); - output.push('>'); - }, - ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { - output.push('*'); - match mutbl { - hir::MutImmutable => output.push_str("const "), - hir::MutMutable => output.push_str("mut "), - } - - push_unique_type_name(tcx, inner_type, output); - }, - ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => { - output.push('&'); - if mutbl == hir::MutMutable { - output.push_str("mut "); - } - - push_unique_type_name(tcx, inner_type, output); - }, - ty::TyArray(inner_type, len) => { - output.push('['); - push_unique_type_name(tcx, inner_type, output); - output.push_str(&format!("; {}", len)); - output.push(']'); - }, - ty::TySlice(inner_type) => { - output.push('['); - push_unique_type_name(tcx, inner_type, output); - output.push(']'); - }, - ty::TyTrait(ref trait_data) => { - push_item_name(tcx, trait_data.principal.skip_binder().def_id, output); - push_type_params(tcx, - &trait_data.principal.skip_binder().substs.types, - &trait_data.bounds.projection_bounds, - output); - }, - ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) | - ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { - if unsafety == hir::Unsafety::Unsafe { - output.push_str("unsafe "); - } - - if abi != ::abi::Abi::Rust { - output.push_str("extern \""); - output.push_str(abi.name()); - output.push_str("\" "); - } - - output.push_str("fn("); - - let sig = tcx.erase_late_bound_regions(sig); - if !sig.inputs.is_empty() { - for ¶meter_type in &sig.inputs { - push_unique_type_name(tcx, parameter_type, output); - output.push_str(", "); - } - output.pop(); - output.pop(); - } - - if sig.variadic { - if !sig.inputs.is_empty() { - output.push_str(", ..."); - } else { - output.push_str("..."); - } - } - - output.push(')'); - - match sig.output { - ty::FnConverging(result_type) if result_type.is_nil() => {} - ty::FnConverging(result_type) => { - output.push_str(" -> "); - push_unique_type_name(tcx, result_type, output); - } - ty::FnDiverging => { - output.push_str(" -> !"); - } - } - }, - ty::TyClosure(def_id, ref closure_substs) => { - push_item_name(tcx, def_id, output); - output.push_str("{"); - output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize())); - output.push_str("}"); - push_type_params(tcx, &closure_substs.func_substs.types, &[], output); - } - ty::TyError | - ty::TyInfer(_) | - ty::TyProjection(..) | - ty::TyParam(_) => { - bug!("debuginfo: Trying to create type name for \ - unexpected type: {:?}", t); - } - } -} - -fn push_item_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - output: &mut String) { - let def_path = tcx.def_path(def_id); - - // some_crate:: - output.push_str(&tcx.crate_name(def_path.krate)); - output.push_str("::"); - - // foo::bar::ItemName:: - for part in tcx.def_path(def_id).data { - output.push_str(&format!("{}[{}]::", - part.data.as_interned_str(), - part.disambiguator)); - } - - // remove final "::" - output.pop(); - output.pop(); -} - -fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - types: &'tcx subst::VecPerParamSpace>, - projections: &[ty::PolyProjectionPredicate<'tcx>], - output: &mut String) { - if types.is_empty() && projections.is_empty() { - return; - } - - output.push('<'); - - for &type_parameter in types { - push_unique_type_name(tcx, type_parameter, output); - output.push_str(", "); - } - - for projection in projections { - let projection = projection.skip_binder(); - let name = token::get_ident_interner().get(projection.projection_ty.item_name); - output.push_str(&name[..]); - output.push_str("="); - push_unique_type_name(tcx, projection.ty, output); - output.push_str(", "); - } - - output.pop(); - output.pop(); - - output.push('>'); -} - -fn push_instance_as_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, - output: &mut String) { - push_item_name(tcx, instance.def, output); - push_type_params(tcx, &instance.substs.types, &[], output); -} - -pub fn def_id_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId) -> String { - let mut output = String::new(); - push_item_name(tcx, def_id, &mut output); - output -} - -fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: ty::Ty<'tcx>) - -> String { - let mut output = String::new(); - push_unique_type_name(tcx, ty, &mut output); - output -} - -impl<'a, 'tcx> TransItem<'tcx> { - pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { - match *self { - TransItem::Fn(ref instance) => { - 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(), - TransItem::DropGlue(..) | - TransItem::Static(..) => false, - } - } - - pub fn is_lazily_instantiated(&self) -> bool { - match *self { - TransItem::Fn(ref instance) => !instance.substs.types.is_empty(), - TransItem::DropGlue(..) => true, - TransItem::Static(..) => false, - } - } - - pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { - let def_id = match *self { - TransItem::Fn(ref instance) => instance.def, - TransItem::Static(node_id) => tcx.map.local_def_id(node_id), - TransItem::DropGlue(..) => return None, - }; - - let attributes = tcx.get_attrs(def_id); - if let Some(name) = attr::first_attr_value_str_by_name(&attributes, "linkage") { - if let Some(linkage) = llvm_linkage_by_name(&name) { - Some(linkage) - } else { - let span = tcx.map.span_if_local(def_id); - if let Some(span) = span { - tcx.sess.span_fatal(span, "invalid linkage specified") - } else { - tcx.sess.fatal(&format!("invalid linkage specified: {}", name)) - } - } - } else { - None - } - } - - pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { - let hir_map = &tcx.map; - - return match *self { - TransItem::DropGlue(dg) => { - let mut s = String::with_capacity(32); - match dg { - DropGlueKind::Ty(_) => s.push_str("drop-glue "), - DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "), - }; - push_unique_type_name(tcx, dg.ty(), &mut s); - s - } - TransItem::Fn(instance) => { - to_string_internal(tcx, "fn ", instance) - }, - TransItem::Static(node_id) => { - let def_id = hir_map.local_def_id(node_id); - let instance = Instance::mono(tcx, def_id); - to_string_internal(tcx, "static ", instance) - }, - }; - - fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - prefix: &str, - instance: Instance<'tcx>) - -> String { - let mut result = String::with_capacity(32); - result.push_str(prefix); - push_instance_as_string(tcx, instance, &mut result); - result - } - } - - fn to_raw_string(&self) -> String { - match *self { - TransItem::DropGlue(dg) => { - format!("DropGlue({})", dg.ty() as *const _ as usize) - } - TransItem::Fn(instance) => { - format!("Fn({:?}, {})", - instance.def, - instance.substs as *const _ as usize) - } - TransItem::Static(id) => { - format!("Static({:?})", id) - } - } - } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum TransItemState { PredictedAndGenerated, @@ -1546,7 +1234,7 @@ pub enum TransItemState { } pub fn collecting_debug_information(scx: &SharedCrateContext) -> bool { - return cfg!(debug_assertions) && + return scx.sess().opts.cg.debug_assertions == Some(true) && scx.sess().opts.debugging_opts.print_trans_items.is_some(); } diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs index 7775ed3fc68ae..3e876eb3d7de0 100644 --- a/src/librustc_trans/consts.rs +++ b/src/librustc_trans/consts.rs @@ -21,7 +21,8 @@ use rustc::hir::map as hir_map; use {abi, adt, closure, debuginfo, expr, machine}; use base::{self, exported_name, imported_name, push_ctxt}; use callee::Callee; -use collector::{self, TransItem}; +use collector; +use trans_item::TransItem; use common::{type_is_sized, C_nil, const_get_elt}; use common::{CrateContext, C_integral, C_floating, C_bool, C_str_slice, C_bytes, val_ty}; use common::{C_struct, C_undef, const_to_opt_int, const_to_opt_uint, VariantInfo, C_uint}; @@ -1011,7 +1012,7 @@ pub fn get_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, def_id: DefId) -> Datum<'tcx, Lvalue> { let ty = ccx.tcx().lookup_item_type(def_id).ty; - let instance = Instance::mono(ccx.tcx(), def_id); + let instance = Instance::mono(ccx.shared(), def_id); if let Some(&g) = ccx.instances().borrow().get(&instance) { return Datum::new(g, ty, Lvalue::new("static")); } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index 61137d7f377c2..60c6af84ebbb6 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -27,8 +27,9 @@ use glue::DropGlueKind; use mir::CachedMir; use monomorphize::Instance; -use collector::{TransItem, TransItemState}; use partitioning::CodegenUnit; +use collector::TransItemState; +use trans_item::TransItem; use type_::{Type, TypeNames}; use rustc::ty::subst::{Substs, VecPerParamSpace}; use rustc::ty::{self, Ty, TyCtxt}; @@ -487,6 +488,21 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn translation_items(&self) -> &RefCell, TransItemState>> { &self.translation_items } + + /// Given the def-id of some item that has no type parameters, make + /// a suitable "empty substs" for it. + pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> { + let scheme = self.tcx().lookup_item_type(item_def_id); + self.empty_substs_for_scheme(&scheme) + } + + pub fn empty_substs_for_scheme(&self, scheme: &ty::TypeScheme<'tcx>) + -> &'tcx Substs<'tcx> { + assert!(scheme.generics.types.is_empty()); + self.tcx().mk_substs( + Substs::new(VecPerParamSpace::empty(), + scheme.generics.regions.map(|_| ty::ReStatic))) + } } impl<'tcx> LocalCrateContext<'tcx> { @@ -901,16 +917,12 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { /// Given the def-id of some item that has no type parameters, make /// a suitable "empty substs" for it. pub fn empty_substs_for_def_id(&self, item_def_id: DefId) -> &'tcx Substs<'tcx> { - let scheme = self.tcx().lookup_item_type(item_def_id); - self.empty_substs_for_scheme(&scheme) + self.shared().empty_substs_for_def_id(item_def_id) } pub fn empty_substs_for_scheme(&self, scheme: &ty::TypeScheme<'tcx>) -> &'tcx Substs<'tcx> { - assert!(scheme.generics.types.is_empty()); - self.tcx().mk_substs( - Substs::new(VecPerParamSpace::empty(), - scheme.generics.regions.map(|_| ty::ReStatic))) + self.shared().empty_substs_for_scheme(scheme) } } diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs index a29ff95851d76..10e33195305f6 100644 --- a/src/librustc_trans/glue.rs +++ b/src/librustc_trans/glue.rs @@ -29,13 +29,14 @@ use build::*; use callee::{Callee, ArgVals}; use cleanup; use cleanup::CleanupMethods; -use collector::{self, TransItem}; +use collector; use common::*; use debuginfo::DebugLoc; use declare; use expr; use machine::*; use monomorphize; +use trans_item::TransItem; use type_of::{type_of, sizing_type_of, align_of}; use type_::Type; use value::Value; diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index f48409ec75573..bccb5aa050b51 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -123,6 +123,7 @@ mod mir; mod monomorphize; mod partitioning; mod symbol_names_test; +mod trans_item; mod tvec; mod type_; mod type_of; diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs index 039304ece60b0..0403c7b1f757b 100644 --- a/src/librustc_trans/mir/constant.rs +++ b/src/librustc_trans/mir/constant.rs @@ -854,6 +854,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId) -> Result { - let instance = Instance::mono(ccx.tcx(), def_id); + let instance = Instance::mono(ccx.shared(), def_id); MirConstContext::trans_def(ccx, instance, vec![]).map(|c| c.llval) } diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index 8b1809e40233a..dfaf84ecef023 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -183,8 +183,8 @@ impl<'tcx> Instance<'tcx> { assert!(substs.regions.iter().all(|&r| r == ty::ReStatic)); Instance { def: def_id, substs: substs } } - pub fn mono<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Instance<'tcx> { - Instance::new(def_id, tcx.mk_substs(Substs::empty())) + pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> { + Instance::new(def_id, scx.empty_substs_for_def_id(def_id)) } } diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs index 18a860f9357b9..098ba759247be 100644 --- a/src/librustc_trans/partitioning.rs +++ b/src/librustc_trans/partitioning.rs @@ -116,30 +116,20 @@ //! source-level module, functions from the same module will be available for //! inlining, even when they are not marked #[inline]. -use collector::{TransItem, ReferenceMap}; +use collector::InliningMap; +use llvm; use monomorphize; use rustc::hir::def_id::DefId; use rustc::hir::map::DefPathData; use rustc::ty::TyCtxt; use rustc::ty::item_path::characteristic_def_id_of_type; -use llvm; use syntax::parse::token::{self, InternedString}; +use trans_item::TransItem; use util::nodemap::{FnvHashMap, FnvHashSet}; -#[derive(Clone, Copy, Eq, PartialEq, Debug)] -pub enum InstantiationMode { - /// This variant indicates that a translation item should be placed in some - /// codegen unit as a definition and with the given linkage. - Def(llvm::Linkage), - - /// This variant indicates that only a declaration of some translation item - /// should be placed in a given codegen unit. - Decl -} - pub struct CodegenUnit<'tcx> { pub name: InternedString, - pub items: FnvHashMap, InstantiationMode>, + pub items: FnvHashMap, llvm::Linkage>, } pub enum PartitioningStrategy { @@ -156,7 +146,7 @@ const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit"; pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I, strategy: PartitioningStrategy, - reference_map: &ReferenceMap<'tcx>) + inlining_map: &InliningMap<'tcx>) -> Vec> where I: Iterator> { @@ -176,13 +166,8 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // translation items can be drop-glue, functions from external crates, and // local functions the definition of which is marked with #[inline]. let post_inlining = place_inlined_translation_items(initial_partitioning, - reference_map); - - // Now we know all *definitions* within all codegen units, thus we can - // easily determine which declarations need to be placed within each one. - let post_declarations = place_declarations(post_inlining, reference_map); - - post_declarations.0 + inlining_map); + post_inlining.0 } struct PreInliningPartitioning<'tcx> { @@ -191,7 +176,6 @@ struct PreInliningPartitioning<'tcx> { } struct PostInliningPartitioning<'tcx>(Vec>); -struct PostDeclarationsPartitioning<'tcx>(Vec>); fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_items: I) @@ -239,8 +223,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } }; - codegen_unit.items.insert(trans_item, - InstantiationMode::Def(linkage)); + codegen_unit.items.insert(trans_item, linkage); roots.insert(trans_item); } } @@ -294,7 +277,7 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning< } fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartitioning<'tcx>, - reference_map: &ReferenceMap<'tcx>) + inlining_map: &InliningMap<'tcx>) -> PostInliningPartitioning<'tcx> { let mut new_partitioning = Vec::new(); @@ -302,7 +285,7 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit // Collect all items that need to be available in this codegen unit let mut reachable = FnvHashSet(); for root in codegen_unit.items.keys() { - follow_inlining(*root, reference_map, &mut reachable); + follow_inlining(*root, inlining_map, &mut reachable); } let mut new_codegen_unit = CodegenUnit { @@ -312,22 +295,22 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit // Add all translation items that are not already there for trans_item in reachable { - if let Some(instantiation_mode) = codegen_unit.items.get(&trans_item) { + if let Some(linkage) = codegen_unit.items.get(&trans_item) { // This is a root, just copy it over - new_codegen_unit.items.insert(trans_item, *instantiation_mode); + new_codegen_unit.items.insert(trans_item, *linkage); } else { if initial_partitioning.roots.contains(&trans_item) { // This item will be instantiated in some other codegen unit, // so we just add it here with AvailableExternallyLinkage new_codegen_unit.items.insert(trans_item, - InstantiationMode::Def(llvm::AvailableExternallyLinkage)); + llvm::AvailableExternallyLinkage); } else { // We can't be sure if this will also be instantiated // somewhere else, so we add an instance here with // LinkOnceODRLinkage. That way the item can be discarded if // it's not needed (inlined) after all. new_codegen_unit.items.insert(trans_item, - InstantiationMode::Def(llvm::LinkOnceODRLinkage)); + llvm::LinkOnceODRLinkage); } } } @@ -338,43 +321,18 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit return PostInliningPartitioning(new_partitioning); fn follow_inlining<'tcx>(trans_item: TransItem<'tcx>, - reference_map: &ReferenceMap<'tcx>, + inlining_map: &InliningMap<'tcx>, visited: &mut FnvHashSet>) { if !visited.insert(trans_item) { return; } - reference_map.with_inlining_candidates(trans_item, |target| { - follow_inlining(target, reference_map, visited); + inlining_map.with_inlining_candidates(trans_item, |target| { + follow_inlining(target, inlining_map, visited); }); } } -fn place_declarations<'tcx>(codegen_units: PostInliningPartitioning<'tcx>, - reference_map: &ReferenceMap<'tcx>) - -> PostDeclarationsPartitioning<'tcx> { - let PostInliningPartitioning(mut codegen_units) = codegen_units; - - for codegen_unit in codegen_units.iter_mut() { - let mut declarations = FnvHashSet(); - - for (trans_item, _) in &codegen_unit.items { - for referenced_item in reference_map.get_direct_references_from(*trans_item) { - if !codegen_unit.items.contains_key(referenced_item) { - declarations.insert(*referenced_item); - } - } - } - - codegen_unit.items - .extend(declarations.iter() - .map(|trans_item| (*trans_item, - InstantiationMode::Decl))); - } - - PostDeclarationsPartitioning(codegen_units) -} - fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_item: TransItem<'tcx>) -> Option { diff --git a/src/librustc_trans/symbol_names_test.rs b/src/librustc_trans/symbol_names_test.rs index 2e3355968dffa..284a227276dd0 100644 --- a/src/librustc_trans/symbol_names_test.rs +++ b/src/librustc_trans/symbol_names_test.rs @@ -52,7 +52,7 @@ impl<'a, 'tcx> SymbolNamesTest<'a, 'tcx> { for attr in tcx.get_attrs(def_id).iter() { if attr.check_name(SYMBOL_NAME) { // for now, can only use on monomorphic names - let instance = Instance::mono(tcx, def_id); + let instance = Instance::mono(self.ccx.shared(), def_id); let name = symbol_names::exported_name(self.ccx, &instance); tcx.sess.span_err(attr.span, &format!("symbol-name({})", name)); } else if attr.check_name(ITEM_PATH) { diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs new file mode 100644 index 0000000000000..d7c5c41a156ba --- /dev/null +++ b/src/librustc_trans/trans_item.rs @@ -0,0 +1,384 @@ +// Copyright 2016 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. + +//! Walks the crate looking for items/impl-items/trait-items that have +//! either a `rustc_symbol_name` or `rustc_item_path` attribute and +//! generates an error giving, respectively, the symbol name or +//! item-path. This is used for unit testing the code that generates +//! paths etc in all kinds of annoying scenarios. + +use base::llvm_linkage_by_name; +use glue::DropGlueKind; +use llvm; +use monomorphize::Instance; +use rustc::hir; +use rustc::hir::def_id::DefId; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst; +use std::hash::{Hash, Hasher}; +use syntax::ast::{self, NodeId}; +use syntax::attr; +use syntax::parse::token; + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum TransItem<'tcx> { + DropGlue(DropGlueKind<'tcx>), + Fn(Instance<'tcx>), + Static(NodeId) +} + +impl<'tcx> Hash for TransItem<'tcx> { + fn hash(&self, s: &mut H) { + match *self { + TransItem::DropGlue(t) => { + 0u8.hash(s); + t.hash(s); + }, + TransItem::Fn(instance) => { + 1u8.hash(s); + instance.def.hash(s); + (instance.substs as *const _ as usize).hash(s); + } + TransItem::Static(node_id) => { + 2u8.hash(s); + node_id.hash(s); + } + }; + } +} + +//=----------------------------------------------------------------------------- +// TransItem String Keys +//=----------------------------------------------------------------------------- + +// The code below allows for producing a unique string key for a trans item. +// These keys are used by the handwritten auto-tests, so they need to be +// predictable and human-readable. +// +// Note: A lot of this could looks very similar to what's already in the +// ppaux module. It would be good to refactor things so we only have one +// parameterizable implementation for printing types. + +/// Same as `unique_type_name()` but with the result pushed onto the given +/// `output` parameter. +pub fn push_unique_type_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + t: ty::Ty<'tcx>, + output: &mut String) { + match t.sty { + ty::TyBool => output.push_str("bool"), + ty::TyChar => output.push_str("char"), + ty::TyStr => output.push_str("str"), + ty::TyInt(ast::IntTy::Is) => output.push_str("isize"), + ty::TyInt(ast::IntTy::I8) => output.push_str("i8"), + ty::TyInt(ast::IntTy::I16) => output.push_str("i16"), + ty::TyInt(ast::IntTy::I32) => output.push_str("i32"), + ty::TyInt(ast::IntTy::I64) => output.push_str("i64"), + ty::TyUint(ast::UintTy::Us) => output.push_str("usize"), + ty::TyUint(ast::UintTy::U8) => output.push_str("u8"), + ty::TyUint(ast::UintTy::U16) => output.push_str("u16"), + ty::TyUint(ast::UintTy::U32) => output.push_str("u32"), + ty::TyUint(ast::UintTy::U64) => output.push_str("u64"), + ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"), + ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"), + ty::TyStruct(adt_def, substs) | + ty::TyEnum(adt_def, substs) => { + push_item_name(tcx, adt_def.did, output); + push_type_params(tcx, &substs.types, &[], output); + }, + ty::TyTuple(component_types) => { + output.push('('); + for &component_type in component_types { + push_unique_type_name(tcx, component_type, output); + output.push_str(", "); + } + if !component_types.is_empty() { + output.pop(); + output.pop(); + } + output.push(')'); + }, + ty::TyBox(inner_type) => { + output.push_str("Box<"); + push_unique_type_name(tcx, inner_type, output); + output.push('>'); + }, + ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => { + output.push('*'); + match mutbl { + hir::MutImmutable => output.push_str("const "), + hir::MutMutable => output.push_str("mut "), + } + + push_unique_type_name(tcx, inner_type, output); + }, + ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => { + output.push('&'); + if mutbl == hir::MutMutable { + output.push_str("mut "); + } + + push_unique_type_name(tcx, inner_type, output); + }, + ty::TyArray(inner_type, len) => { + output.push('['); + push_unique_type_name(tcx, inner_type, output); + output.push_str(&format!("; {}", len)); + output.push(']'); + }, + ty::TySlice(inner_type) => { + output.push('['); + push_unique_type_name(tcx, inner_type, output); + output.push(']'); + }, + ty::TyTrait(ref trait_data) => { + push_item_name(tcx, trait_data.principal.skip_binder().def_id, output); + push_type_params(tcx, + &trait_data.principal.skip_binder().substs.types, + &trait_data.bounds.projection_bounds, + output); + }, + ty::TyFnDef(_, _, &ty::BareFnTy{ unsafety, abi, ref sig } ) | + ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => { + if unsafety == hir::Unsafety::Unsafe { + output.push_str("unsafe "); + } + + if abi != ::abi::Abi::Rust { + output.push_str("extern \""); + output.push_str(abi.name()); + output.push_str("\" "); + } + + output.push_str("fn("); + + let sig = tcx.erase_late_bound_regions(sig); + if !sig.inputs.is_empty() { + for ¶meter_type in &sig.inputs { + push_unique_type_name(tcx, parameter_type, output); + output.push_str(", "); + } + output.pop(); + output.pop(); + } + + if sig.variadic { + if !sig.inputs.is_empty() { + output.push_str(", ..."); + } else { + output.push_str("..."); + } + } + + output.push(')'); + + match sig.output { + ty::FnConverging(result_type) if result_type.is_nil() => {} + ty::FnConverging(result_type) => { + output.push_str(" -> "); + push_unique_type_name(tcx, result_type, output); + } + ty::FnDiverging => { + output.push_str(" -> !"); + } + } + }, + ty::TyClosure(def_id, ref closure_substs) => { + push_item_name(tcx, def_id, output); + output.push_str("{"); + output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize())); + output.push_str("}"); + push_type_params(tcx, &closure_substs.func_substs.types, &[], output); + } + ty::TyError | + ty::TyInfer(_) | + ty::TyProjection(..) | + ty::TyParam(_) => { + bug!("debuginfo: Trying to create type name for \ + unexpected type: {:?}", t); + } + } +} + +fn push_item_name(tcx: TyCtxt, + def_id: DefId, + output: &mut String) { + let def_path = tcx.def_path(def_id); + + // some_crate:: + output.push_str(&tcx.crate_name(def_path.krate)); + output.push_str("::"); + + // foo::bar::ItemName:: + for part in tcx.def_path(def_id).data { + output.push_str(&format!("{}[{}]::", + part.data.as_interned_str(), + part.disambiguator)); + } + + // remove final "::" + output.pop(); + output.pop(); +} + +fn push_type_params<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + types: &'tcx subst::VecPerParamSpace>, + projections: &[ty::PolyProjectionPredicate<'tcx>], + output: &mut String) { + if types.is_empty() && projections.is_empty() { + return; + } + + output.push('<'); + + for &type_parameter in types { + push_unique_type_name(tcx, type_parameter, output); + output.push_str(", "); + } + + for projection in projections { + let projection = projection.skip_binder(); + let name = token::get_ident_interner().get(projection.projection_ty.item_name); + output.push_str(&name[..]); + output.push_str("="); + push_unique_type_name(tcx, projection.ty, output); + output.push_str(", "); + } + + output.pop(); + output.pop(); + + output.push('>'); +} + +fn push_instance_as_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + instance: Instance<'tcx>, + output: &mut String) { + push_item_name(tcx, instance.def, output); + push_type_params(tcx, &instance.substs.types, &[], output); +} + +pub fn def_id_to_string(tcx: TyCtxt, def_id: DefId) -> String { + let mut output = String::new(); + push_item_name(tcx, def_id, &mut output); + output +} + +pub fn type_to_string<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + ty: ty::Ty<'tcx>) + -> String { + let mut output = String::new(); + push_unique_type_name(tcx, ty, &mut output); + output +} + +impl<'tcx> TransItem<'tcx> { + + pub fn requests_inline<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool { + match *self { + TransItem::Fn(ref instance) => { + 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(), + TransItem::DropGlue(..) | + TransItem::Static(..) => false, + } + } + + pub fn is_lazily_instantiated(&self) -> bool { + match *self { + TransItem::Fn(ref instance) => !instance.substs.types.is_empty(), + TransItem::DropGlue(..) => true, + TransItem::Static(..) => false, + } + } + + pub fn explicit_linkage<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option { + let def_id = match *self { + TransItem::Fn(ref instance) => instance.def, + TransItem::Static(node_id) => tcx.map.local_def_id(node_id), + TransItem::DropGlue(..) => return None, + }; + + let attributes = tcx.get_attrs(def_id); + if let Some(name) = attr::first_attr_value_str_by_name(&attributes, "linkage") { + if let Some(linkage) = llvm_linkage_by_name(&name) { + Some(linkage) + } else { + let span = tcx.map.span_if_local(def_id); + if let Some(span) = span { + tcx.sess.span_fatal(span, "invalid linkage specified") + } else { + tcx.sess.fatal(&format!("invalid linkage specified: {}", name)) + } + } + } else { + None + } + } + + pub fn to_string<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String { + let hir_map = &tcx.map; + + return match *self { + TransItem::DropGlue(dg) => { + let mut s = String::with_capacity(32); + match dg { + DropGlueKind::Ty(_) => s.push_str("drop-glue "), + DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "), + }; + push_unique_type_name(tcx, dg.ty(), &mut s); + s + } + TransItem::Fn(instance) => { + to_string_internal(tcx, "fn ", instance) + }, + TransItem::Static(node_id) => { + let def_id = hir_map.local_def_id(node_id); + let empty_substs = tcx.mk_substs(subst::Substs::empty()); + let instance = Instance::new(def_id, empty_substs); + to_string_internal(tcx, "static ", instance) + }, + }; + + fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + prefix: &str, + instance: Instance<'tcx>) + -> String { + let mut result = String::with_capacity(32); + result.push_str(prefix); + push_instance_as_string(tcx, instance, &mut result); + result + } + } + + pub fn to_raw_string(&self) -> String { + match *self { + TransItem::DropGlue(dg) => { + format!("DropGlue({})", dg.ty() as *const _ as usize) + } + TransItem::Fn(instance) => { + format!("Fn({:?}, {})", + instance.def, + instance.substs as *const _ as usize) + } + TransItem::Static(id) => { + format!("Static({:?})", id) + } + } + } +} diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs new file mode 100644 index 0000000000000..db940b680473a --- /dev/null +++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs @@ -0,0 +1,41 @@ +// 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 + +//~ TRANS_ITEM drop-glue drop_in_place_intrinsic::StructWithDtor[0] +//~ TRANS_ITEM drop-glue-contents drop_in_place_intrinsic::StructWithDtor[0] +struct StructWithDtor(u32); + +impl Drop for StructWithDtor { + //~ TRANS_ITEM fn drop_in_place_intrinsic::{{impl}}[0]::drop[0] + fn drop(&mut self) {} +} + +//~ TRANS_ITEM fn drop_in_place_intrinsic::main[0] +fn main() { + + //~ TRANS_ITEM drop-glue [drop_in_place_intrinsic::StructWithDtor[0]; 2] + let x = [StructWithDtor(0), StructWithDtor(1)]; + + drop_slice_in_place(&x); +} + +//~ TRANS_ITEM fn drop_in_place_intrinsic::drop_slice_in_place[0] +fn drop_slice_in_place(x: &[StructWithDtor]) { + unsafe { + // This is the interesting thing in this test case: Normally we would + // not have drop-glue for the unsized [StructWithDtor]. This has to be + // generated though when the drop_in_place() intrinsic is used. + //~ TRANS_ITEM drop-glue [drop_in_place_intrinsic::StructWithDtor[0]] + ::std::ptr::drop_in_place(x as *const _ as *mut [StructWithDtor]); + } +} diff --git a/src/test/codegen-units/item-collection/static-init.rs b/src/test/codegen-units/item-collection/static-init.rs new file mode 100644 index 0000000000000..41c0f46f80bfb --- /dev/null +++ b/src/test/codegen-units/item-collection/static-init.rs @@ -0,0 +1,23 @@ +// Copyright 2016 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:-Zprint-trans-items=eager + +pub static FN : fn() = foo::; + +pub fn foo() { } + +//~ TRANS_ITEM fn static_init::foo[0] +//~ TRANS_ITEM static static_init::FN[0] + +fn main() { } + +//~ TRANS_ITEM fn static_init::main[0] +//~ TRANS_ITEM drop-glue i8 diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs index 1edc3d5d2e238..04ebef645ec98 100644 --- a/src/test/codegen-units/partitioning/local-drop-glue.rs +++ b/src/test/codegen-units/partitioning/local-drop-glue.rs @@ -23,7 +23,7 @@ struct Struct { } impl Drop for Struct { - //~ TRANS_ITEM fn local_drop_glue::{{impl}}[0]::drop[0] @@ local_drop_glue[WeakODR] local_drop_glue-mod1[Declaration] + //~ TRANS_ITEM fn local_drop_glue::{{impl}}[0]::drop[0] @@ local_drop_glue[WeakODR] fn drop(&mut self) {} } diff --git a/src/test/codegen-units/partitioning/local-generic.rs b/src/test/codegen-units/partitioning/local-generic.rs index 4c762ebdc2e54..e38e676b95c61 100644 --- a/src/test/codegen-units/partitioning/local-generic.rs +++ b/src/test/codegen-units/partitioning/local-generic.rs @@ -19,10 +19,10 @@ // Used in different modules/codegen units but always instantiated in the same // codegen unit. -//~ TRANS_ITEM fn local_generic::generic[0] @@ local_generic.volatile[WeakODR] local_generic[Declaration] -//~ TRANS_ITEM fn local_generic::generic[0] @@ local_generic.volatile[WeakODR] local_generic-mod1[Declaration] -//~ TRANS_ITEM fn local_generic::generic[0] @@ local_generic.volatile[WeakODR] local_generic-mod1-mod1[Declaration] -//~ TRANS_ITEM fn local_generic::generic[0]<&str> @@ local_generic.volatile[WeakODR] local_generic-mod2[Declaration] +//~ TRANS_ITEM fn local_generic::generic[0] @@ local_generic.volatile[WeakODR] +//~ TRANS_ITEM fn local_generic::generic[0] @@ local_generic.volatile[WeakODR] +//~ TRANS_ITEM fn local_generic::generic[0] @@ local_generic.volatile[WeakODR] +//~ TRANS_ITEM fn local_generic::generic[0]<&str> @@ local_generic.volatile[WeakODR] pub fn generic(x: T) -> T { x } //~ TRANS_ITEM fn local_generic::user[0] @@ local_generic[WeakODR] diff --git a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs index 390bade153c58..99dda0e38bad7 100644 --- a/src/test/codegen-units/partitioning/methods-are-with-self-type.rs +++ b/src/test/codegen-units/partitioning/methods-are-with-self-type.rs @@ -61,19 +61,19 @@ mod type2 { //~ TRANS_ITEM fn methods_are_with_self_type::main[0] fn main() { - //~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::method[0] @@ methods_are_with_self_type.volatile[WeakODR] methods_are_with_self_type[Declaration] + //~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::method[0] @@ methods_are_with_self_type.volatile[WeakODR] SomeGenericType(0u32, 0u64).method(); - //~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::associated_fn[0] @@ methods_are_with_self_type.volatile[WeakODR] methods_are_with_self_type[Declaration] + //~ TRANS_ITEM fn methods_are_with_self_type::mod1[0]::{{impl}}[1]::associated_fn[0] @@ methods_are_with_self_type.volatile[WeakODR] SomeGenericType::associated_fn('c', "&str"); - //~ TRANS_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0] @@ methods_are_with_self_type-type1.volatile[WeakODR] methods_are_with_self_type[Declaration] + //~ TRANS_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0] @@ methods_are_with_self_type-type1.volatile[WeakODR] type1::Struct.foo(); - //~ TRANS_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0] @@ methods_are_with_self_type-type2.volatile[WeakODR] methods_are_with_self_type[Declaration] + //~ TRANS_ITEM fn methods_are_with_self_type::{{impl}}[0]::foo[0] @@ methods_are_with_self_type-type2.volatile[WeakODR] type2::Struct.foo(); - //~ TRANS_ITEM fn methods_are_with_self_type::Trait[0]::default[0] @@ methods_are_with_self_type-type1.volatile[WeakODR] methods_are_with_self_type[Declaration] + //~ TRANS_ITEM fn methods_are_with_self_type::Trait[0]::default[0] @@ methods_are_with_self_type-type1.volatile[WeakODR] type1::Struct.default(); - //~ TRANS_ITEM fn methods_are_with_self_type::Trait[0]::default[0] @@ methods_are_with_self_type-type2.volatile[WeakODR] methods_are_with_self_type[Declaration] + //~ TRANS_ITEM fn methods_are_with_self_type::Trait[0]::default[0] @@ methods_are_with_self_type-type2.volatile[WeakODR] type2::Struct.default(); }