about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <bjorn3@users.noreply.github.com>2017-10-19 11:01:31 +0200
committerbjorn3 <bjorn3@users.noreply.github.com>2017-10-19 11:01:31 +0200
commit906523efea60f4d58d6ce58bc61589d4ff3d7b4e (patch)
treefc1effcd46f2827dfc809ba2a25bdd16de0943fe
parentb7960878ba77124505aabe7dc99d0a898354c326 (diff)
downloadrust-906523efea60f4d58d6ce58bc61589d4ff3d7b4e.tar.gz
rust-906523efea60f4d58d6ce58bc61589d4ff3d7b4e.zip
Move collector to rustc_trans_utils
-rw-r--r--src/Cargo.lock1
-rw-r--r--src/librustc_trans/back/symbol_names.rs2
-rw-r--r--src/librustc_trans/base.rs30
-rw-r--r--src/librustc_trans/common.rs17
-rw-r--r--src/librustc_trans/lib.rs5
-rw-r--r--src/librustc_trans/partitioning.rs2
-rw-r--r--src/librustc_trans/trans_item.rs417
-rw-r--r--src/librustc_trans_utils/Cargo.toml1
-rw-r--r--src/librustc_trans_utils/collector.rs (renamed from src/librustc_trans/collector.rs)3
-rw-r--r--src/librustc_trans_utils/common.rs78
-rw-r--r--src/librustc_trans_utils/lib.rs5
-rw-r--r--src/librustc_trans_utils/monomorphize.rs (renamed from src/librustc_trans/monomorphize.rs)0
-rw-r--r--src/librustc_trans_utils/trans_item.rs464
13 files changed, 565 insertions, 460 deletions
diff --git a/src/Cargo.lock b/src/Cargo.lock
index 328ce353e2a..0989c430df0 100644
--- a/src/Cargo.lock
+++ b/src/Cargo.lock
@@ -1787,6 +1787,7 @@ dependencies = [
  "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "rustc 0.0.0",
  "rustc_back 0.0.0",
+ "rustc_data_structures 0.0.0",
  "syntax 0.0.0",
  "syntax_pos 0.0.0",
 ]
diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs
index 66a27f1c4a9..0ebfe4daad1 100644
--- a/src/librustc_trans/back/symbol_names.rs
+++ b/src/librustc_trans/back/symbol_names.rs
@@ -98,7 +98,7 @@
 //! DefPaths which are much more robust in the face of changes to the code base.
 
 use monomorphize::Instance;
-use trans_item::{TransItemExt, InstantiationMode};
+use trans_item::{BaseTransItemExt, InstantiationMode};
 
 use rustc::middle::weak_lang_items;
 use rustc::middle::trans::TransItem;
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 6b53b5b6411..5a3adde8d1d 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -70,7 +70,7 @@ use monomorphize::{self, Instance};
 use partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt};
 use symbol_names_test;
 use time_graph;
-use trans_item::{TransItem, TransItemExt, DefPathBasedNames};
+use trans_item::{TransItem, BaseTransItemExt, TransItemExt, DefPathBasedNames};
 use type_::Type;
 use type_of;
 use value::Value;
@@ -93,6 +93,7 @@ use syntax::ast;
 use mir::lvalue::Alignment;
 
 pub use rustc_trans_utils::{find_exported_symbols, check_for_rustc_errors_attr};
+pub use rustc_trans_utils::trans_item::linkage_by_name;
 
 pub struct StatRecorder<'a, 'tcx: 'a> {
     ccx: &'a CrateContext<'a, 'tcx>,
@@ -618,33 +619,6 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
     mir::trans_mir(ccx, lldecl, &mir, instance, sig);
 }
 
-pub fn linkage_by_name(name: &str) -> Option<Linkage> {
-    use rustc::middle::trans::Linkage::*;
-
-    // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
-    // applicable to variable declarations and may not really make sense for
-    // Rust code in the first place but whitelist them anyway and trust that
-    // the user knows what s/he's doing. Who knows, unanticipated use cases
-    // may pop up in the future.
-    //
-    // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
-    // and don't have to be, LLVM treats them as no-ops.
-    match name {
-        "appending" => Some(Appending),
-        "available_externally" => Some(AvailableExternally),
-        "common" => Some(Common),
-        "extern_weak" => Some(ExternalWeak),
-        "external" => Some(External),
-        "internal" => Some(Internal),
-        "linkonce" => Some(LinkOnceAny),
-        "linkonce_odr" => Some(LinkOnceODR),
-        "private" => Some(Private),
-        "weak" => Some(WeakAny),
-        "weak_odr" => Some(WeakODR),
-        _ => None,
-    }
-}
-
 pub fn set_link_section(ccx: &CrateContext,
                         llval: ValueRef,
                         attrs: &[ast::Attribute]) {
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 52607904f73..e3856cabcf9 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -36,7 +36,6 @@ use libc::{c_uint, c_char};
 use std::iter;
 
 use syntax::abi::Abi;
-use syntax::attr;
 use syntax::symbol::InternedString;
 use syntax_pos::{Span, DUMMY_SP};
 
@@ -552,22 +551,6 @@ pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 }
 
-pub fn requests_inline<'a, 'tcx>(
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    instance: &ty::Instance<'tcx>
-) -> bool {
-    if is_inline_instance(tcx, instance) {
-        return true
-    }
-    if let ty::InstanceDef::DropGlue(..) = instance.def {
-        // Drop glue wants to be instantiated at every translation
-        // unit, but without an #[inline] hint. We should make this
-        // available to normal end-users.
-        return true
-    }
-    attr::requests_inline(&instance.def.attrs(tcx)[..])
-}
-
 pub fn is_inline_instance<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     instance: &ty::Instance<'tcx>
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 2b1c62c7f1c..88ec3a65d35 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -83,6 +83,9 @@ use rustc::ty::maps::Providers;
 use rustc::ty::{self, TyCtxt};
 use rustc::util::nodemap::{FxHashSet, FxHashMap};
 
+use rustc_trans_utils::collector;
+use rustc_trans_utils::monomorphize;
+
 mod diagnostics;
 
 pub mod back {
@@ -124,7 +127,6 @@ mod cabi_x86;
 mod cabi_x86_64;
 mod cabi_x86_win64;
 mod callee;
-mod collector;
 mod common;
 mod consts;
 mod context;
@@ -137,7 +139,6 @@ mod machine;
 mod metadata;
 mod meth;
 mod mir;
-mod monomorphize;
 mod partitioning;
 mod symbol_names_test;
 mod time_graph;
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index 386806e4c9c..6980ba8a525 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -114,7 +114,7 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet};
 use std::collections::hash_map::Entry;
 use syntax::ast::NodeId;
 use syntax::symbol::{Symbol, InternedString};
-use trans_item::{TransItem, TransItemExt, InstantiationMode};
+use trans_item::{TransItem, BaseTransItemExt, TransItemExt, InstantiationMode};
 
 pub use rustc::middle::trans::CodegenUnit;
 
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 060f02ee23e..db1af8cdefb 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -24,50 +24,21 @@ use declare;
 use llvm;
 use monomorphize::Instance;
 use rustc::hir;
-use rustc::hir::def_id::DefId;
 use rustc::middle::trans::{Linkage, Visibility};
-use rustc::session::config::OptLevel;
-use rustc::traits;
-use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc::ty::subst::{Subst, Substs};
+use rustc::ty::{self, TyCtxt, TypeFoldable};
 use syntax::ast;
-use syntax::attr::{self, InlineAttr};
+use syntax::attr;
 use syntax_pos::Span;
 use syntax_pos::symbol::Symbol;
 use type_of;
-use std::fmt::{self, Write};
-use std::iter;
+use std::fmt;
 
 pub use rustc::middle::trans::TransItem;
 
-/// Describes how a translation item will be instantiated in object files.
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
-pub enum InstantiationMode {
-    /// There will be exactly one instance of the given TransItem. It will have
-    /// external linkage so that it can be linked to from other codegen units.
-    GloballyShared {
-        /// In some compilation scenarios we may decide to take functions that
-        /// are typically `LocalCopy` and instead move them to `GloballyShared`
-        /// to avoid translating them a bunch of times. In this situation,
-        /// however, our local copy may conflict with other crates also
-        /// inlining the same function.
-        ///
-        /// This flag indicates that this situation is occuring, and informs
-        /// symbol name calculation that some extra mangling is needed to
-        /// avoid conflicts. Note that this may eventually go away entirely if
-        /// ThinLTO enables us to *always* have a globally shared instance of a
-        /// function within one crate's compilation.
-        may_conflict: bool,
-    },
-
-    /// Each codegen unit containing a reference to the given TransItem will
-    /// have its own private copy of the function (with internal linkage).
-    LocalCopy,
-}
-
-pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
-    fn as_trans_item(&self) -> &TransItem<'tcx>;
+pub use rustc_trans_utils::trans_item::*;
+pub use rustc_trans_utils::trans_item::TransItemExt as BaseTransItemExt;
 
+pub trait TransItemExt<'a, 'tcx>: fmt::Debug + BaseTransItemExt<'a, 'tcx> {
     fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
         debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}",
                self.to_string(ccx.tcx()),
@@ -165,53 +136,6 @@ pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
         }.map(|node_id| tcx.hir.span(node_id))
     }
 
-    fn instantiation_mode(&self,
-                          tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                          -> InstantiationMode {
-        let inline_in_all_cgus =
-            tcx.sess.opts.debugging_opts.inline_in_all_cgus.unwrap_or_else(|| {
-                tcx.sess.opts.optimize != OptLevel::No
-            });
-
-        match *self.as_trans_item() {
-            TransItem::Fn(ref instance) => {
-                // If this function isn't inlined or otherwise has explicit
-                // linkage, then we'll be creating a globally shared version.
-                if self.explicit_linkage(tcx).is_some() ||
-                    !common::requests_inline(tcx, instance)
-                {
-                    return InstantiationMode::GloballyShared  { may_conflict: false }
-                }
-
-                // At this point we don't have explicit linkage and we're an
-                // inlined function. If we're inlining into all CGUs then we'll
-                // be creating a local copy per CGU
-                if inline_in_all_cgus {
-                    return InstantiationMode::LocalCopy
-                }
-
-                // Finally, if this is `#[inline(always)]` we're sure to respect
-                // that with an inline copy per CGU, but otherwise we'll be
-                // creating one copy of this `#[inline]` function which may
-                // conflict with upstream crates as it could be an exported
-                // symbol.
-                let attrs = instance.def.attrs(tcx);
-                match attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs) {
-                    InlineAttr::Always => InstantiationMode::LocalCopy,
-                    _ => {
-                        InstantiationMode::GloballyShared  { may_conflict: true }
-                    }
-                }
-            }
-            TransItem::Static(..) => {
-                InstantiationMode::GloballyShared { may_conflict: false }
-            }
-            TransItem::GlobalAsm(..) => {
-                InstantiationMode::GloballyShared { may_conflict: false }
-            }
-        }
-    }
-
     fn is_generic_fn(&self) -> bool {
         match *self.as_trans_item() {
             TransItem::Fn(ref instance) => {
@@ -222,97 +146,6 @@ pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
         }
     }
 
-    fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Linkage> {
-        let def_id = match *self.as_trans_item() {
-            TransItem::Fn(ref instance) => instance.def_id(),
-            TransItem::Static(node_id) => tcx.hir.local_def_id(node_id),
-            TransItem::GlobalAsm(..) => 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) = base::linkage_by_name(&name.as_str()) {
-                Some(linkage)
-            } else {
-                let span = tcx.hir.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
-        }
-    }
-
-    /// Returns whether this instance is instantiable - whether it has no unsatisfied
-    /// predicates.
-    ///
-    /// In order to translate an item, all of its predicates must hold, because
-    /// otherwise the item does not make sense. Type-checking ensures that
-    /// the predicates of every item that is *used by* a valid item *do*
-    /// hold, so we can rely on that.
-    ///
-    /// However, we translate collector roots (reachable items) and functions
-    /// in vtables when they are seen, even if they are not used, and so they
-    /// might not be instantiable. For example, a programmer can define this
-    /// public function:
-    ///
-    ///     pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
-    ///         <&mut () as Clone>::clone(&s);
-    ///     }
-    ///
-    /// That function can't be translated, because the method `<&mut () as Clone>::clone`
-    /// does not exist. Luckily for us, that function can't ever be used,
-    /// because that would require for `&'a mut (): Clone` to hold, so we
-    /// can just not emit any code, or even a linker reference for it.
-    ///
-    /// Similarly, if a vtable method has such a signature, and therefore can't
-    /// be used, we can just not emit it and have a placeholder (a null pointer,
-    /// which will never be accessed) in its place.
-    fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
-        debug!("is_instantiable({:?})", self);
-        let (def_id, substs) = match *self.as_trans_item() {
-            TransItem::Fn(ref instance) => (instance.def_id(), instance.substs),
-            TransItem::Static(node_id) => (tcx.hir.local_def_id(node_id), Substs::empty()),
-            // global asm never has predicates
-            TransItem::GlobalAsm(..) => return true
-        };
-
-        let predicates = tcx.predicates_of(def_id).predicates.subst(tcx, substs);
-        traits::normalize_and_test_predicates(tcx, predicates)
-    }
-
-    fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
-        let hir_map = &tcx.hir;
-
-        return match *self.as_trans_item() {
-            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::new(def_id, tcx.intern_substs(&[]));
-                to_string_internal(tcx, "static ", instance)
-            },
-            TransItem::GlobalAsm(..) => {
-                "global_asm".to_string()
-            }
-        };
-
-        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);
-            let printer = DefPathBasedNames::new(tcx, false, false);
-            printer.push_instance_as_string(instance, &mut result);
-            result
-        }
-    }
-
     fn to_raw_string(&self) -> String {
         match *self.as_trans_item() {
             TransItem::Fn(instance) => {
@@ -330,11 +163,7 @@ pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
     }
 }
 
-impl<'a, 'tcx> TransItemExt<'a, 'tcx> for TransItem<'tcx> {
-    fn as_trans_item(&self) -> &TransItem<'tcx> {
-        self
-    }
-}
+impl<'a, 'tcx> TransItemExt<'a, 'tcx> for TransItem<'tcx> {}
 
 fn predefine_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                               node_id: ast::NodeId,
@@ -402,235 +231,3 @@ fn predefine_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     ccx.instances().borrow_mut().insert(instance, lldecl);
 }
 
-//=-----------------------------------------------------------------------------
-// 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 struct DefPathBasedNames<'a, 'tcx: 'a> {
-    tcx: TyCtxt<'a, 'tcx, 'tcx>,
-    omit_disambiguators: bool,
-    omit_local_crate_name: bool,
-}
-
-impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
-    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-               omit_disambiguators: bool,
-               omit_local_crate_name: bool)
-               -> Self {
-        DefPathBasedNames {
-            tcx,
-            omit_disambiguators,
-            omit_local_crate_name,
-        }
-    }
-
-    pub fn push_type_name(&self, t: 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::TyNever             => output.push_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::TyInt(ast::IntTy::I128)   => output.push_str("i128"),
-            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::TyUint(ast::UintTy::U128)  => output.push_str("u128"),
-            ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"),
-            ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
-            ty::TyAdt(adt_def, substs) => {
-                self.push_def_path(adt_def.did, output);
-                self.push_type_params(substs, iter::empty(), output);
-            },
-            ty::TyTuple(component_types, _) => {
-                output.push('(');
-                for &component_type in component_types {
-                    self.push_type_name(component_type, output);
-                    output.push_str(", ");
-                }
-                if !component_types.is_empty() {
-                    output.pop();
-                    output.pop();
-                }
-                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 "),
-                }
-
-                self.push_type_name(inner_type, output);
-            },
-            ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => {
-                output.push('&');
-                if mutbl == hir::MutMutable {
-                    output.push_str("mut ");
-                }
-
-                self.push_type_name(inner_type, output);
-            },
-            ty::TyArray(inner_type, len) => {
-                output.push('[');
-                self.push_type_name(inner_type, output);
-                write!(output, "; {}",
-                    len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap();
-                output.push(']');
-            },
-            ty::TySlice(inner_type) => {
-                output.push('[');
-                self.push_type_name(inner_type, output);
-                output.push(']');
-            },
-            ty::TyDynamic(ref trait_data, ..) => {
-                if let Some(principal) = trait_data.principal() {
-                    self.push_def_path(principal.def_id(), output);
-                    self.push_type_params(principal.skip_binder().substs,
-                        trait_data.projection_bounds(),
-                        output);
-                }
-            },
-            ty::TyFnDef(..) |
-            ty::TyFnPtr(_) => {
-                let sig = t.fn_sig(self.tcx);
-                if sig.unsafety() == hir::Unsafety::Unsafe {
-                    output.push_str("unsafe ");
-                }
-
-                let abi = sig.abi();
-                if abi != ::abi::Abi::Rust {
-                    output.push_str("extern \"");
-                    output.push_str(abi.name());
-                    output.push_str("\" ");
-                }
-
-                output.push_str("fn(");
-
-                let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig);
-
-                if !sig.inputs().is_empty() {
-                    for &parameter_type in sig.inputs() {
-                        self.push_type_name(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(')');
-
-                if !sig.output().is_nil() {
-                    output.push_str(" -> ");
-                    self.push_type_name(sig.output(), output);
-                }
-            },
-            ty::TyGenerator(def_id, ref closure_substs, _) |
-            ty::TyClosure(def_id, ref closure_substs) => {
-                self.push_def_path(def_id, output);
-                let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
-                let substs = closure_substs.substs.truncate_to(self.tcx, generics);
-                self.push_type_params(substs, iter::empty(), output);
-            }
-            ty::TyError |
-            ty::TyInfer(_) |
-            ty::TyProjection(..) |
-            ty::TyParam(_) |
-            ty::TyAnon(..) => {
-                bug!("DefPathBasedNames: Trying to create type name for \
-                                         unexpected type: {:?}", t);
-            }
-        }
-    }
-
-    pub fn push_def_path(&self,
-                         def_id: DefId,
-                         output: &mut String) {
-        let def_path = self.tcx.def_path(def_id);
-
-        // some_crate::
-        if !(self.omit_local_crate_name && def_id.is_local()) {
-            output.push_str(&self.tcx.crate_name(def_path.krate).as_str());
-            output.push_str("::");
-        }
-
-        // foo::bar::ItemName::
-        for part in self.tcx.def_path(def_id).data {
-            if self.omit_disambiguators {
-                write!(output, "{}::", part.data.as_interned_str()).unwrap();
-            } else {
-                write!(output, "{}[{}]::",
-                       part.data.as_interned_str(),
-                       part.disambiguator).unwrap();
-            }
-        }
-
-        // remove final "::"
-        output.pop();
-        output.pop();
-    }
-
-    fn push_type_params<I>(&self,
-                            substs: &Substs<'tcx>,
-                            projections: I,
-                            output: &mut String)
-        where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>>
-    {
-        let mut projections = projections.peekable();
-        if substs.types().next().is_none() && projections.peek().is_none() {
-            return;
-        }
-
-        output.push('<');
-
-        for type_parameter in substs.types() {
-            self.push_type_name(type_parameter, output);
-            output.push_str(", ");
-        }
-
-        for projection in projections {
-            let projection = projection.skip_binder();
-            let name = &self.tcx.associated_item(projection.item_def_id).name.as_str();
-            output.push_str(name);
-            output.push_str("=");
-            self.push_type_name(projection.ty, output);
-            output.push_str(", ");
-        }
-
-        output.pop();
-        output.pop();
-
-        output.push('>');
-    }
-
-    pub fn push_instance_as_string(&self,
-                                   instance: Instance<'tcx>,
-                                   output: &mut String) {
-        self.push_def_path(instance.def_id(), output);
-        self.push_type_params(instance.substs, iter::empty(), output);
-    }
-}
diff --git a/src/librustc_trans_utils/Cargo.toml b/src/librustc_trans_utils/Cargo.toml
index bedbea00688..7d9d7cea933 100644
--- a/src/librustc_trans_utils/Cargo.toml
+++ b/src/librustc_trans_utils/Cargo.toml
@@ -19,3 +19,4 @@ syntax = { path = "../libsyntax" }
 syntax_pos = { path = "../libsyntax_pos" }
 rustc = { path = "../librustc" }
 rustc_back = { path = "../librustc_back" }
+rustc_data_structures = { path = "../librustc_data_structures" }
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans_utils/collector.rs
index 33a2e96ee66..c87d86262ef 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans_utils/collector.rs
@@ -195,6 +195,7 @@ use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
 use rustc::middle::const_val::ConstVal;
 use rustc::middle::lang_items::{ExchangeMallocFnLangItem};
+use rustc::middle::trans::TransItem;
 use rustc::traits;
 use rustc::ty::subst::Substs;
 use rustc::ty::{self, TypeFoldable, Ty, TyCtxt};
@@ -206,7 +207,7 @@ use common::{def_ty, instance_ty, type_is_sized};
 use monomorphize::{self, Instance};
 use rustc::util::nodemap::{FxHashSet, FxHashMap, DefIdMap};
 
-use trans_item::{TransItem, TransItemExt, DefPathBasedNames, InstantiationMode};
+use trans_item::{TransItemExt, DefPathBasedNames, InstantiationMode};
 
 use rustc_data_structures::bitvec::BitVector;
 
diff --git a/src/librustc_trans_utils/common.rs b/src/librustc_trans_utils/common.rs
new file mode 100644
index 00000000000..634e37220e2
--- /dev/null
+++ b/src/librustc_trans_utils/common.rs
@@ -0,0 +1,78 @@
+// Copyright 2012-2014 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(non_camel_case_types, non_snake_case)]
+
+//! Code that is useful in various trans modules.
+
+use rustc::hir::def_id::DefId;
+use rustc::hir::map::DefPathData;
+use rustc::traits;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::Substs;
+
+use syntax::attr;
+use syntax_pos::DUMMY_SP;
+
+pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
+    ty.is_sized(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
+}
+
+pub fn requests_inline<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    instance: &ty::Instance<'tcx>
+) -> bool {
+    if is_inline_instance(tcx, instance) {
+        return true
+    }
+    if let ty::InstanceDef::DropGlue(..) = instance.def {
+        // Drop glue wants to be instantiated at every translation
+        // unit, but without an #[inline] hint. We should make this
+        // available to normal end-users.
+        return true
+    }
+    attr::requests_inline(&instance.def.attrs(tcx)[..])
+}
+
+pub fn is_inline_instance<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    instance: &ty::Instance<'tcx>
+) -> bool {
+    let def_id = match instance.def {
+        ty::InstanceDef::Item(def_id) => def_id,
+        ty::InstanceDef::DropGlue(_, Some(_)) => return false,
+        _ => return true
+    };
+    match tcx.def_key(def_id).disambiguated_data.data {
+        DefPathData::StructCtor |
+        DefPathData::EnumVariant(..) |
+        DefPathData::ClosureExpr => true,
+        _ => false
+    }
+}
+
+/// Given a DefId and some Substs, produces the monomorphic item type.
+pub fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                        def_id: DefId,
+                        substs: &'tcx Substs<'tcx>)
+                        -> Ty<'tcx>
+{
+    let ty = tcx.type_of(def_id);
+    tcx.trans_apply_param_substs(substs, &ty)
+}
+
+/// Return the substituted type of an instance.
+pub fn instance_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                             instance: &ty::Instance<'tcx>)
+                             -> Ty<'tcx>
+{
+    let ty = instance.def.def_ty(tcx);
+    tcx.trans_apply_param_substs(instance.substs, &ty)
+}
diff --git a/src/librustc_trans_utils/lib.rs b/src/librustc_trans_utils/lib.rs
index 6873befd2bf..bc8f8d5a6da 100644
--- a/src/librustc_trans_utils/lib.rs
+++ b/src/librustc_trans_utils/lib.rs
@@ -38,6 +38,7 @@ extern crate log;
 #[macro_use]
 extern crate rustc;
 extern crate rustc_back;
+extern crate rustc_data_structures;
 extern crate syntax;
 extern crate syntax_pos;
 
@@ -49,7 +50,11 @@ use rustc::util::nodemap::NodeSet;
 
 use syntax::attr;
 
+mod common;
 pub mod link;
+pub mod collector;
+pub mod trans_item;
+pub mod monomorphize;
 pub mod trans_crate;
 
 /// check for the #[rustc_error] annotation, which forces an
diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans_utils/monomorphize.rs
index 471be439a8f..471be439a8f 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans_utils/monomorphize.rs
diff --git a/src/librustc_trans_utils/trans_item.rs b/src/librustc_trans_utils/trans_item.rs
new file mode 100644
index 00000000000..0ada39d7d27
--- /dev/null
+++ b/src/librustc_trans_utils/trans_item.rs
@@ -0,0 +1,464 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 common;
+use monomorphize::Instance;
+use rustc::hir;
+use rustc::hir::def_id::DefId;
+use rustc::middle::trans::Linkage;
+use rustc::session::config::OptLevel;
+use rustc::traits;
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::subst::{Subst, Substs};
+use syntax::ast;
+use syntax::attr::{self, InlineAttr};
+use std::fmt::{self, Write};
+use std::iter;
+
+pub use rustc::middle::trans::TransItem;
+
+pub fn linkage_by_name(name: &str) -> Option<Linkage> {
+    use rustc::middle::trans::Linkage::*;
+
+    // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
+    // applicable to variable declarations and may not really make sense for
+    // Rust code in the first place but whitelist them anyway and trust that
+    // the user knows what s/he's doing. Who knows, unanticipated use cases
+    // may pop up in the future.
+    //
+    // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
+    // and don't have to be, LLVM treats them as no-ops.
+    match name {
+        "appending" => Some(Appending),
+        "available_externally" => Some(AvailableExternally),
+        "common" => Some(Common),
+        "extern_weak" => Some(ExternalWeak),
+        "external" => Some(External),
+        "internal" => Some(Internal),
+        "linkonce" => Some(LinkOnceAny),
+        "linkonce_odr" => Some(LinkOnceODR),
+        "private" => Some(Private),
+        "weak" => Some(WeakAny),
+        "weak_odr" => Some(WeakODR),
+        _ => None,
+    }
+}
+
+/// Describes how a translation item will be instantiated in object files.
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
+pub enum InstantiationMode {
+    /// There will be exactly one instance of the given TransItem. It will have
+    /// external linkage so that it can be linked to from other codegen units.
+    GloballyShared {
+        /// In some compilation scenarios we may decide to take functions that
+        /// are typically `LocalCopy` and instead move them to `GloballyShared`
+        /// to avoid translating them a bunch of times. In this situation,
+        /// however, our local copy may conflict with other crates also
+        /// inlining the same function.
+        ///
+        /// This flag indicates that this situation is occuring, and informs
+        /// symbol name calculation that some extra mangling is needed to
+        /// avoid conflicts. Note that this may eventually go away entirely if
+        /// ThinLTO enables us to *always* have a globally shared instance of a
+        /// function within one crate's compilation.
+        may_conflict: bool,
+    },
+
+    /// Each codegen unit containing a reference to the given TransItem will
+    /// have its own private copy of the function (with internal linkage).
+    LocalCopy,
+}
+
+pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
+    fn as_trans_item(&self) -> &TransItem<'tcx>;
+
+    fn instantiation_mode(&self,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                          -> InstantiationMode {
+        let inline_in_all_cgus =
+            tcx.sess.opts.debugging_opts.inline_in_all_cgus.unwrap_or_else(|| {
+                tcx.sess.opts.optimize != OptLevel::No
+            });
+
+        match *self.as_trans_item() {
+            TransItem::Fn(ref instance) => {
+                // If this function isn't inlined or otherwise has explicit
+                // linkage, then we'll be creating a globally shared version.
+                if self.explicit_linkage(tcx).is_some() ||
+                    !common::requests_inline(tcx, instance)
+                {
+                    return InstantiationMode::GloballyShared  { may_conflict: false }
+                }
+
+                // At this point we don't have explicit linkage and we're an
+                // inlined function. If we're inlining into all CGUs then we'll
+                // be creating a local copy per CGU
+                if inline_in_all_cgus {
+                    return InstantiationMode::LocalCopy
+                }
+
+                // Finally, if this is `#[inline(always)]` we're sure to respect
+                // that with an inline copy per CGU, but otherwise we'll be
+                // creating one copy of this `#[inline]` function which may
+                // conflict with upstream crates as it could be an exported
+                // symbol.
+                let attrs = instance.def.attrs(tcx);
+                match attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs) {
+                    InlineAttr::Always => InstantiationMode::LocalCopy,
+                    _ => {
+                        InstantiationMode::GloballyShared  { may_conflict: true }
+                    }
+                }
+            }
+            TransItem::Static(..) => {
+                InstantiationMode::GloballyShared { may_conflict: false }
+            }
+            TransItem::GlobalAsm(..) => {
+                InstantiationMode::GloballyShared { may_conflict: false }
+            }
+        }
+    }
+
+    fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Linkage> {
+        let def_id = match *self.as_trans_item() {
+            TransItem::Fn(ref instance) => instance.def_id(),
+            TransItem::Static(node_id) => tcx.hir.local_def_id(node_id),
+            TransItem::GlobalAsm(..) => 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) = linkage_by_name(&name.as_str()) {
+                Some(linkage)
+            } else {
+                let span = tcx.hir.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
+        }
+    }
+
+    /// Returns whether this instance is instantiable - whether it has no unsatisfied
+    /// predicates.
+    ///
+    /// In order to translate an item, all of its predicates must hold, because
+    /// otherwise the item does not make sense. Type-checking ensures that
+    /// the predicates of every item that is *used by* a valid item *do*
+    /// hold, so we can rely on that.
+    ///
+    /// However, we translate collector roots (reachable items) and functions
+    /// in vtables when they are seen, even if they are not used, and so they
+    /// might not be instantiable. For example, a programmer can define this
+    /// public function:
+    ///
+    ///     pub fn foo<'a>(s: &'a mut ()) where &'a mut (): Clone {
+    ///         <&mut () as Clone>::clone(&s);
+    ///     }
+    ///
+    /// That function can't be translated, because the method `<&mut () as Clone>::clone`
+    /// does not exist. Luckily for us, that function can't ever be used,
+    /// because that would require for `&'a mut (): Clone` to hold, so we
+    /// can just not emit any code, or even a linker reference for it.
+    ///
+    /// Similarly, if a vtable method has such a signature, and therefore can't
+    /// be used, we can just not emit it and have a placeholder (a null pointer,
+    /// which will never be accessed) in its place.
+    fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
+        debug!("is_instantiable({:?})", self);
+        let (def_id, substs) = match *self.as_trans_item() {
+            TransItem::Fn(ref instance) => (instance.def_id(), instance.substs),
+            TransItem::Static(node_id) => (tcx.hir.local_def_id(node_id), Substs::empty()),
+            // global asm never has predicates
+            TransItem::GlobalAsm(..) => return true
+        };
+
+        let predicates = tcx.predicates_of(def_id).predicates.subst(tcx, substs);
+        traits::normalize_and_test_predicates(tcx, predicates)
+    }
+
+    fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
+        let hir_map = &tcx.hir;
+
+        return match *self.as_trans_item() {
+            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::new(def_id, tcx.intern_substs(&[]));
+                to_string_internal(tcx, "static ", instance)
+            },
+            TransItem::GlobalAsm(..) => {
+                "global_asm".to_string()
+            }
+        };
+
+        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);
+            let printer = DefPathBasedNames::new(tcx, false, false);
+            printer.push_instance_as_string(instance, &mut result);
+            result
+        }
+    }
+}
+
+impl<'a, 'tcx> TransItemExt<'a, 'tcx> for TransItem<'tcx> {
+    fn as_trans_item(&self) -> &TransItem<'tcx> {
+        self
+    }
+}
+
+//=-----------------------------------------------------------------------------
+// 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 struct DefPathBasedNames<'a, 'tcx: 'a> {
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    omit_disambiguators: bool,
+    omit_local_crate_name: bool,
+}
+
+impl<'a, 'tcx> DefPathBasedNames<'a, 'tcx> {
+    pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+               omit_disambiguators: bool,
+               omit_local_crate_name: bool)
+               -> Self {
+        DefPathBasedNames {
+            tcx,
+            omit_disambiguators,
+            omit_local_crate_name,
+        }
+    }
+
+    pub fn push_type_name(&self, t: 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::TyNever             => output.push_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::TyInt(ast::IntTy::I128)   => output.push_str("i128"),
+            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::TyUint(ast::UintTy::U128)  => output.push_str("u128"),
+            ty::TyFloat(ast::FloatTy::F32) => output.push_str("f32"),
+            ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
+            ty::TyAdt(adt_def, substs) => {
+                self.push_def_path(adt_def.did, output);
+                self.push_type_params(substs, iter::empty(), output);
+            },
+            ty::TyTuple(component_types, _) => {
+                output.push('(');
+                for &component_type in component_types {
+                    self.push_type_name(component_type, output);
+                    output.push_str(", ");
+                }
+                if !component_types.is_empty() {
+                    output.pop();
+                    output.pop();
+                }
+                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 "),
+                }
+
+                self.push_type_name(inner_type, output);
+            },
+            ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => {
+                output.push('&');
+                if mutbl == hir::MutMutable {
+                    output.push_str("mut ");
+                }
+
+                self.push_type_name(inner_type, output);
+            },
+            ty::TyArray(inner_type, len) => {
+                output.push('[');
+                self.push_type_name(inner_type, output);
+                write!(output, "; {}",
+                    len.val.to_const_int().unwrap().to_u64().unwrap()).unwrap();
+                output.push(']');
+            },
+            ty::TySlice(inner_type) => {
+                output.push('[');
+                self.push_type_name(inner_type, output);
+                output.push(']');
+            },
+            ty::TyDynamic(ref trait_data, ..) => {
+                if let Some(principal) = trait_data.principal() {
+                    self.push_def_path(principal.def_id(), output);
+                    self.push_type_params(principal.skip_binder().substs,
+                        trait_data.projection_bounds(),
+                        output);
+                }
+            },
+            ty::TyFnDef(..) |
+            ty::TyFnPtr(_) => {
+                let sig = t.fn_sig(self.tcx);
+                if sig.unsafety() == hir::Unsafety::Unsafe {
+                    output.push_str("unsafe ");
+                }
+
+                let abi = sig.abi();
+                if abi != ::syntax::abi::Abi::Rust {
+                    output.push_str("extern \"");
+                    output.push_str(abi.name());
+                    output.push_str("\" ");
+                }
+
+                output.push_str("fn(");
+
+                let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig);
+
+                if !sig.inputs().is_empty() {
+                    for &parameter_type in sig.inputs() {
+                        self.push_type_name(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(')');
+
+                if !sig.output().is_nil() {
+                    output.push_str(" -> ");
+                    self.push_type_name(sig.output(), output);
+                }
+            },
+            ty::TyGenerator(def_id, ref closure_substs, _) |
+            ty::TyClosure(def_id, ref closure_substs) => {
+                self.push_def_path(def_id, output);
+                let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id));
+                let substs = closure_substs.substs.truncate_to(self.tcx, generics);
+                self.push_type_params(substs, iter::empty(), output);
+            }
+            ty::TyError |
+            ty::TyInfer(_) |
+            ty::TyProjection(..) |
+            ty::TyParam(_) |
+            ty::TyAnon(..) => {
+                bug!("DefPathBasedNames: Trying to create type name for \
+                                         unexpected type: {:?}", t);
+            }
+        }
+    }
+
+    pub fn push_def_path(&self,
+                         def_id: DefId,
+                         output: &mut String) {
+        let def_path = self.tcx.def_path(def_id);
+
+        // some_crate::
+        if !(self.omit_local_crate_name && def_id.is_local()) {
+            output.push_str(&self.tcx.crate_name(def_path.krate).as_str());
+            output.push_str("::");
+        }
+
+        // foo::bar::ItemName::
+        for part in self.tcx.def_path(def_id).data {
+            if self.omit_disambiguators {
+                write!(output, "{}::", part.data.as_interned_str()).unwrap();
+            } else {
+                write!(output, "{}[{}]::",
+                       part.data.as_interned_str(),
+                       part.disambiguator).unwrap();
+            }
+        }
+
+        // remove final "::"
+        output.pop();
+        output.pop();
+    }
+
+    fn push_type_params<I>(&self,
+                            substs: &Substs<'tcx>,
+                            projections: I,
+                            output: &mut String)
+        where I: Iterator<Item=ty::PolyExistentialProjection<'tcx>>
+    {
+        let mut projections = projections.peekable();
+        if substs.types().next().is_none() && projections.peek().is_none() {
+            return;
+        }
+
+        output.push('<');
+
+        for type_parameter in substs.types() {
+            self.push_type_name(type_parameter, output);
+            output.push_str(", ");
+        }
+
+        for projection in projections {
+            let projection = projection.skip_binder();
+            let name = &self.tcx.associated_item(projection.item_def_id).name.as_str();
+            output.push_str(name);
+            output.push_str("=");
+            self.push_type_name(projection.ty, output);
+            output.push_str(", ");
+        }
+
+        output.pop();
+        output.pop();
+
+        output.push('>');
+    }
+
+    pub fn push_instance_as_string(&self,
+                                   instance: Instance<'tcx>,
+                                   output: &mut String) {
+        self.push_def_path(instance.def_id(), output);
+        self.push_type_params(instance.substs, iter::empty(), output);
+    }
+}