about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2017-09-12 11:04:46 -0700
committerAlex Crichton <alex@alexcrichton.com>2017-09-17 09:41:43 -0700
commit132bde7cf1ee102b6eb370561bf9af9cfbfb4224 (patch)
treea6bb99ad3f4d2191e794a8fbfa9acb51ff2c4385
parentdba3ddd8d4e037db390f54536b4cb77ea988eab1 (diff)
downloadrust-132bde7cf1ee102b6eb370561bf9af9cfbfb4224.tar.gz
rust-132bde7cf1ee102b6eb370561bf9af9cfbfb4224.zip
rustc: Make trans collect/partition a query
This commit moves the `collect_and_partition_translation_items` function into a
query on `TyCtxt` instead of a free function in trans, allowing us to track
dependencies and such of the function.
-rw-r--r--src/librustc/dep_graph/dep_node.rs1
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/middle/trans.rs69
-rw-r--r--src/librustc/ty/maps.rs14
-rw-r--r--src/librustc_trans/back/linker.rs6
-rw-r--r--src/librustc_trans/base.rs134
-rw-r--r--src/librustc_trans/collector.rs2
-rw-r--r--src/librustc_trans/consts.rs6
-rw-r--r--src/librustc_trans/context.rs8
-rw-r--r--src/librustc_trans/lib.rs1
-rw-r--r--src/librustc_trans/partitioning.rs143
-rw-r--r--src/librustc_trans/trans_item.rs215
12 files changed, 352 insertions, 248 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 757a256164e..afd31306817 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -576,6 +576,7 @@ define_dep_nodes!( <'tcx>
     [] StabilityIndex,
     [] AllCrateNums,
     [] ExportedSymbols,
+    [] CollectAndPartitionTranslationItems,
 );
 
 trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 59edc9fb083..f7b1d2d92f7 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -104,6 +104,7 @@ pub mod middle {
     pub mod recursion_limit;
     pub mod resolve_lifetime;
     pub mod stability;
+    pub mod trans;
     pub mod weak_lang_items;
 }
 
diff --git a/src/librustc/middle/trans.rs b/src/librustc/middle/trans.rs
new file mode 100644
index 00000000000..e871a38c4ef
--- /dev/null
+++ b/src/librustc/middle/trans.rs
@@ -0,0 +1,69 @@
+use syntax::ast::NodeId;
+use syntax::symbol::InternedString;
+use ty::Instance;
+use util::nodemap::FxHashMap;
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
+pub enum TransItem<'tcx> {
+    Fn(Instance<'tcx>),
+    Static(NodeId),
+    GlobalAsm(NodeId),
+}
+
+pub struct CodegenUnit<'tcx> {
+    /// A name for this CGU. Incremental compilation requires that
+    /// name be unique amongst **all** crates.  Therefore, it should
+    /// contain something unique to this crate (e.g., a module path)
+    /// as well as the crate name and disambiguator.
+    name: InternedString,
+    items: FxHashMap<TransItem<'tcx>, (Linkage, Visibility)>,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum Linkage {
+    External,
+    AvailableExternally,
+    LinkOnceAny,
+    LinkOnceODR,
+    WeakAny,
+    WeakODR,
+    Appending,
+    Internal,
+    Private,
+    ExternalWeak,
+    Common,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub enum Visibility {
+    Default,
+    Hidden,
+    Protected,
+}
+
+impl<'tcx> CodegenUnit<'tcx> {
+    pub fn new(name: InternedString) -> CodegenUnit<'tcx> {
+        CodegenUnit {
+            name: name,
+            items: FxHashMap(),
+        }
+    }
+
+    pub fn name(&self) -> &InternedString {
+        &self.name
+    }
+
+    pub fn set_name(&mut self, name: InternedString) {
+        self.name = name;
+    }
+
+    pub fn items(&self) -> &FxHashMap<TransItem<'tcx>, (Linkage, Visibility)> {
+        &self.items
+    }
+
+    pub fn items_mut(&mut self)
+        -> &mut FxHashMap<TransItem<'tcx>, (Linkage, Visibility)>
+    {
+        &mut self.items
+    }
+}
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 2d3dc6cd65b..c6fff0071bf 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -24,6 +24,7 @@ use middle::resolve_lifetime::{Region, ObjectLifetimeDefault};
 use middle::stability::{self, DeprecationEntry};
 use middle::lang_items::{LanguageItems, LangItem};
 use middle::exported_symbols::ExportedSymbols;
+use middle::trans::{TransItem, CodegenUnit};
 use mir;
 use mir::transform::{MirSuite, MirPassIndex};
 use session::CompileResult;
@@ -753,6 +754,12 @@ impl<'tcx> QueryDescription for queries::exported_symbol_set<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::collect_and_partition_translation_items<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("collect_and_partition_translation_items")
+    }
+}
+
 // If enabled, send a message to the profile-queries thread
 macro_rules! profq_msg {
     ($tcx:expr, $msg:expr) => {
@@ -1382,6 +1389,9 @@ define_maps! { <'tcx>
 
     [] fn exported_symbol_set: exported_symbol_set_node(CrateNum)
         -> Arc<ExportedSymbols>,
+    [] fn collect_and_partition_translation_items:
+        collect_and_partition_translation_items_node(CrateNum)
+        -> (Arc<FxHashSet<TransItem<'tcx>>>, Vec<Arc<CodegenUnit<'tcx>>>),
 }
 
 fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
@@ -1499,3 +1509,7 @@ fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
 fn exported_symbol_set_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
     DepConstructor::ExportedSymbols
 }
+
+fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+    DepConstructor::CollectAndPartitionTranslationItems
+}
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index ec436bcb241..1eb3e86a15b 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -34,11 +34,11 @@ pub struct LinkerInfo {
 }
 
 impl<'a, 'tcx> LinkerInfo {
-    pub fn new(scx: &SharedCrateContext<'a, 'tcx>,
-               exports: &ExportedSymbols) -> LinkerInfo {
+    pub fn new(scx: &SharedCrateContext<'a, 'tcx>) -> LinkerInfo {
+        let exports = scx.tcx().exported_symbols();
         LinkerInfo {
             exports: scx.sess().crate_types.borrow().iter().map(|&c| {
-                (c, exported_symbols(scx, exports, c))
+                (c, exported_symbols(scx, &exports, c))
             }).collect(),
         }
     }
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 5f8e95b6ca9..7d0e7c21074 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -33,16 +33,18 @@ use back::link;
 use back::linker::LinkerInfo;
 use back::symbol_export;
 use back::write::{self, OngoingCrateTranslation};
-use llvm::{ContextRef, Linkage, ModuleRef, ValueRef, Vector, get_param};
+use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param};
 use llvm;
 use metadata;
-use rustc::hir::def_id::LOCAL_CRATE;
+use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
 use rustc::middle::lang_items::StartFnLangItem;
+use rustc::middle::trans::{Linkage, Visibility};
 use rustc::middle::cstore::{EncodedMetadata, EncodedMetadataHashes};
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::maps::Providers;
 use rustc::dep_graph::AssertDepGraphSafe;
 use rustc::middle::cstore::{self, LinkMeta, LinkagePreference};
-use rustc::middle::exported_symbols::{ExportedSymbols, SymbolExportLevel};
+use rustc::middle::exported_symbols::ExportedSymbols;
 use rustc::hir::map as hir_map;
 use rustc::util::common::{time, print_time_passes_entry};
 use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType};
@@ -68,10 +70,10 @@ use machine;
 use meth;
 use mir;
 use monomorphize::{self, Instance};
-use partitioning::{self, PartitioningStrategy, CodegenUnit};
+use partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt};
 use symbol_names_test;
 use time_graph;
-use trans_item::{TransItem, DefPathBasedNames};
+use trans_item::{TransItem, TransItemExt, DefPathBasedNames};
 use type_::Type;
 use type_of;
 use value::Value;
@@ -615,7 +617,9 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
     mir::trans_mir(ccx, lldecl, &mir, instance, sig);
 }
 
-pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
+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
@@ -625,17 +629,17 @@ pub fn llvm_linkage_by_name(name: &str) -> Option<Linkage> {
     // 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(llvm::Linkage::AppendingLinkage),
-        "available_externally" => Some(llvm::Linkage::AvailableExternallyLinkage),
-        "common" => Some(llvm::Linkage::CommonLinkage),
-        "extern_weak" => Some(llvm::Linkage::ExternalWeakLinkage),
-        "external" => Some(llvm::Linkage::ExternalLinkage),
-        "internal" => Some(llvm::Linkage::InternalLinkage),
-        "linkonce" => Some(llvm::Linkage::LinkOnceAnyLinkage),
-        "linkonce_odr" => Some(llvm::Linkage::LinkOnceODRLinkage),
-        "private" => Some(llvm::Linkage::PrivateLinkage),
-        "weak" => Some(llvm::Linkage::WeakAnyLinkage),
-        "weak_odr" => Some(llvm::Linkage::WeakODRLinkage),
+        "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,
     }
 }
@@ -974,12 +978,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // Skip crate items and just output metadata in -Z no-trans mode.
     if tcx.sess.opts.debugging_opts.no_trans ||
        !tcx.sess.opts.output_types.should_trans() {
-        let empty_exported_symbols = ExportedSymbols::new(
-            SymbolExportLevel::C,
-            Default::default(),
-            Default::default(),
-        );
-        let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols);
+        let linker_info = LinkerInfo::new(&shared_ccx);
         let ongoing_translation = write::start_async_translation(
             tcx.sess,
             output_filenames,
@@ -987,7 +986,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             tcx.crate_name(LOCAL_CRATE),
             link_meta,
             metadata,
-            Arc::new(empty_exported_symbols),
+            shared_ccx.tcx().exported_symbols(),
             no_builtins,
             None,
             linker_info,
@@ -1006,16 +1005,14 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         return ongoing_translation;
     }
 
-    let exported_symbols = tcx.exported_symbols();
-
     // Run the translation item collector and partition the collected items into
     // codegen units.
     let (translation_items, codegen_units) =
-        collect_and_partition_translation_items(shared_ccx.tcx(), &exported_symbols);
+        shared_ccx.tcx().collect_and_partition_translation_items(LOCAL_CRATE);
 
     assert!(codegen_units.len() <= 1 || !tcx.sess.lto());
 
-    let linker_info = LinkerInfo::new(&shared_ccx, &exported_symbols);
+    let linker_info = LinkerInfo::new(&shared_ccx);
     let subsystem = attr::first_attr_value_str_by_name(&krate.attrs,
                                                        "windows_subsystem");
     let windows_subsystem = subsystem.map(|subsystem| {
@@ -1039,7 +1036,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         tcx.crate_name(LOCAL_CRATE),
         link_meta,
         metadata,
-        exported_symbols.clone(),
+        tcx.exported_symbols(),
         no_builtins,
         windows_subsystem,
         linker_info,
@@ -1090,8 +1087,6 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                              metadata_module,
                                                              codegen_unit_count == 0);
 
-    let translation_items = Arc::new(translation_items);
-
     let mut all_stats = Stats::default();
     let mut module_dispositions = tcx.sess.opts.incremental.as_ref().map(|_| Vec::new());
 
@@ -1124,7 +1119,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         AssertDepGraphSafe(&shared_ccx),
                                         AssertDepGraphSafe((cgu,
                                                             translation_items.clone(),
-                                                            exported_symbols.clone())),
+                                                            tcx.exported_symbols())),
                                         module_translation);
             all_stats.extend(stats);
 
@@ -1165,7 +1160,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     fn module_translation<'a, 'tcx>(
         scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>,
-        args: AssertDepGraphSafe<(CodegenUnit<'tcx>,
+        args: AssertDepGraphSafe<(Arc<CodegenUnit<'tcx>>,
                                   Arc<FxHashSet<TransItem<'tcx>>>,
                                   Arc<ExportedSymbols>)>)
         -> (Stats, ModuleTranslation)
@@ -1174,7 +1169,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         let AssertDepGraphSafe(scx) = scx;
         let AssertDepGraphSafe((cgu, crate_trans_items, exported_symbols)) = args;
 
-        let cgu_name = String::from(cgu.name());
+        let cgu_name = cgu.name().to_string();
         let cgu_id = cgu.work_product_id();
         let symbol_name_hash = cgu.compute_symbol_name_hash(scx);
 
@@ -1398,11 +1393,14 @@ fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_i
     }
 }
 
-fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                                     exported_symbols: &ExportedSymbols)
-                                                     -> (FxHashSet<TransItem<'tcx>>,
-                                                         Vec<CodegenUnit<'tcx>>) {
+fn collect_and_partition_translation_items<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    cnum: CrateNum,
+) -> (Arc<FxHashSet<TransItem<'tcx>>>, Vec<Arc<CodegenUnit<'tcx>>>)
+{
+    assert_eq!(cnum, LOCAL_CRATE);
     let time_passes = tcx.sess.time_passes();
+    let exported_symbols = tcx.exported_symbols();
 
     let collection_mode = match tcx.sess.opts.debugging_opts.print_trans_items {
         Some(ref s) => {
@@ -1427,7 +1425,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>
     let (items, inlining_map) =
         time(time_passes, "translation item collection", || {
             collector::collect_crate_translation_items(tcx,
-                                                       exported_symbols,
+                                                       &exported_symbols,
                                                        collection_mode)
     });
 
@@ -1444,7 +1442,10 @@ fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>
                                 items.iter().cloned(),
                                 strategy,
                                 &inlining_map,
-                                exported_symbols)
+                                &exported_symbols)
+            .into_iter()
+            .map(Arc::new)
+            .collect::<Vec<_>>()
     });
 
     assert!(tcx.sess.opts.cg.codegen_units == codegen_units.len() ||
@@ -1477,17 +1478,17 @@ fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>
                     output.push_str(&cgu_name);
 
                     let linkage_abbrev = match linkage {
-                        llvm::Linkage::ExternalLinkage => "External",
-                        llvm::Linkage::AvailableExternallyLinkage => "Available",
-                        llvm::Linkage::LinkOnceAnyLinkage => "OnceAny",
-                        llvm::Linkage::LinkOnceODRLinkage => "OnceODR",
-                        llvm::Linkage::WeakAnyLinkage => "WeakAny",
-                        llvm::Linkage::WeakODRLinkage => "WeakODR",
-                        llvm::Linkage::AppendingLinkage => "Appending",
-                        llvm::Linkage::InternalLinkage => "Internal",
-                        llvm::Linkage::PrivateLinkage => "Private",
-                        llvm::Linkage::ExternalWeakLinkage => "ExternalWeak",
-                        llvm::Linkage::CommonLinkage => "Common",
+                        Linkage::External => "External",
+                        Linkage::AvailableExternally => "Available",
+                        Linkage::LinkOnceAny => "OnceAny",
+                        Linkage::LinkOnceODR => "OnceODR",
+                        Linkage::WeakAny => "WeakAny",
+                        Linkage::WeakODR => "WeakODR",
+                        Linkage::Appending => "Appending",
+                        Linkage::Internal => "Internal",
+                        Linkage::Private => "Private",
+                        Linkage::ExternalWeak => "ExternalWeak",
+                        Linkage::Common => "Common",
                     };
 
                     output.push_str("[");
@@ -1505,7 +1506,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>
         }
     }
 
-    (translation_items, codegen_units)
+    (Arc::new(translation_items), codegen_units)
 }
 
 impl CrateInfo {
@@ -1550,3 +1551,32 @@ impl CrateInfo {
         return info
     }
 }
+
+pub fn provide(providers: &mut Providers) {
+    providers.collect_and_partition_translation_items =
+        collect_and_partition_translation_items;
+}
+
+pub fn linkage_to_llvm(linkage: Linkage) -> llvm::Linkage {
+    match linkage {
+        Linkage::External => llvm::Linkage::ExternalLinkage,
+        Linkage::AvailableExternally => llvm::Linkage::AvailableExternallyLinkage,
+        Linkage::LinkOnceAny => llvm::Linkage::LinkOnceAnyLinkage,
+        Linkage::LinkOnceODR => llvm::Linkage::LinkOnceODRLinkage,
+        Linkage::WeakAny => llvm::Linkage::WeakAnyLinkage,
+        Linkage::WeakODR => llvm::Linkage::WeakODRLinkage,
+        Linkage::Appending => llvm::Linkage::AppendingLinkage,
+        Linkage::Internal => llvm::Linkage::InternalLinkage,
+        Linkage::Private => llvm::Linkage::PrivateLinkage,
+        Linkage::ExternalWeak => llvm::Linkage::ExternalWeakLinkage,
+        Linkage::Common => llvm::Linkage::CommonLinkage,
+    }
+}
+
+pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility {
+    match linkage {
+        Visibility::Default => llvm::Visibility::Default,
+        Visibility::Hidden => llvm::Visibility::Hidden,
+        Visibility::Protected => llvm::Visibility::Protected,
+    }
+}
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index ff550d10c6d..a45bcb51ab5 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -207,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, DefPathBasedNames, InstantiationMode};
+use trans_item::{TransItem, TransItemExt, DefPathBasedNames, InstantiationMode};
 
 use rustc_data_structures::bitvec::BitVector;
 
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index a566cddde56..4f78e77fc69 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -16,7 +16,7 @@ use rustc::hir::map as hir_map;
 use rustc::middle::const_val::ConstEvalErr;
 use {debuginfo, machine};
 use base;
-use trans_item::TransItem;
+use trans_item::{TransItem, TransItemExt};
 use common::{self, CrateContext, val_ty};
 use declare;
 use monomorphize::Instance;
@@ -150,7 +150,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
                     // extern "C" fn() from being non-null, so we can't just declare a
                     // static and call it a day. Some linkages (like weak) will make it such
                     // that the static actually has a null value.
-                    let linkage = match base::llvm_linkage_by_name(&name.as_str()) {
+                    let linkage = match base::linkage_by_name(&name.as_str()) {
                         Some(linkage) => linkage,
                         None => {
                             ccx.sess().span_fatal(span, "invalid linkage specified");
@@ -165,7 +165,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
                     unsafe {
                         // Declare a symbol `foo` with the desired linkage.
                         let g1 = declare::declare_global(ccx, &sym, llty2);
-                        llvm::LLVMRustSetLinkage(g1, linkage);
+                        llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage));
 
                         // Declare an internal global `extern_with_linkage_foo` which
                         // is initialized with the address of `foo`.  If `foo` is
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 94695b4e046..7a2db29705d 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -93,7 +93,7 @@ pub struct LocalCrateContext<'a, 'tcx: 'a> {
     llmod: ModuleRef,
     llcx: ContextRef,
     stats: Stats,
-    codegen_unit: CodegenUnit<'tcx>,
+    codegen_unit: Arc<CodegenUnit<'tcx>>,
 
     /// The translation items of the whole crate.
     crate_trans_items: Arc<FxHashSet<TransItem<'tcx>>>,
@@ -330,7 +330,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
         common::type_is_freeze(self.tcx, ty)
     }
 
-    pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
+    pub fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> {
         self.tcx
     }
 
@@ -353,7 +353,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
 
 impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
     pub fn new(shared: &SharedCrateContext<'a, 'tcx>,
-               codegen_unit: CodegenUnit<'tcx>,
+               codegen_unit: Arc<CodegenUnit<'tcx>>,
                crate_trans_items: Arc<FxHashSet<TransItem<'tcx>>>,
                exported_symbols: Arc<ExportedSymbols>,)
                -> LocalCrateContext<'a, 'tcx> {
@@ -465,7 +465,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         self.local_ccx
     }
 
-    pub fn tcx<'a>(&'a self) -> TyCtxt<'a, 'tcx, 'tcx> {
+    pub fn tcx(&self) -> TyCtxt<'b, 'tcx, 'tcx> {
         self.shared.tcx
     }
 
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 8c8bd6a5e50..701c7be8ad6 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -251,6 +251,7 @@ __build_diagnostic_array! { librustc_trans, DIAGNOSTICS }
 
 pub fn provide_local(providers: &mut Providers) {
     back::symbol_names::provide(providers);
+    base::provide(providers);
     providers.exported_symbol_set = |tcx, cnum| {
         assert_eq!(cnum, LOCAL_CRATE);
         Arc::new(back::symbol_export::compute(tcx))
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index d47739b906c..d4aecb9e56c 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -105,11 +105,11 @@
 use collector::InliningMap;
 use common;
 use context::SharedCrateContext;
-use llvm;
 use rustc::dep_graph::{DepNode, WorkProductId};
 use rustc::hir::def_id::DefId;
 use rustc::hir::map::DefPathData;
 use rustc::middle::exported_symbols::ExportedSymbols;
+use rustc::middle::trans::{Linkage, Visibility};
 use rustc::session::config::NUMBERED_CODEGEN_UNIT_MARKER;
 use rustc::ty::{self, TyCtxt, InstanceDef};
 use rustc::ty::item_path::characteristic_def_id_of_type;
@@ -119,7 +119,9 @@ use std::collections::hash_map::Entry;
 use std::hash::Hash;
 use syntax::ast::NodeId;
 use syntax::symbol::{Symbol, InternedString};
-use trans_item::{TransItem, InstantiationMode};
+use trans_item::{TransItem, TransItemExt, InstantiationMode};
+
+pub use rustc::middle::trans::CodegenUnit;
 
 pub enum PartitioningStrategy {
     /// Generate one codegen unit per source-level module.
@@ -129,53 +131,34 @@ pub enum PartitioningStrategy {
     FixedUnitCount(usize)
 }
 
-pub struct CodegenUnit<'tcx> {
-    /// A name for this CGU. Incremental compilation requires that
-    /// name be unique amongst **all** crates.  Therefore, it should
-    /// contain something unique to this crate (e.g., a module path)
-    /// as well as the crate name and disambiguator.
-    name: InternedString,
-
-    items: FxHashMap<TransItem<'tcx>, (llvm::Linkage, llvm::Visibility)>,
-}
-
-impl<'tcx> CodegenUnit<'tcx> {
-    pub fn new(name: InternedString,
-               items: FxHashMap<TransItem<'tcx>, (llvm::Linkage, llvm::Visibility)>)
-               -> Self {
-        CodegenUnit {
-            name,
-            items,
-        }
-    }
+pub trait CodegenUnitExt<'tcx> {
+    fn as_codegen_unit(&self) -> &CodegenUnit<'tcx>;
 
-    pub fn empty(name: InternedString) -> Self {
-        Self::new(name, FxHashMap())
+    fn contains_item(&self, item: &TransItem<'tcx>) -> bool {
+        self.items().contains_key(item)
     }
 
-    pub fn contains_item(&self, item: &TransItem<'tcx>) -> bool {
-        self.items.contains_key(item)
+    fn name<'a>(&'a self) -> &'a InternedString
+        where 'tcx: 'a,
+    {
+        &self.as_codegen_unit().name()
     }
 
-    pub fn name(&self) -> &str {
-        &self.name
+    fn items(&self) -> &FxHashMap<TransItem<'tcx>, (Linkage, Visibility)> {
+        &self.as_codegen_unit().items()
     }
 
-    pub fn items(&self) -> &FxHashMap<TransItem<'tcx>, (llvm::Linkage, llvm::Visibility)> {
-        &self.items
-    }
-
-    pub fn work_product_id(&self) -> WorkProductId {
+    fn work_product_id(&self) -> WorkProductId {
         WorkProductId::from_cgu_name(self.name())
     }
 
-    pub fn work_product_dep_node(&self) -> DepNode {
+    fn work_product_dep_node(&self) -> DepNode {
         self.work_product_id().to_dep_node()
     }
 
-    pub fn compute_symbol_name_hash<'a>(&self,
-                                        scx: &SharedCrateContext<'a, 'tcx>)
-                                        -> u64 {
+    fn compute_symbol_name_hash<'a>(&self,
+                                    scx: &SharedCrateContext<'a, 'tcx>)
+                                    -> u64 {
         let mut state = IchHasher::new();
         let all_items = self.items_in_deterministic_order(scx.tcx());
         for (item, (linkage, visibility)) in all_items {
@@ -188,10 +171,10 @@ impl<'tcx> CodegenUnit<'tcx> {
         state.finish().to_smaller_hash()
     }
 
-    pub fn items_in_deterministic_order<'a>(&self,
-                                            tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                                            -> Vec<(TransItem<'tcx>,
-                                                   (llvm::Linkage, llvm::Visibility))> {
+    fn items_in_deterministic_order<'a>(&self,
+                                        tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                                        -> Vec<(TransItem<'tcx>,
+                                               (Linkage, Visibility))> {
         // The codegen tests rely on items being process in the same order as
         // they appear in the file, so for local items, we sort by node_id first
         #[derive(PartialEq, Eq, PartialOrd, Ord)]
@@ -209,7 +192,7 @@ impl<'tcx> CodegenUnit<'tcx> {
             }, item.symbol_name(tcx))
         }
 
-        let items: Vec<_> = self.items.iter().map(|(&i, &l)| (i, l)).collect();
+        let items: Vec<_> = self.items().iter().map(|(&i, &l)| (i, l)).collect();
         let mut items : Vec<_> = items.iter()
             .map(|il| (il, item_sort_key(tcx, il.0))).collect();
         items.sort_by(|&(_, ref key1), &(_, ref key2)| key1.cmp(key2));
@@ -217,6 +200,11 @@ impl<'tcx> CodegenUnit<'tcx> {
     }
 }
 
+impl<'tcx> CodegenUnitExt<'tcx> for CodegenUnit<'tcx> {
+    fn as_codegen_unit(&self) -> &CodegenUnit<'tcx> {
+        self
+    }
+}
 
 // Anything we can't find a proper codegen unit for goes into this.
 const FALLBACK_CODEGEN_UNIT: &'static str = "__rustc_fallback_codegen_unit";
@@ -267,7 +255,7 @@ pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     } = post_inlining;
 
     result.sort_by(|cgu1, cgu2| {
-        (&cgu1.name[..]).cmp(&cgu2.name[..])
+        cgu1.name().cmp(cgu2.name())
     });
 
     if tcx.sess.opts.enable_dep_node_debug_strs() {
@@ -329,14 +317,14 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
             };
 
             let make_codegen_unit = || {
-                CodegenUnit::empty(codegen_unit_name.clone())
+                CodegenUnit::new(codegen_unit_name.clone())
             };
 
             let codegen_unit = codegen_units.entry(codegen_unit_name.clone())
                                                 .or_insert_with(make_codegen_unit);
 
             let (linkage, visibility) = match trans_item.explicit_linkage(tcx) {
-                Some(explicit_linkage) => (explicit_linkage, llvm::Visibility::Default),
+                Some(explicit_linkage) => (explicit_linkage, Visibility::Default),
                 None => {
                     match trans_item {
                         TransItem::Fn(ref instance) => {
@@ -344,14 +332,14 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 InstanceDef::Item(def_id) => {
                                     if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
                                         if exported_symbols.contains(&node_id) {
-                                            llvm::Visibility::Default
+                                            Visibility::Default
                                         } else {
                                             internalization_candidates.insert(trans_item);
-                                            llvm::Visibility::Hidden
+                                            Visibility::Hidden
                                         }
                                     } else {
                                         internalization_candidates.insert(trans_item);
-                                        llvm::Visibility::Hidden
+                                        Visibility::Hidden
                                     }
                                 }
                                 InstanceDef::FnPtrShim(..) |
@@ -365,23 +353,23 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                           trans_item)
                                 }
                             };
-                            (llvm::ExternalLinkage, visibility)
+                            (Linkage::External, visibility)
                         }
                         TransItem::Static(node_id) |
                         TransItem::GlobalAsm(node_id) => {
                             let visibility = if exported_symbols.contains(&node_id) {
-                                llvm::Visibility::Default
+                                Visibility::Default
                             } else {
                                 internalization_candidates.insert(trans_item);
-                                llvm::Visibility::Hidden
+                                Visibility::Hidden
                             };
-                            (llvm::ExternalLinkage, visibility)
+                            (Linkage::External, visibility)
                         }
                     }
                 }
             };
 
-            codegen_unit.items.insert(trans_item, (linkage, visibility));
+            codegen_unit.items_mut().insert(trans_item, (linkage, visibility));
             roots.insert(trans_item);
         }
     }
@@ -391,7 +379,7 @@ fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     if codegen_units.is_empty() {
         let codegen_unit_name = Symbol::intern(FALLBACK_CODEGEN_UNIT).as_str();
         codegen_units.insert(codegen_unit_name.clone(),
-                             CodegenUnit::empty(codegen_unit_name.clone()));
+                             CodegenUnit::new(codegen_unit_name.clone()));
     }
 
     PreInliningPartitioning {
@@ -414,17 +402,17 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<
     // translation items in a given unit. This could be improved on.
     while codegen_units.len() > target_cgu_count {
         // Sort small cgus to the back
-        codegen_units.sort_by_key(|cgu| -(cgu.items.len() as i64));
-        let smallest = codegen_units.pop().unwrap();
+        codegen_units.sort_by_key(|cgu| -(cgu.items().len() as i64));
+        let mut smallest = codegen_units.pop().unwrap();
         let second_smallest = codegen_units.last_mut().unwrap();
 
-        for (k, v) in smallest.items.into_iter() {
-            second_smallest.items.insert(k, v);
+        for (k, v) in smallest.items_mut().drain() {
+            second_smallest.items_mut().insert(k, v);
         }
     }
 
     for (index, cgu) in codegen_units.iter_mut().enumerate() {
-        cgu.name = numbered_codegen_unit_name(crate_name, index);
+        cgu.set_name(numbered_codegen_unit_name(crate_name, index));
     }
 
     // If the initial partitioning contained less than target_cgu_count to begin
@@ -432,8 +420,8 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<
     // we reach the target count
     while codegen_units.len() < target_cgu_count {
         let index = codegen_units.len();
-        codegen_units.push(
-            CodegenUnit::empty(numbered_codegen_unit_name(crate_name, index)));
+        let name = numbered_codegen_unit_name(crate_name, index);
+        codegen_units.push(CodegenUnit::new(name));
     }
 }
 
@@ -454,20 +442,17 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit
     for old_codegen_unit in initial_cgus {
         // Collect all items that need to be available in this codegen unit
         let mut reachable = FxHashSet();
-        for root in old_codegen_unit.items.keys() {
+        for root in old_codegen_unit.items().keys() {
             follow_inlining(*root, inlining_map, &mut reachable);
         }
 
-        let mut new_codegen_unit = CodegenUnit {
-            name: old_codegen_unit.name,
-            items: FxHashMap(),
-        };
+        let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name().clone());
 
         // Add all translation items that are not already there
         for trans_item in reachable {
-            if let Some(linkage) = old_codegen_unit.items.get(&trans_item) {
+            if let Some(linkage) = old_codegen_unit.items().get(&trans_item) {
                 // This is a root, just copy it over
-                new_codegen_unit.items.insert(trans_item, *linkage);
+                new_codegen_unit.items_mut().insert(trans_item, *linkage);
             } else {
                 if roots.contains(&trans_item) {
                     bug!("GloballyShared trans-item inlined into other CGU: \
@@ -475,8 +460,10 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit
                 }
 
                 // This is a cgu-private copy
-                new_codegen_unit.items.insert(trans_item,
-                                              (llvm::InternalLinkage, llvm::Visibility::Default));
+                new_codegen_unit.items_mut().insert(
+                    trans_item,
+                    (Linkage::Internal, Visibility::Default),
+                );
             }
 
             if !single_codegen_unit {
@@ -487,7 +474,7 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit
                         let placement = e.into_mut();
                         debug_assert!(match *placement {
                             TransItemPlacement::SingleCgu { ref cgu_name } => {
-                                *cgu_name != new_codegen_unit.name
+                                *cgu_name != *new_codegen_unit.name()
                             }
                             TransItemPlacement::MultipleCgus => true,
                         });
@@ -495,7 +482,7 @@ fn place_inlined_translation_items<'tcx>(initial_partitioning: PreInliningPartit
                     }
                     Entry::Vacant(e) => {
                         e.insert(TransItemPlacement::SingleCgu {
-                            cgu_name: new_codegen_unit.name.clone()
+                            cgu_name: new_codegen_unit.name().clone()
                         });
                     }
                 }
@@ -533,8 +520,8 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // could be accessed from.
         for cgu in &mut partitioning.codegen_units {
             for candidate in &partitioning.internalization_candidates {
-                cgu.items.insert(*candidate, (llvm::InternalLinkage,
-                                              llvm::Visibility::Default));
+                cgu.items_mut().insert(*candidate,
+                                       (Linkage::Internal, Visibility::Default));
             }
         }
 
@@ -558,10 +545,10 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>,
     // accessed from outside its defining codegen unit.
     for cgu in &mut partitioning.codegen_units {
         let home_cgu = TransItemPlacement::SingleCgu {
-            cgu_name: cgu.name.clone()
+            cgu_name: cgu.name().clone()
         };
 
-        for (accessee, linkage_and_visibility) in &mut cgu.items {
+        for (accessee, linkage_and_visibility) in cgu.items_mut() {
             if !partitioning.internalization_candidates.contains(accessee) {
                 // This item is no candidate for internalizing, so skip it.
                 continue
@@ -584,7 +571,7 @@ fn internalize_symbols<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
             // If we got here, we did not find any accesses from other CGUs,
             // so it's fine to make this translation item internal.
-            *linkage_and_visibility = (llvm::InternalLinkage, llvm::Visibility::Default);
+            *linkage_and_visibility = (Linkage::Internal, Visibility::Default);
         }
     }
 }
@@ -675,9 +662,9 @@ fn debug_dump<'a, 'b, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     if cfg!(debug_assertions) {
         debug!("{}", label);
         for cgu in cgus {
-            debug!("CodegenUnit {}:", cgu.name);
+            debug!("CodegenUnit {}:", cgu.name());
 
-            for (trans_item, linkage) in &cgu.items {
+            for (trans_item, linkage) in cgu.items() {
                 let symbol_name = trans_item.symbol_name(tcx);
                 let symbol_hash_start = symbol_name.rfind('h');
                 let symbol_hash = symbol_hash_start.map(|i| &symbol_name[i ..])
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 5a51f690c45..526b61303e1 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -25,23 +25,19 @@ use llvm;
 use monomorphize::Instance;
 use rustc::hir;
 use rustc::hir::def_id::DefId;
+use rustc::middle::trans::{Linkage, Visibility};
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::subst::{Subst, Substs};
-use syntax::ast::{self, NodeId};
+use syntax::ast;
 use syntax::attr;
 use syntax_pos::Span;
 use syntax_pos::symbol::Symbol;
 use type_of;
-use std::fmt::Write;
+use std::fmt::{self, Write};
 use std::iter;
 
-#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
-pub enum TransItem<'tcx> {
-    Fn(Instance<'tcx>),
-    Static(NodeId),
-    GlobalAsm(NodeId),
-}
+pub use rustc::middle::trans::TransItem;
 
 /// Describes how a translation item will be instantiated in object files.
 #[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
@@ -55,15 +51,16 @@ pub enum InstantiationMode {
     LocalCopy,
 }
 
-impl<'a, 'tcx> TransItem<'tcx> {
+pub trait TransItemExt<'a, 'tcx>: fmt::Debug {
+    fn as_trans_item(&self) -> &TransItem<'tcx>;
 
-    pub fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
+    fn define(&self, ccx: &CrateContext<'a, 'tcx>) {
         debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}",
-                  self.to_string(ccx.tcx()),
-                  self.to_raw_string(),
-                  ccx.codegen_unit().name());
+               self.to_string(ccx.tcx()),
+               self.to_raw_string(),
+               ccx.codegen_unit().name());
 
-        match *self {
+        match *self.as_trans_item() {
             TransItem::Static(node_id) => {
                 let tcx = ccx.tcx();
                 let item = tcx.hir.expect_item(node_id);
@@ -97,10 +94,10 @@ impl<'a, 'tcx> TransItem<'tcx> {
                ccx.codegen_unit().name());
     }
 
-    pub fn predefine(&self,
-                     ccx: &CrateContext<'a, 'tcx>,
-                     linkage: llvm::Linkage,
-                     visibility: llvm::Visibility) {
+    fn predefine(&self,
+                 ccx: &CrateContext<'a, 'tcx>,
+                 linkage: Linkage,
+                 visibility: Visibility) {
         debug!("BEGIN PREDEFINING '{} ({})' in cgu {}",
                self.to_string(ccx.tcx()),
                self.to_raw_string(),
@@ -110,12 +107,12 @@ impl<'a, 'tcx> TransItem<'tcx> {
 
         debug!("symbol {}", &symbol_name);
 
-        match *self {
+        match *self.as_trans_item() {
             TransItem::Static(node_id) => {
-                TransItem::predefine_static(ccx, node_id, linkage, visibility, &symbol_name);
+                predefine_static(ccx, node_id, linkage, visibility, &symbol_name);
             }
             TransItem::Fn(instance) => {
-                TransItem::predefine_fn(ccx, instance, linkage, visibility, &symbol_name);
+                predefine_fn(ccx, instance, linkage, visibility, &symbol_name);
             }
             TransItem::GlobalAsm(..) => {}
         }
@@ -126,75 +123,8 @@ impl<'a, 'tcx> TransItem<'tcx> {
                ccx.codegen_unit().name());
     }
 
-    fn predefine_static(ccx: &CrateContext<'a, 'tcx>,
-                        node_id: ast::NodeId,
-                        linkage: llvm::Linkage,
-                        visibility: llvm::Visibility,
-                        symbol_name: &str) {
-        let def_id = ccx.tcx().hir.local_def_id(node_id);
-        let instance = Instance::mono(ccx.tcx(), def_id);
-        let ty = common::instance_ty(ccx.tcx(), &instance);
-        let llty = type_of::type_of(ccx, ty);
-
-        let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| {
-            ccx.sess().span_fatal(ccx.tcx().hir.span(node_id),
-                &format!("symbol `{}` is already defined", symbol_name))
-        });
-
-        unsafe {
-            llvm::LLVMRustSetLinkage(g, linkage);
-            llvm::LLVMRustSetVisibility(g, visibility);
-        }
-
-        ccx.instances().borrow_mut().insert(instance, g);
-        ccx.statics().borrow_mut().insert(g, def_id);
-    }
-
-    fn predefine_fn(ccx: &CrateContext<'a, 'tcx>,
-                    instance: Instance<'tcx>,
-                    linkage: llvm::Linkage,
-                    visibility: llvm::Visibility,
-                    symbol_name: &str) {
-        assert!(!instance.substs.needs_infer() &&
-                !instance.substs.has_param_types());
-
-        let mono_ty = common::instance_ty(ccx.tcx(), &instance);
-        let attrs = instance.def.attrs(ccx.tcx());
-        let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty);
-        unsafe { llvm::LLVMRustSetLinkage(lldecl, linkage) };
-        base::set_link_section(ccx, lldecl, &attrs);
-        if linkage == llvm::Linkage::LinkOnceODRLinkage ||
-            linkage == llvm::Linkage::WeakODRLinkage {
-            llvm::SetUniqueComdat(ccx.llmod(), lldecl);
-        }
-
-        // If we're compiling the compiler-builtins crate, e.g. the equivalent of
-        // compiler-rt, then we want to implicitly compile everything with hidden
-        // visibility as we're going to link this object all over the place but
-        // don't want the symbols to get exported.
-        if linkage != llvm::Linkage::InternalLinkage &&
-           linkage != llvm::Linkage::PrivateLinkage &&
-           attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") {
-            unsafe {
-                llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden);
-            }
-        } else {
-            unsafe {
-                llvm::LLVMRustSetVisibility(lldecl, visibility);
-            }
-        }
-
-        debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance);
-        if common::is_inline_instance(ccx.tcx(), &instance) {
-            attributes::inline(lldecl, attributes::InlineAttr::Hint);
-        }
-        attributes::from_fn_attrs(ccx, &attrs, lldecl);
-
-        ccx.instances().borrow_mut().insert(instance, lldecl);
-    }
-
-    pub fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::SymbolName {
-        match *self {
+    fn symbol_name(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::SymbolName {
+        match *self.as_trans_item() {
             TransItem::Fn(instance) => tcx.symbol_name(instance),
             TransItem::Static(node_id) => {
                 let def_id = tcx.hir.local_def_id(node_id);
@@ -209,8 +139,8 @@ impl<'a, 'tcx> TransItem<'tcx> {
         }
     }
 
-    pub fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Span> {
-        match *self {
+    fn local_span(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<Span> {
+        match *self.as_trans_item() {
             TransItem::Fn(Instance { def, .. }) => {
                 tcx.hir.as_local_node_id(def.def_id())
             }
@@ -221,10 +151,10 @@ impl<'a, 'tcx> TransItem<'tcx> {
         }.map(|node_id| tcx.hir.span(node_id))
     }
 
-    pub fn instantiation_mode(&self,
-                              tcx: TyCtxt<'a, 'tcx, 'tcx>)
-                              -> InstantiationMode {
-        match *self {
+    fn instantiation_mode(&self,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>)
+                          -> InstantiationMode {
+        match *self.as_trans_item() {
             TransItem::Fn(ref instance) => {
                 if self.explicit_linkage(tcx).is_none() &&
                     common::requests_inline(tcx, instance)
@@ -239,8 +169,8 @@ impl<'a, 'tcx> TransItem<'tcx> {
         }
     }
 
-    pub fn is_generic_fn(&self) -> bool {
-        match *self {
+    fn is_generic_fn(&self) -> bool {
+        match *self.as_trans_item() {
             TransItem::Fn(ref instance) => {
                 instance.substs.types().next().is_some()
             }
@@ -249,8 +179,8 @@ impl<'a, 'tcx> TransItem<'tcx> {
         }
     }
 
-    pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<llvm::Linkage> {
-        let def_id = match *self {
+    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,
@@ -258,7 +188,7 @@ impl<'a, 'tcx> TransItem<'tcx> {
 
         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::llvm_linkage_by_name(&name.as_str()) {
+            if let Some(linkage) = base::linkage_by_name(&name.as_str()) {
                 Some(linkage)
             } else {
                 let span = tcx.hir.span_if_local(def_id);
@@ -298,9 +228,9 @@ impl<'a, 'tcx> TransItem<'tcx> {
     /// 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.
-    pub fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
+    fn is_instantiable(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
         debug!("is_instantiable({:?})", self);
-        let (def_id, substs) = match *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
@@ -311,10 +241,10 @@ impl<'a, 'tcx> TransItem<'tcx> {
         traits::normalize_and_test_predicates(tcx, predicates)
     }
 
-    pub fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
+    fn to_string(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
         let hir_map = &tcx.hir;
 
-        return match *self {
+        return match *self.as_trans_item() {
             TransItem::Fn(instance) => {
                 to_string_internal(tcx, "fn ", instance)
             },
@@ -340,8 +270,8 @@ impl<'a, 'tcx> TransItem<'tcx> {
         }
     }
 
-    pub fn to_raw_string(&self) -> String {
-        match *self {
+    fn to_raw_string(&self) -> String {
+        match *self.as_trans_item() {
             TransItem::Fn(instance) => {
                 format!("Fn({:?}, {})",
                          instance.def,
@@ -357,6 +287,77 @@ impl<'a, 'tcx> TransItem<'tcx> {
     }
 }
 
+impl<'a, 'tcx> TransItemExt<'a, 'tcx> for TransItem<'tcx> {
+    fn as_trans_item(&self) -> &TransItem<'tcx> {
+        self
+    }
+}
+
+fn predefine_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                              node_id: ast::NodeId,
+                              linkage: Linkage,
+                              visibility: Visibility,
+                              symbol_name: &str) {
+    let def_id = ccx.tcx().hir.local_def_id(node_id);
+    let instance = Instance::mono(ccx.tcx(), def_id);
+    let ty = common::instance_ty(ccx.tcx(), &instance);
+    let llty = type_of::type_of(ccx, ty);
+
+    let g = declare::define_global(ccx, symbol_name, llty).unwrap_or_else(|| {
+        ccx.sess().span_fatal(ccx.tcx().hir.span(node_id),
+            &format!("symbol `{}` is already defined", symbol_name))
+    });
+
+    unsafe {
+        llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage));
+        llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility));
+    }
+
+    ccx.instances().borrow_mut().insert(instance, g);
+    ccx.statics().borrow_mut().insert(g, def_id);
+}
+
+fn predefine_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                          instance: Instance<'tcx>,
+                          linkage: Linkage,
+                          visibility: Visibility,
+                          symbol_name: &str) {
+    assert!(!instance.substs.needs_infer() &&
+            !instance.substs.has_param_types());
+
+    let mono_ty = common::instance_ty(ccx.tcx(), &instance);
+    let attrs = instance.def.attrs(ccx.tcx());
+    let lldecl = declare::declare_fn(ccx, symbol_name, mono_ty);
+    unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
+    base::set_link_section(ccx, lldecl, &attrs);
+    if linkage == Linkage::LinkOnceODR ||
+        linkage == Linkage::WeakODR {
+        llvm::SetUniqueComdat(ccx.llmod(), lldecl);
+    }
+
+    // If we're compiling the compiler-builtins crate, e.g. the equivalent of
+    // compiler-rt, then we want to implicitly compile everything with hidden
+    // visibility as we're going to link this object all over the place but
+    // don't want the symbols to get exported.
+    if linkage != Linkage::Internal && linkage != Linkage::Private &&
+       attr::contains_name(ccx.tcx().hir.krate_attrs(), "compiler_builtins") {
+        unsafe {
+            llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden);
+        }
+    } else {
+        unsafe {
+            llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility));
+        }
+    }
+
+    debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance);
+    if common::is_inline_instance(ccx.tcx(), &instance) {
+        attributes::inline(lldecl, attributes::InlineAttr::Hint);
+    }
+    attributes::from_fn_attrs(ccx, &attrs, lldecl);
+
+    ccx.instances().borrow_mut().insert(instance, lldecl);
+}
 
 //=-----------------------------------------------------------------------------
 // TransItem String Keys