about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-09-17 22:05:31 +0000
committerbors <bors@rust-lang.org>2017-09-17 22:05:31 +0000
commite8a76d8accf04047a938ba43b32d5ff9ab581715 (patch)
tree9c8a37e523ef8300f9600dd73a84018f742bca85
parentcfcac37204c8dbdde192c1c9387cdbe663fe5ed5 (diff)
parent6d614ddc2ebc25d3987b1efc84c0c7fea00ce325 (diff)
downloadrust-e8a76d8accf04047a938ba43b32d5ff9ab581715.tar.gz
rust-e8a76d8accf04047a938ba43b32d5ff9ab581715.zip
Auto merge of #44529 - alexcrichton:trans-query, r=michaelwoerister
Refactor translation unit partitioning/collection as a query

This commit is targeted at #44486 with the ultimate goal of making the `collect_and_partition_translation_items` function a query. This mostly just involved query-ifying a few other systems along with plumbing the tcx instead of `SharedCrateContext` in a few locations.

Currently this only tackles the first bullet of #44486 and doesn't add a dedicated query for a particular codegen unit. I wasn't quite sure how to do that yet but figured this was good to put up.

Closes #44486
-rw-r--r--src/librustc/dep_graph/dep_node.rs11
-rw-r--r--src/librustc/lib.rs2
-rw-r--r--src/librustc/middle/cstore.rs5
-rw-r--r--src/librustc/middle/exported_symbols.rs31
-rw-r--r--src/librustc/middle/reachable.rs8
-rw-r--r--src/librustc/middle/trans.rs110
-rw-r--r--src/librustc/ty/context.rs21
-rw-r--r--src/librustc/ty/maps.rs69
-rw-r--r--src/librustc/ty/mod.rs1
-rw-r--r--src/librustc_driver/driver.rs52
-rw-r--r--src/librustc_driver/lib.rs1
-rw-r--r--src/librustc_driver/pretty.rs14
-rw-r--r--src/librustc_driver/test.rs14
-rw-r--r--src/librustc_metadata/cstore_impl.rs2
-rw-r--r--src/librustc_metadata/decoder.rs3
-rw-r--r--src/librustc_trans/abi.rs2
-rw-r--r--src/librustc_trans/back/linker.rs49
-rw-r--r--src/librustc_trans/back/lto.rs14
-rw-r--r--src/librustc_trans/back/symbol_export.rs289
-rw-r--r--src/librustc_trans/back/symbol_names.rs26
-rw-r--r--src/librustc_trans/back/write.rs298
-rw-r--r--src/librustc_trans/base.rs663
-rw-r--r--src/librustc_trans/builder.rs9
-rw-r--r--src/librustc_trans/callee.rs91
-rw-r--r--src/librustc_trans/collector.rs200
-rw-r--r--src/librustc_trans/common.rs27
-rw-r--r--src/librustc_trans/consts.rs12
-rw-r--r--src/librustc_trans/context.rs96
-rw-r--r--src/librustc_trans/debuginfo/metadata.rs6
-rw-r--r--src/librustc_trans/debuginfo/mod.rs2
-rw-r--r--src/librustc_trans/debuginfo/utils.rs3
-rw-r--r--src/librustc_trans/diagnostics.rs24
-rw-r--r--src/librustc_trans/glue.rs10
-rw-r--r--src/librustc_trans/lib.rs20
-rw-r--r--src/librustc_trans/meth.rs2
-rw-r--r--src/librustc_trans/mir/block.rs6
-rw-r--r--src/librustc_trans/mir/constant.rs2
-rw-r--r--src/librustc_trans/mir/rvalue.rs2
-rw-r--r--src/librustc_trans/monomorphize.rs51
-rw-r--r--src/librustc_trans/partitioning.rs181
-rw-r--r--src/librustc_trans/trans_item.rs215
-rw-r--r--src/librustdoc/core.rs8
-rw-r--r--src/libsyntax/attr.rs24
-rw-r--r--src/libsyntax/diagnostic_list.rs23
44 files changed, 1452 insertions, 1247 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 27561bddd29..06469c16bc2 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -71,6 +71,7 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable};
 use ich::StableHashingContext;
 use std::fmt;
 use std::hash::Hash;
+use syntax_pos::symbol::InternedString;
 
 // erase!() just makes tokens go away. It's used to specify which macro argument
 // is repeated (i.e. which sub-expression of the macro we are in) but don't need
@@ -535,7 +536,7 @@ define_dep_nodes!( <'tcx>
     [] GetPanicStrategy(CrateNum),
     [] IsNoBuiltins(CrateNum),
     [] ImplDefaultness(DefId),
-    [] ExportedSymbols(CrateNum),
+    [] ExportedSymbolIds(CrateNum),
     [] NativeLibraries(CrateNum),
     [] PluginRegistrarFn(CrateNum),
     [] DeriveRegistrarFn(CrateNum),
@@ -575,6 +576,14 @@ define_dep_nodes!( <'tcx>
     [] MaybeUnusedExternCrates,
     [] StabilityIndex,
     [] AllCrateNums,
+    [] ExportedSymbols(CrateNum),
+    [] CollectAndPartitionTranslationItems,
+    [] ExportName(DefId),
+    [] ContainsExternIndicator(DefId),
+    [] IsTranslatedFunction(DefId),
+    [] CodegenUnit(InternedString),
+    [] CompileCodegenUnit(InternedString),
+    [] OutputFilenames,
 );
 
 trait DepNodeParams<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> : fmt::Debug {
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index df97f2fb8bc..f7b1d2d92f7 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -92,6 +92,7 @@ pub mod middle {
     pub mod dependency_format;
     pub mod effect;
     pub mod entry;
+    pub mod exported_symbols;
     pub mod free_region;
     pub mod intrinsicck;
     pub mod lang_items;
@@ -103,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/cstore.rs b/src/librustc/middle/cstore.rs
index a7d874386d1..bea6ef4dc11 100644
--- a/src/librustc/middle/cstore.rs
+++ b/src/librustc/middle/cstore.rs
@@ -366,8 +366,9 @@ pub trait CrateLoader {
 // In order to get this left-to-right dependency ordering, we perform a
 // topological sort of all crates putting the leaves at the right-most
 // positions.
-pub fn used_crates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)> {
+pub fn used_crates(tcx: TyCtxt, prefer: LinkagePreference)
+    -> Vec<(CrateNum, LibSource)>
+{
     let mut libs = tcx.crates()
         .iter()
         .cloned()
diff --git a/src/librustc/middle/exported_symbols.rs b/src/librustc/middle/exported_symbols.rs
new file mode 100644
index 00000000000..230878f8545
--- /dev/null
+++ b/src/librustc/middle/exported_symbols.rs
@@ -0,0 +1,31 @@
+// 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.
+
+/// The SymbolExportLevel of a symbols specifies from which kinds of crates
+/// the symbol will be exported. `C` symbols will be exported from any
+/// kind of crate, including cdylibs which export very few things.
+/// `Rust` will only be exported if the crate produced is a Rust
+/// dylib.
+#[derive(Eq, PartialEq, Debug, Copy, Clone)]
+pub enum SymbolExportLevel {
+    C,
+    Rust,
+}
+
+impl SymbolExportLevel {
+    pub fn is_below_threshold(self, threshold: SymbolExportLevel) -> bool {
+        if threshold == SymbolExportLevel::Rust {
+            // We export everything from Rust dylibs
+            true
+        } else {
+            self == SymbolExportLevel::C
+        }
+    }
+}
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index d3e34c851f3..7c442450901 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -233,8 +233,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
                 } else {
                     false
                 };
-                let is_extern = attr::contains_extern_indicator(&self.tcx.sess.diagnostic(),
-                                                                &item.attrs);
+                let def_id = self.tcx.hir.local_def_id(item.id);
+                let is_extern = self.tcx.contains_extern_indicator(def_id);
                 if reachable || is_extern {
                     self.reachable_symbols.insert(search_item);
                 }
@@ -369,10 +369,6 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a,
     }
 }
 
-pub fn find_reachable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Rc<NodeSet> {
-    tcx.reachable_set(LOCAL_CRATE)
-}
-
 fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> Rc<NodeSet> {
     debug_assert!(crate_num == LOCAL_CRATE);
 
diff --git a/src/librustc/middle/trans.rs b/src/librustc/middle/trans.rs
new file mode 100644
index 00000000000..9a501257548
--- /dev/null
+++ b/src/librustc/middle/trans.rs
@@ -0,0 +1,110 @@
+// Copyright 2017 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.
+
+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
+    }
+}
+
+#[derive(Clone, Default)]
+pub struct Stats {
+    pub n_glues_created: usize,
+    pub n_null_glues: usize,
+    pub n_real_glues: usize,
+    pub n_fns: usize,
+    pub n_inlines: usize,
+    pub n_closures: usize,
+    pub n_llvm_insns: usize,
+    pub llvm_insns: FxHashMap<String, usize>,
+    // (ident, llvm-instructions)
+    pub fn_stats: Vec<(String, usize)>,
+}
+
+impl Stats {
+    pub fn extend(&mut self, stats: Stats) {
+        self.n_glues_created += stats.n_glues_created;
+        self.n_null_glues += stats.n_null_glues;
+        self.n_real_glues += stats.n_real_glues;
+        self.n_fns += stats.n_fns;
+        self.n_inlines += stats.n_inlines;
+        self.n_closures += stats.n_closures;
+        self.n_llvm_insns += stats.n_llvm_insns;
+
+        for (k, v) in stats.llvm_insns {
+            *self.llvm_insns.entry(k).or_insert(0) += v;
+        }
+        self.fn_stats.extend(stats.fn_stats);
+    }
+}
diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs
index fb0cdab0b6a..945a0814427 100644
--- a/src/librustc/ty/context.rs
+++ b/src/librustc/ty/context.rs
@@ -13,6 +13,7 @@
 use dep_graph::DepGraph;
 use errors::DiagnosticBuilder;
 use session::Session;
+use session::config::OutputFilenames;
 use middle;
 use hir::{TraitCandidate, HirId, ItemLocalId};
 use hir::def::{Def, Export};
@@ -64,6 +65,8 @@ use std::mem;
 use std::ops::Deref;
 use std::iter;
 use std::rc::Rc;
+use std::sync::mpsc;
+use std::sync::Arc;
 use syntax::abi;
 use syntax::ast::{self, Name, NodeId};
 use syntax::attr;
@@ -901,6 +904,16 @@ pub struct GlobalCtxt<'tcx> {
     /// error reporting, and so is lazily initialized and generally
     /// shouldn't taint the common path (hence the RefCell).
     pub all_traits: RefCell<Option<Vec<DefId>>>,
+
+    /// A general purpose channel to throw data out the back towards LLVM worker
+    /// threads.
+    ///
+    /// This is intended to only get used during the trans phase of the compiler
+    /// when satisfying the query for a particular codegen unit. Internally in
+    /// the query it'll send data along this channel to get processed later.
+    pub tx_to_llvm_workers: mpsc::Sender<Box<Any + Send>>,
+
+    output_filenames: Arc<OutputFilenames>,
 }
 
 impl<'tcx> GlobalCtxt<'tcx> {
@@ -1025,6 +1038,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                                   named_region_map: resolve_lifetime::NamedRegionMap,
                                   hir: hir_map::Map<'tcx>,
                                   crate_name: &str,
+                                  tx: mpsc::Sender<Box<Any + Send>>,
+                                  output_filenames: &OutputFilenames,
                                   f: F) -> R
                                   where F: for<'b> FnOnce(TyCtxt<'b, 'tcx, 'tcx>) -> R
     {
@@ -1145,6 +1160,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             derive_macros: RefCell::new(NodeMap()),
             stability_interner: RefCell::new(FxHashSet()),
             all_traits: RefCell::new(None),
+            tx_to_llvm_workers: tx,
+            output_filenames: Arc::new(output_filenames.clone()),
        }, f)
     }
 
@@ -2218,4 +2235,8 @@ pub fn provide(providers: &mut ty::maps::Providers) {
         assert_eq!(cnum, LOCAL_CRATE);
         Rc::new(tcx.cstore.postorder_cnums_untracked())
     };
+    providers.output_filenames = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        tcx.output_filenames.clone()
+    };
 }
diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs
index 18c59d405a2..bf17b82535c 100644
--- a/src/librustc/ty/maps.rs
+++ b/src/librustc/ty/maps.rs
@@ -23,9 +23,12 @@ use middle::region;
 use middle::resolve_lifetime::{Region, ObjectLifetimeDefault};
 use middle::stability::{self, DeprecationEntry};
 use middle::lang_items::{LanguageItems, LangItem};
+use middle::exported_symbols::SymbolExportLevel;
+use middle::trans::{CodegenUnit, Stats};
 use mir;
 use mir::transform::{MirSuite, MirPassIndex};
 use session::CompileResult;
+use session::config::OutputFilenames;
 use traits::specialization_graph;
 use ty::{self, CrateInherentImpls, Ty, TyCtxt};
 use ty::layout::{Layout, LayoutError};
@@ -48,7 +51,9 @@ use std::mem;
 use std::collections::BTreeMap;
 use std::ops::Deref;
 use std::rc::Rc;
+use std::sync::Arc;
 use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::symbol::InternedString;
 use syntax::attr;
 use syntax::ast;
 use syntax::symbol::Symbol;
@@ -177,6 +182,15 @@ impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> {
     }
 }
 
+impl Key for InternedString {
+    fn map_crate(&self) -> CrateNum {
+        LOCAL_CRATE
+    }
+    fn default_span(&self, _tcx: TyCtxt) -> Span {
+        DUMMY_SP
+    }
+}
+
 trait Value<'tcx>: Sized {
     fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
 }
@@ -595,7 +609,7 @@ impl<'tcx> QueryDescription for queries::is_sanitizer_runtime<'tcx> {
     }
 }
 
-impl<'tcx> QueryDescription for queries::exported_symbols<'tcx> {
+impl<'tcx> QueryDescription for queries::exported_symbol_ids<'tcx> {
     fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
         format!("looking up the exported symbols of a crate")
     }
@@ -745,6 +759,36 @@ impl<'tcx> QueryDescription for queries::all_crate_nums<'tcx> {
     }
 }
 
+impl<'tcx> QueryDescription for queries::exported_symbols<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("exported_symbols")
+    }
+}
+
+impl<'tcx> QueryDescription for queries::collect_and_partition_translation_items<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("collect_and_partition_translation_items")
+    }
+}
+
+impl<'tcx> QueryDescription for queries::codegen_unit<'tcx> {
+    fn describe(_tcx: TyCtxt, _: InternedString) -> String {
+        format!("codegen_unit")
+    }
+}
+
+impl<'tcx> QueryDescription for queries::compile_codegen_unit<'tcx> {
+    fn describe(_tcx: TyCtxt, _: InternedString) -> String {
+        format!("compile_codegen_unit")
+    }
+}
+
+impl<'tcx> QueryDescription for queries::output_filenames<'tcx> {
+    fn describe(_tcx: TyCtxt, _: CrateNum) -> String {
+        format!("output_filenames")
+    }
+}
+
 // If enabled, send a message to the profile-queries thread
 macro_rules! profq_msg {
     ($tcx:expr, $msg:expr) => {
@@ -1322,7 +1366,7 @@ define_maps! { <'tcx>
     [] fn lint_levels: lint_levels_node(CrateNum) -> Rc<lint::LintLevelMap>,
 
     [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness,
-    [] fn exported_symbols: ExportedSymbols(CrateNum) -> Rc<Vec<DefId>>,
+    [] fn exported_symbol_ids: ExportedSymbolIds(CrateNum) -> Rc<DefIdSet>,
     [] fn native_libraries: NativeLibraries(CrateNum) -> Rc<Vec<NativeLibrary>>,
     [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option<DefId>,
     [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option<DefId>,
@@ -1371,6 +1415,19 @@ define_maps! { <'tcx>
 
     [] fn stability_index: stability_index_node(CrateNum) -> Rc<stability::Index<'tcx>>,
     [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Rc<Vec<CrateNum>>,
+
+    [] fn exported_symbols: ExportedSymbols(CrateNum)
+        -> Arc<Vec<(String, DefId, SymbolExportLevel)>>,
+    [] fn collect_and_partition_translation_items:
+        collect_and_partition_translation_items_node(CrateNum)
+        -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>),
+    [] fn export_name: ExportName(DefId) -> Option<Symbol>,
+    [] fn contains_extern_indicator: ContainsExternIndicator(DefId) -> bool,
+    [] fn is_translated_function: IsTranslatedFunction(DefId) -> bool,
+    [] fn codegen_unit: CodegenUnit(InternedString) -> Arc<CodegenUnit<'tcx>>,
+    [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats,
+    [] fn output_filenames: output_filenames_node(CrateNum)
+        -> Arc<OutputFilenames>,
 }
 
 fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
@@ -1484,3 +1541,11 @@ fn stability_index_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
 fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
     DepConstructor::AllCrateNums
 }
+
+fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+    DepConstructor::CollectAndPartitionTranslationItems
+}
+
+fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> {
+    DepConstructor::OutputFilenames
+}
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 2d5b0ce0954..e2df963f80f 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -121,7 +121,6 @@ mod sty;
 #[derive(Clone)]
 pub struct CrateAnalysis {
     pub access_levels: Rc<AccessLevels>,
-    pub reachable: Rc<NodeSet>,
     pub name: String,
     pub glob_map: Option<hir::GlobMap>,
 }
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index ed012f87996..32a160bcffc 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -28,7 +28,6 @@ use rustc::mir::transform::{MIR_CONST, MIR_VALIDATED, MIR_OPTIMIZED, Passes};
 use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
 use rustc::traits;
 use rustc::util::common::{ErrorReported, time};
-use rustc::util::nodemap::NodeSet;
 use rustc_allocator as allocator;
 use rustc_borrowck as borrowck;
 use rustc_incremental::{self, IncrementalHashesMap};
@@ -47,6 +46,7 @@ use super::Compilation;
 
 use serialize::json;
 
+use std::any::Any;
 use std::env;
 use std::ffi::{OsString, OsStr};
 use std::fs;
@@ -54,6 +54,7 @@ use std::io::{self, Write};
 use std::iter;
 use std::path::{Path, PathBuf};
 use std::rc::Rc;
+use std::sync::mpsc;
 use syntax::{ast, diagnostics, visit};
 use syntax::attr;
 use syntax::ext::base::ExtCtxt;
@@ -192,6 +193,7 @@ pub fn compile_input(sess: &Session,
                                                                   &resolutions,
                                                                   &expanded_crate,
                                                                   &hir_map.krate(),
+                                                                  &outputs,
                                                                   &crate_name),
                                     Ok(()));
         }
@@ -215,7 +217,8 @@ pub fn compile_input(sess: &Session,
                                     &arena,
                                     &arenas,
                                     &crate_name,
-                                    |tcx, analysis, incremental_hashes_map, result| {
+                                    &outputs,
+                                    |tcx, analysis, incremental_hashes_map, rx, result| {
             {
                 // Eventually, we will want to track plugins.
                 let _ignore = tcx.dep_graph.in_ignore();
@@ -243,8 +246,9 @@ pub fn compile_input(sess: &Session,
                 tcx.print_debug_stats();
             }
 
-            let trans = phase_4_translate_to_llvm(tcx, analysis, incremental_hashes_map,
-                                                  &outputs);
+            let trans = phase_4_translate_to_llvm(tcx,
+                                                  incremental_hashes_map,
+                                                  rx);
 
             if log_enabled!(::log::LogLevel::Info) {
                 println!("Post-trans");
@@ -258,7 +262,7 @@ pub fn compile_input(sess: &Session,
                 }
             }
 
-            Ok((outputs, trans, tcx.dep_graph.clone()))
+            Ok((outputs.clone(), trans, tcx.dep_graph.clone()))
         })??
     };
 
@@ -483,6 +487,7 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> {
                                 resolutions: &'a Resolutions,
                                 krate: &'a ast::Crate,
                                 hir_crate: &'a hir::Crate,
+                                output_filenames: &'a OutputFilenames,
                                 crate_name: &'a str)
                                 -> Self {
         CompileState {
@@ -495,6 +500,7 @@ impl<'a, 'tcx> CompileState<'a, 'tcx> {
             resolutions: Some(resolutions),
             expanded_crate: Some(krate),
             hir_crate: Some(hir_crate),
+            output_filenames: Some(output_filenames),
             out_file: out_file.as_ref().map(|s| &**s),
             ..CompileState::empty(input, session, out_dir)
         }
@@ -885,7 +891,6 @@ pub fn phase_2_configure_and_expand<F>(sess: &Session,
         defs: resolver.definitions,
         analysis: ty::CrateAnalysis {
             access_levels: Rc::new(AccessLevels::default()),
-            reachable: Rc::new(NodeSet()),
             name: crate_name.to_string(),
             glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None },
         },
@@ -911,19 +916,21 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                                                arena: &'tcx DroplessArena,
                                                arenas: &'tcx GlobalArenas<'tcx>,
                                                name: &str,
+                                               output_filenames: &OutputFilenames,
                                                f: F)
                                                -> Result<R, CompileIncomplete>
     where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>,
                             ty::CrateAnalysis,
                             IncrementalHashesMap,
+                            mpsc::Receiver<Box<Any + Send>>,
                             CompileResult) -> R
 {
     macro_rules! try_with_f {
-        ($e: expr, ($t: expr, $a: expr, $h: expr)) => {
+        ($e: expr, ($($t:tt)*)) => {
             match $e {
                 Ok(x) => x,
                 Err(x) => {
-                    f($t, $a, $h, Err(x));
+                    f($($t)*, Err(x));
                     return Err(x);
                 }
             }
@@ -958,7 +965,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     mir::provide(&mut local_providers);
     reachable::provide(&mut local_providers);
     rustc_privacy::provide(&mut local_providers);
-    trans::provide(&mut local_providers);
+    trans::provide_local(&mut local_providers);
     typeck::provide(&mut local_providers);
     ty::provide(&mut local_providers);
     traits::provide(&mut local_providers);
@@ -970,7 +977,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 
     let mut extern_providers = ty::maps::Providers::default();
     cstore::provide(&mut extern_providers);
-    trans::provide(&mut extern_providers);
+    trans::provide_extern(&mut extern_providers);
     ty::provide_extern(&mut extern_providers);
     traits::provide_extern(&mut extern_providers);
     // FIXME(eddyb) get rid of this once we replace const_eval with miri.
@@ -1030,6 +1037,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
     passes.push_pass(MIR_OPTIMIZED, mir::transform::add_call_guards::CriticalCallEdges);
     passes.push_pass(MIR_OPTIMIZED, mir::transform::dump_mir::Marker("PreTrans"));
 
+    let (tx, rx) = mpsc::channel();
+
     TyCtxt::create_and_enter(sess,
                              cstore,
                              local_providers,
@@ -1041,6 +1050,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
                              named_region_map,
                              hir_map,
                              name,
+                             tx,
+                             output_filenames,
                              |tcx| {
         let incremental_hashes_map =
             time(time_passes,
@@ -1056,7 +1067,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
              || stability::check_unstable_api_usage(tcx));
 
         // passes are timed inside typeck
-        try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map));
+        try_with_f!(typeck::check_crate(tcx),
+                    (tcx, analysis, incremental_hashes_map, rx));
 
         time(time_passes,
              "const checking",
@@ -1100,14 +1112,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
         // lint warnings and so on -- kindck used to do this abort, but
         // kindck is gone now). -nmatsakis
         if sess.err_count() > 0 {
-            return Ok(f(tcx, analysis, incremental_hashes_map, sess.compile_status()));
+            return Ok(f(tcx, analysis, incremental_hashes_map, rx, sess.compile_status()));
         }
 
-        analysis.reachable =
-            time(time_passes,
-                 "reachability checking",
-                 || reachable::find_reachable(tcx));
-
         time(time_passes, "death checking", || middle::dead::check_crate(tcx));
 
         time(time_passes, "unused lib feature checking", || {
@@ -1116,16 +1123,15 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
 
         time(time_passes, "lint checking", || lint::check_crate(tcx));
 
-        return Ok(f(tcx, analysis, incremental_hashes_map, tcx.sess.compile_status()));
+        return Ok(f(tcx, analysis, incremental_hashes_map, rx, tcx.sess.compile_status()));
     })
 }
 
 /// Run the translation phase to LLVM, after which the AST and analysis can
 /// be discarded.
 pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                           analysis: ty::CrateAnalysis,
                                            incremental_hashes_map: IncrementalHashesMap,
-                                           output_filenames: &OutputFilenames)
+                                           rx: mpsc::Receiver<Box<Any + Send>>)
                                            -> write::OngoingCrateTranslation {
     let time_passes = tcx.sess.time_passes();
 
@@ -1134,9 +1140,9 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
          || ::rustc::middle::dependency_format::calculate(tcx));
 
     let translation =
-        time(time_passes,
-             "translation",
-             move || trans::trans_crate(tcx, analysis, incremental_hashes_map, output_filenames));
+        time(time_passes, "translation", move || {
+            trans::trans_crate(tcx, incremental_hashes_map, rx)
+        });
 
     if tcx.sess.profile_queries() {
         profile::dump("profile_queries".to_string())
diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs
index 522b9eb2232..044f4a5eaf5 100644
--- a/src/librustc_driver/lib.rs
+++ b/src/librustc_driver/lib.rs
@@ -645,6 +645,7 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls {
                                                      ppm,
                                                      state.arena.unwrap(),
                                                      state.arenas.unwrap(),
+                                                     state.output_filenames.unwrap(),
                                                      opt_uii.clone(),
                                                      state.out_file);
                 };
diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs
index 82dda2d2aa1..cd153b82077 100644
--- a/src/librustc_driver/pretty.rs
+++ b/src/librustc_driver/pretty.rs
@@ -23,7 +23,7 @@ use rustc::cfg::graphviz::LabelledCFG;
 use rustc::dep_graph::DepGraph;
 use rustc::middle::cstore::CrateStore;
 use rustc::session::Session;
-use rustc::session::config::Input;
+use rustc::session::config::{Input, OutputFilenames};
 use rustc_borrowck as borrowck;
 use rustc_borrowck::graphviz as borrowck_dot;
 
@@ -205,6 +205,7 @@ impl PpSourceMode {
                                                resolutions: &Resolutions,
                                                arena: &'tcx DroplessArena,
                                                arenas: &'tcx GlobalArenas<'tcx>,
+                                               output_filenames: &OutputFilenames,
                                                id: &str,
                                                f: F)
                                                -> A
@@ -235,7 +236,8 @@ impl PpSourceMode {
                                                                  arena,
                                                                  arenas,
                                                                  id,
-                                                                 |tcx, _, _, _| {
+                                                                 output_filenames,
+                                                                 |tcx, _, _, _, _| {
                     let empty_tables = ty::TypeckTables::empty(None);
                     let annotation = TypedAnnotation {
                         tcx,
@@ -888,6 +890,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                 ppm: PpMode,
                                                 arena: &'tcx DroplessArena,
                                                 arenas: &'tcx GlobalArenas<'tcx>,
+                                                output_filenames: &OutputFilenames,
                                                 opt_uii: Option<UserIdentifiedItem>,
                                                 ofile: Option<&Path>) {
     let dep_graph = DepGraph::new(false);
@@ -902,6 +905,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                             crate_name,
                             arena,
                             arenas,
+                            output_filenames,
                             ppm,
                             opt_uii,
                             ofile);
@@ -940,6 +944,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                            resolutions,
                                            arena,
                                            arenas,
+                                           output_filenames,
                                            crate_name,
                                            move |annotation, krate| {
                     debug!("pretty printing source code {:?}", s);
@@ -964,6 +969,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
                                            resolutions,
                                            arena,
                                            arenas,
+                                           output_filenames,
                                            crate_name,
                                            move |annotation, _| {
                     debug!("pretty printing source code {:?}", s);
@@ -1007,6 +1013,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                                        crate_name: &str,
                                        arena: &'tcx DroplessArena,
                                        arenas: &'tcx GlobalArenas<'tcx>,
+                                       output_filenames: &OutputFilenames,
                                        ppm: PpMode,
                                        uii: Option<UserIdentifiedItem>,
                                        ofile: Option<&Path>) {
@@ -1028,7 +1035,8 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
                                                      arena,
                                                      arenas,
                                                      crate_name,
-                                                     |tcx, _, _, _| {
+                                                     output_filenames,
+                                                     |tcx, _, _, _, _| {
         match ppm {
             PpmMir | PpmMirCFG => {
                 if let Some(nodeid) = nodeid {
diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs
index d0edcbc3260..34f4e0e7b0c 100644
--- a/src/librustc_driver/test.rs
+++ b/src/librustc_driver/test.rs
@@ -10,6 +10,9 @@
 
 //! # Standalone Tests for the Inference Module
 
+use std::path::PathBuf;
+use std::sync::mpsc;
+
 use driver;
 use rustc_lint;
 use rustc_resolve::MakeGlobMap;
@@ -26,6 +29,7 @@ use rustc_metadata::cstore::CStore;
 use rustc::hir::map as hir_map;
 use rustc::mir::transform::Passes;
 use rustc::session::{self, config};
+use rustc::session::config::{OutputFilenames, OutputTypes};
 use std::rc::Rc;
 use syntax::ast;
 use syntax::abi::Abi;
@@ -133,6 +137,14 @@ fn test_env<F>(source_string: &str,
 
     // run just enough stuff to build a tcx:
     let named_region_map = resolve_lifetime::krate(&sess, &*cstore, &hir_map);
+    let (tx, _rx) = mpsc::channel();
+    let outputs = OutputFilenames {
+        out_directory: PathBuf::new(),
+        out_filestem: String::new(),
+        single_output_file: None,
+        extra: String::new(),
+        outputs: OutputTypes::new(&[]),
+    };
     TyCtxt::create_and_enter(&sess,
                              &*cstore,
                              ty::maps::Providers::default(),
@@ -144,6 +156,8 @@ fn test_env<F>(source_string: &str,
                              named_region_map.unwrap(),
                              hir_map,
                              "test_crate",
+                             tx,
+                             &outputs,
                              |tcx| {
         tcx.infer_ctxt().enter(|infcx| {
             let mut region_scope_tree = region::ScopeTree::default();
diff --git a/src/librustc_metadata/cstore_impl.rs b/src/librustc_metadata/cstore_impl.rs
index 74e4ffcdfff..3a116160bca 100644
--- a/src/librustc_metadata/cstore_impl.rs
+++ b/src/librustc_metadata/cstore_impl.rs
@@ -175,7 +175,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
     extern_crate => { Rc::new(cdata.extern_crate.get()) }
     is_no_builtins => { cdata.is_no_builtins() }
     impl_defaultness => { cdata.get_impl_defaultness(def_id.index) }
-    exported_symbols => { Rc::new(cdata.get_exported_symbols()) }
+    exported_symbol_ids => { Rc::new(cdata.get_exported_symbols()) }
     native_libraries => { Rc::new(cdata.get_native_libraries()) }
     plugin_registrar_fn => {
         cdata.root.plugin_registrar_fn.map(|index| {
diff --git a/src/librustc_metadata/decoder.rs b/src/librustc_metadata/decoder.rs
index 689f9f5b244..1c4f1c63486 100644
--- a/src/librustc_metadata/decoder.rs
+++ b/src/librustc_metadata/decoder.rs
@@ -24,6 +24,7 @@ use rustc::middle::lang_items;
 use rustc::session::Session;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
+use rustc::util::nodemap::DefIdSet;
 
 use rustc::mir::Mir;
 
@@ -1017,7 +1018,7 @@ impl<'a, 'tcx> CrateMetadata {
         arg_names.decode(self).collect()
     }
 
-    pub fn get_exported_symbols(&self) -> Vec<DefId> {
+    pub fn get_exported_symbols(&self) -> DefIdSet {
         self.exported_symbols
             .iter()
             .map(|&index| self.local_def_id(index))
diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs
index 4211c8df5ca..8e933d5ac88 100644
--- a/src/librustc_trans/abi.rs
+++ b/src/librustc_trans/abi.rs
@@ -612,7 +612,7 @@ pub struct FnType<'tcx> {
 impl<'a, 'tcx> FnType<'tcx> {
     pub fn of_instance(ccx: &CrateContext<'a, 'tcx>, instance: &ty::Instance<'tcx>)
                        -> Self {
-        let fn_ty = instance_ty(ccx.shared(), &instance);
+        let fn_ty = instance_ty(ccx.tcx(), &instance);
         let sig = ty_fn_sig(ccx, fn_ty);
         let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
         Self::new(ccx, sig, &[])
diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_trans/back/linker.rs
index 487d9e05945..239b488fabe 100644
--- a/src/librustc_trans/back/linker.rs
+++ b/src/librustc_trans/back/linker.rs
@@ -15,16 +15,15 @@ use std::io::prelude::*;
 use std::io::{self, BufWriter};
 use std::path::{Path, PathBuf};
 
-use context::SharedCrateContext;
-
 use back::archive;
 use back::command::Command;
-use back::symbol_export::ExportedSymbols;
-use rustc::middle::dependency_format::Linkage;
+use back::symbol_export;
 use rustc::hir::def_id::{LOCAL_CRATE, CrateNum};
-use rustc_back::LinkerFlavor;
+use rustc::middle::dependency_format::Linkage;
 use rustc::session::Session;
 use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel};
+use rustc::ty::TyCtxt;
+use rustc_back::LinkerFlavor;
 use serialize::{json, Encoder};
 
 /// For all the linkers we support, and information they might
@@ -33,19 +32,18 @@ pub struct LinkerInfo {
     exports: HashMap<CrateType, Vec<String>>,
 }
 
-impl<'a, 'tcx> LinkerInfo {
-    pub fn new(scx: &SharedCrateContext<'a, 'tcx>,
-               exports: &ExportedSymbols) -> LinkerInfo {
+impl LinkerInfo {
+    pub fn new(tcx: TyCtxt) -> LinkerInfo {
         LinkerInfo {
-            exports: scx.sess().crate_types.borrow().iter().map(|&c| {
-                (c, exported_symbols(scx, exports, c))
+            exports: tcx.sess.crate_types.borrow().iter().map(|&c| {
+                (c, exported_symbols(tcx, c))
             }).collect(),
         }
     }
 
-    pub fn to_linker(&'a self,
-                     cmd: Command,
-                     sess: &'a Session) -> Box<Linker+'a> {
+    pub fn to_linker<'a>(&'a self,
+                         cmd: Command,
+                         sess: &'a Session) -> Box<Linker+'a> {
         match sess.linker_flavor() {
             LinkerFlavor::Msvc => {
                 Box::new(MsvcLinker {
@@ -734,16 +732,17 @@ impl<'a> Linker for EmLinker<'a> {
     }
 }
 
-fn exported_symbols(scx: &SharedCrateContext,
-                    exported_symbols: &ExportedSymbols,
-                    crate_type: CrateType)
-                    -> Vec<String> {
+fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec<String> {
     let mut symbols = Vec::new();
-    exported_symbols.for_each_exported_symbol(LOCAL_CRATE, |name, _, _| {
-        symbols.push(name.to_owned());
-    });
 
-    let formats = scx.sess().dependency_formats.borrow();
+    let export_threshold = symbol_export::threshold(tcx);
+    for &(ref name, _, level) in tcx.exported_symbols(LOCAL_CRATE).iter() {
+        if level.is_below_threshold(export_threshold) {
+            symbols.push(name.clone());
+        }
+    }
+
+    let formats = tcx.sess.dependency_formats.borrow();
     let deps = formats[&crate_type].iter();
 
     for (index, dep_format) in deps.enumerate() {
@@ -751,9 +750,11 @@ fn exported_symbols(scx: &SharedCrateContext,
         // For each dependency that we are linking to statically ...
         if *dep_format == Linkage::Static {
             // ... we add its symbol list to our export list.
-            exported_symbols.for_each_exported_symbol(cnum, |name, _, _| {
-                symbols.push(name.to_owned());
-            })
+            for &(ref name, _, level) in tcx.exported_symbols(cnum).iter() {
+                if level.is_below_threshold(export_threshold) {
+                    symbols.push(name.clone());
+                }
+            }
         }
     }
 
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs
index 3e2d9f5c32e..aa13e4aa196 100644
--- a/src/librustc_trans/back/lto.rs
+++ b/src/librustc_trans/back/lto.rs
@@ -16,6 +16,7 @@ use errors::{FatalError, Handler};
 use llvm;
 use llvm::archive_ro::ArchiveRO;
 use llvm::{ModuleRef, TargetMachineRef, True, False};
+use rustc::middle::exported_symbols::SymbolExportLevel;
 use rustc::util::common::time;
 use rustc::util::common::path2cstr;
 use rustc::hir::def_id::LOCAL_CRATE;
@@ -67,8 +68,8 @@ pub fn run(cgcx: &CodegenContext,
     let export_threshold =
         symbol_export::crates_export_threshold(&cgcx.crate_types);
 
-    let symbol_filter = &|&(ref name, _, level): &(String, _, _)| {
-        if symbol_export::is_below_threshold(level, export_threshold) {
+    let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| {
+        if level.is_below_threshold(export_threshold) {
             let mut bytes = Vec::with_capacity(name.len() + 1);
             bytes.extend(name.bytes());
             Some(CString::new(bytes).unwrap())
@@ -77,8 +78,7 @@ pub fn run(cgcx: &CodegenContext,
         }
     };
 
-    let mut symbol_white_list: Vec<CString> = cgcx.exported_symbols
-        .exported_symbols(LOCAL_CRATE)
+    let mut symbol_white_list: Vec<CString> = cgcx.exported_symbols[&LOCAL_CRATE]
         .iter()
         .filter_map(symbol_filter)
         .collect();
@@ -88,9 +88,9 @@ pub fn run(cgcx: &CodegenContext,
     // module that we've got.
     for &(cnum, ref path) in cgcx.each_linked_rlib_for_lto.iter() {
         symbol_white_list.extend(
-            cgcx.exported_symbols.exported_symbols(cnum)
-                                 .iter()
-                                 .filter_map(symbol_filter));
+            cgcx.exported_symbols[&cnum]
+                .iter()
+                .filter_map(symbol_filter));
 
         let archive = ArchiveRO::open(&path).expect("wanted an rlib");
         let bytecodes = archive.iter().filter_map(|child| {
diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_trans/back/symbol_export.rs
index b546059b4c5..844442edbc8 100644
--- a/src/librustc_trans/back/symbol_export.rs
+++ b/src/librustc_trans/back/symbol_export.rs
@@ -8,46 +8,83 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::rc::Rc;
+use std::sync::Arc;
+
+use base;
 use monomorphize::Instance;
-use rustc::util::nodemap::{FxHashMap, NodeSet};
-use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX};
+use rustc::hir::def_id::CrateNum;
+use rustc::hir::def_id::{DefId, LOCAL_CRATE, INVALID_CRATE, CRATE_DEF_INDEX};
+use rustc::middle::exported_symbols::SymbolExportLevel;
 use rustc::session::config;
 use rustc::ty::TyCtxt;
+use rustc::ty::maps::Providers;
+use rustc::util::nodemap::FxHashMap;
 use rustc_allocator::ALLOCATOR_METHODS;
-use syntax::attr;
-
-/// The SymbolExportLevel of a symbols specifies from which kinds of crates
-/// the symbol will be exported. `C` symbols will be exported from any
-/// kind of crate, including cdylibs which export very few things.
-/// `Rust` will only be exported if the crate produced is a Rust
-/// dylib.
-#[derive(Eq, PartialEq, Debug, Copy, Clone)]
-pub enum SymbolExportLevel {
-    C,
-    Rust,
+
+pub type ExportedSymbols = FxHashMap<
+    CrateNum,
+    Arc<Vec<(String, DefId, SymbolExportLevel)>>,
+>;
+
+pub fn threshold(tcx: TyCtxt) -> SymbolExportLevel {
+    crates_export_threshold(&tcx.sess.crate_types.borrow())
 }
 
-/// The set of symbols exported from each crate in the crate graph.
-#[derive(Debug)]
-pub struct ExportedSymbols {
-    pub export_threshold: SymbolExportLevel,
-    exports: FxHashMap<CrateNum, Vec<(String, DefId, SymbolExportLevel)>>,
-    local_exports: NodeSet,
+pub fn metadata_symbol_name(tcx: TyCtxt) -> String {
+    format!("rust_metadata_{}_{}",
+            tcx.crate_name(LOCAL_CRATE),
+            tcx.crate_disambiguator(LOCAL_CRATE))
 }
 
-impl ExportedSymbols {
-    pub fn empty() -> ExportedSymbols {
-        ExportedSymbols {
-            export_threshold: SymbolExportLevel::C,
-            exports: FxHashMap(),
-            local_exports: NodeSet(),
-        }
+fn crate_export_threshold(crate_type: config::CrateType) -> SymbolExportLevel {
+    match crate_type {
+        config::CrateTypeExecutable |
+        config::CrateTypeStaticlib  |
+        config::CrateTypeProcMacro  |
+        config::CrateTypeCdylib     => SymbolExportLevel::C,
+        config::CrateTypeRlib       |
+        config::CrateTypeDylib      => SymbolExportLevel::Rust,
     }
+}
 
-    pub fn compute<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             local_exported_symbols: &NodeSet)
-                             -> ExportedSymbols {
-        let export_threshold = crates_export_threshold(&tcx.sess.crate_types.borrow());
+pub fn crates_export_threshold(crate_types: &[config::CrateType])
+                                      -> SymbolExportLevel {
+    if crate_types.iter().any(|&crate_type| {
+        crate_export_threshold(crate_type) == SymbolExportLevel::Rust
+    }) {
+        SymbolExportLevel::Rust
+    } else {
+        SymbolExportLevel::C
+    }
+}
+
+pub fn provide_local(providers: &mut Providers) {
+    providers.exported_symbol_ids = |tcx, cnum| {
+        let export_threshold = threshold(tcx);
+        Rc::new(tcx.exported_symbols(cnum)
+            .iter()
+            .filter_map(|&(_, id, level)| {
+                if level.is_below_threshold(export_threshold) {
+                    Some(id)
+                } else {
+                    None
+                }
+            })
+            .collect())
+    };
+
+    providers.is_exported_symbol = |tcx, id| {
+        // FIXME(#42293) needs red/green to not break a bunch of incremental
+        // tests
+        tcx.dep_graph.with_ignore(|| {
+            tcx.exported_symbol_ids(id.krate).contains(&id)
+        })
+    };
+
+    providers.exported_symbols = |tcx, cnum| {
+        assert_eq!(cnum, LOCAL_CRATE);
+        let local_exported_symbols = base::find_exported_symbols(tcx);
 
         let mut local_crate: Vec<_> = local_exported_symbols
             .iter()
@@ -62,17 +99,6 @@ impl ExportedSymbols {
             })
             .collect();
 
-        let mut local_exports = local_crate
-            .iter()
-            .filter_map(|&(_, def_id, level)| {
-                if is_below_threshold(level, export_threshold) {
-                    tcx.hir.as_local_node_id(def_id)
-                } else {
-                    None
-                }
-            })
-            .collect::<NodeSet>();
-
         const INVALID_DEF_ID: DefId = DefId {
             krate: INVALID_CRATE,
             index: CRATE_DEF_INDEX,
@@ -98,7 +124,6 @@ impl ExportedSymbols {
             let disambiguator = tcx.sess.local_crate_disambiguator();
             let registrar = tcx.sess.generate_derive_registrar_symbol(disambiguator, idx);
             local_crate.push((registrar, def_id, SymbolExportLevel::C));
-            local_exports.insert(id);
         }
 
         if tcx.sess.crate_types.borrow().contains(&config::CrateTypeDylib) {
@@ -106,141 +131,65 @@ impl ExportedSymbols {
                               INVALID_DEF_ID,
                               SymbolExportLevel::Rust));
         }
+        Arc::new(local_crate)
+    };
+}
 
-        let mut exports = FxHashMap();
-        exports.insert(LOCAL_CRATE, local_crate);
-
-        for &cnum in tcx.crates().iter() {
-            debug_assert!(cnum != LOCAL_CRATE);
-
-            // If this crate is a plugin and/or a custom derive crate, then
-            // we're not even going to link those in so we skip those crates.
-            if tcx.plugin_registrar_fn(cnum).is_some() ||
-               tcx.derive_registrar_fn(cnum).is_some() {
-                continue;
-            }
-
-            // Check to see if this crate is a "special runtime crate". These
-            // crates, implementation details of the standard library, typically
-            // have a bunch of `pub extern` and `#[no_mangle]` functions as the
-            // ABI between them. We don't want their symbols to have a `C`
-            // export level, however, as they're just implementation details.
-            // Down below we'll hardwire all of the symbols to the `Rust` export
-            // level instead.
-            let special_runtime_crate =
-                tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum);
-
-            let crate_exports = tcx
-                .exported_symbols(cnum)
-                .iter()
-                .map(|&def_id| {
-                    let name = tcx.symbol_name(Instance::mono(tcx, def_id));
-                    let export_level = if special_runtime_crate {
-                        // We can probably do better here by just ensuring that
-                        // it has hidden visibility rather than public
-                        // visibility, as this is primarily here to ensure it's
-                        // not stripped during LTO.
-                        //
-                        // In general though we won't link right if these
-                        // symbols are stripped, and LTO currently strips them.
-                        if &*name == "rust_eh_personality" ||
-                           &*name == "rust_eh_register_frames" ||
-                           &*name == "rust_eh_unregister_frames" {
-                            SymbolExportLevel::C
-                        } else {
-                            SymbolExportLevel::Rust
-                        }
-                    } else {
-                        export_level(tcx, def_id)
-                    };
-                    debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
-                    (str::to_owned(&name), def_id, export_level)
-                })
-                .collect();
-
-            exports.insert(cnum, crate_exports);
-        }
-
-        return ExportedSymbols {
-            export_threshold,
-            exports,
-            local_exports,
-        };
-
-        fn export_level(tcx: TyCtxt,
-                        sym_def_id: DefId)
-                        -> SymbolExportLevel {
-            let attrs = tcx.get_attrs(sym_def_id);
-            if attr::contains_extern_indicator(tcx.sess.diagnostic(), &attrs) {
-                SymbolExportLevel::C
-            } else {
-                SymbolExportLevel::Rust
-            }
-        }
-    }
-
-    pub fn local_exports(&self) -> &NodeSet {
-        &self.local_exports
-    }
-
-    pub fn exported_symbols(&self,
-                            cnum: CrateNum)
-                            -> &[(String, DefId, SymbolExportLevel)] {
-        match self.exports.get(&cnum) {
-            Some(exports) => exports,
-            None => &[]
+pub fn provide_extern(providers: &mut Providers) {
+    providers.exported_symbols = |tcx, cnum| {
+        // If this crate is a plugin and/or a custom derive crate, then
+        // we're not even going to link those in so we skip those crates.
+        if tcx.plugin_registrar_fn(cnum).is_some() ||
+           tcx.derive_registrar_fn(cnum).is_some() {
+            return Arc::new(Vec::new())
         }
-    }
 
-    pub fn for_each_exported_symbol<F>(&self,
-                                       cnum: CrateNum,
-                                       mut f: F)
-        where F: FnMut(&str, DefId, SymbolExportLevel)
-    {
-        for &(ref name, def_id, export_level) in self.exported_symbols(cnum) {
-            if is_below_threshold(export_level, self.export_threshold) {
-                f(&name, def_id, export_level)
-            }
-        }
-    }
-}
-
-pub fn metadata_symbol_name(tcx: TyCtxt) -> String {
-    format!("rust_metadata_{}_{}",
-            tcx.crate_name(LOCAL_CRATE),
-            tcx.crate_disambiguator(LOCAL_CRATE))
-}
+        // Check to see if this crate is a "special runtime crate". These
+        // crates, implementation details of the standard library, typically
+        // have a bunch of `pub extern` and `#[no_mangle]` functions as the
+        // ABI between them. We don't want their symbols to have a `C`
+        // export level, however, as they're just implementation details.
+        // Down below we'll hardwire all of the symbols to the `Rust` export
+        // level instead.
+        let special_runtime_crate =
+            tcx.is_panic_runtime(cnum) || tcx.is_compiler_builtins(cnum);
+
+        let crate_exports = tcx
+            .exported_symbol_ids(cnum)
+            .iter()
+            .map(|&def_id| {
+                let name = tcx.symbol_name(Instance::mono(tcx, def_id));
+                let export_level = if special_runtime_crate {
+                    // We can probably do better here by just ensuring that
+                    // it has hidden visibility rather than public
+                    // visibility, as this is primarily here to ensure it's
+                    // not stripped during LTO.
+                    //
+                    // In general though we won't link right if these
+                    // symbols are stripped, and LTO currently strips them.
+                    if &*name == "rust_eh_personality" ||
+                       &*name == "rust_eh_register_frames" ||
+                       &*name == "rust_eh_unregister_frames" {
+                        SymbolExportLevel::C
+                    } else {
+                        SymbolExportLevel::Rust
+                    }
+                } else {
+                    export_level(tcx, def_id)
+                };
+                debug!("EXPORTED SYMBOL (re-export): {} ({:?})", name, export_level);
+                (str::to_owned(&name), def_id, export_level)
+            })
+            .collect();
 
-pub fn crate_export_threshold(crate_type: config::CrateType)
-                                     -> SymbolExportLevel {
-    match crate_type {
-        config::CrateTypeExecutable |
-        config::CrateTypeStaticlib  |
-        config::CrateTypeProcMacro  |
-        config::CrateTypeCdylib     => SymbolExportLevel::C,
-        config::CrateTypeRlib       |
-        config::CrateTypeDylib      => SymbolExportLevel::Rust,
-    }
+        Arc::new(crate_exports)
+    };
 }
 
-pub fn crates_export_threshold(crate_types: &[config::CrateType])
-                                      -> SymbolExportLevel {
-    if crate_types.iter().any(|&crate_type| {
-        crate_export_threshold(crate_type) == SymbolExportLevel::Rust
-    }) {
-        SymbolExportLevel::Rust
-    } else {
+fn export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel {
+    if tcx.contains_extern_indicator(sym_def_id) {
         SymbolExportLevel::C
-    }
-}
-
-pub fn is_below_threshold(level: SymbolExportLevel,
-                          threshold: SymbolExportLevel)
-                          -> bool {
-    if threshold == SymbolExportLevel::Rust {
-        // We export everything from Rust dylibs
-        true
     } else {
-        level == SymbolExportLevel::C
+        SymbolExportLevel::Rust
     }
 }
diff --git a/src/librustc_trans/back/symbol_names.rs b/src/librustc_trans/back/symbol_names.rs
index abeb2568cbe..306071223fc 100644
--- a/src/librustc_trans/back/symbol_names.rs
+++ b/src/librustc_trans/back/symbol_names.rs
@@ -119,6 +119,30 @@ pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         def_symbol_name,
         symbol_name,
+
+        export_name: |tcx, id| {
+            tcx.get_attrs(id).iter().fold(None, |ia, attr| {
+                if attr.check_name("export_name") {
+                    if let s @ Some(_) = attr.value_str() {
+                        s
+                    } else {
+                        struct_span_err!(tcx.sess, attr.span, E0558,
+                                         "export_name attribute has invalid format")
+                            .span_label(attr.span, "did you mean #[export_name=\"*\"]?")
+                            .emit();
+                        None
+                    }
+                } else {
+                    ia
+                }
+            })
+        },
+
+        contains_extern_indicator: |tcx, id| {
+            attr::contains_name(&tcx.get_attrs(id), "no_mangle") ||
+                tcx.export_name(id).is_some()
+        },
+
         ..*providers
     };
 }
@@ -245,7 +269,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
         return tcx.item_name(def_id).to_string();
     }
 
-    if let Some(name) = attr::find_export_name_attr(tcx.sess.diagnostic(), &attrs) {
+    if let Some(name) = tcx.export_name(def_id) {
         // Use provided name
         return name.to_string();
     }
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 68140011e7e..ef6bf2504f3 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -18,17 +18,20 @@ use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
 use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
                              AllPasses, Sanitizer};
 use rustc::session::Session;
+use rustc::util::nodemap::FxHashMap;
 use time_graph::{self, TimeGraph};
 use llvm;
 use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef};
 use llvm::SMDiagnosticRef;
 use {CrateTranslation, ModuleSource, ModuleTranslation, CompiledModule, ModuleKind};
 use CrateInfo;
-use rustc::hir::def_id::CrateNum;
+use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
+use rustc::ty::TyCtxt;
 use rustc::util::common::{time, time_depth, set_time_depth, path2cstr, print_time_passes_entry};
 use rustc::util::fs::{link_or_copy, rename_or_copy_remove};
 use errors::{self, Handler, Level, DiagnosticBuilder, FatalError};
 use errors::emitter::{Emitter};
+use syntax::attr;
 use syntax::ext::hygiene::Mark;
 use syntax_pos::MultiSpan;
 use syntax_pos::symbol::Symbol;
@@ -36,6 +39,7 @@ use context::{is_pie_binary, get_reloc_model};
 use jobserver::{Client, Acquired};
 use rustc_demangle;
 
+use std::any::Any;
 use std::ffi::CString;
 use std::fmt;
 use std::fs;
@@ -199,8 +203,6 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef {
 
 /// Module-specific configuration for `optimize_and_codegen`.
 pub struct ModuleConfig {
-    /// LLVM TargetMachine to use for codegen.
-    tm: TargetMachineRef,
     /// Names of additional optimization passes to run.
     passes: Vec<String>,
     /// Some(level) to optimize at a certain level, or None to run
@@ -233,12 +235,9 @@ pub struct ModuleConfig {
     obj_is_bitcode: bool,
 }
 
-unsafe impl Send for ModuleConfig { }
-
 impl ModuleConfig {
-    fn new(sess: &Session, passes: Vec<String>) -> ModuleConfig {
+    fn new(passes: Vec<String>) -> ModuleConfig {
         ModuleConfig {
-            tm: create_target_machine(sess),
             passes,
             opt_level: None,
             opt_size: None,
@@ -286,40 +285,6 @@ impl ModuleConfig {
         self.merge_functions = sess.opts.optimize == config::OptLevel::Default ||
                                sess.opts.optimize == config::OptLevel::Aggressive;
     }
-
-    fn clone(&self, sess: &Session) -> ModuleConfig {
-        ModuleConfig {
-            tm: create_target_machine(sess),
-            passes: self.passes.clone(),
-            opt_level: self.opt_level,
-            opt_size: self.opt_size,
-
-            emit_no_opt_bc: self.emit_no_opt_bc,
-            emit_bc: self.emit_bc,
-            emit_lto_bc: self.emit_lto_bc,
-            emit_ir: self.emit_ir,
-            emit_asm: self.emit_asm,
-            emit_obj: self.emit_obj,
-            obj_is_bitcode: self.obj_is_bitcode,
-
-            no_verify: self.no_verify,
-            no_prepopulate_passes: self.no_prepopulate_passes,
-            no_builtins: self.no_builtins,
-            time_passes: self.time_passes,
-            vectorize_loop: self.vectorize_loop,
-            vectorize_slp: self.vectorize_slp,
-            merge_functions: self.merge_functions,
-            inline_threshold: self.inline_threshold,
-        }
-    }
-}
-
-impl Drop for ModuleConfig {
-    fn drop(&mut self) {
-        unsafe {
-            llvm::LLVMRustDisposeTargetMachine(self.tm);
-        }
-    }
 }
 
 /// Additional resources used by optimize_and_codegen (not module specific)
@@ -333,6 +298,11 @@ pub struct CodegenContext {
     pub opts: Arc<config::Options>,
     pub crate_types: Vec<config::CrateType>,
     pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>,
+    output_filenames: Arc<OutputFilenames>,
+    regular_module_config: Arc<ModuleConfig>,
+    metadata_module_config: Arc<ModuleConfig>,
+    allocator_module_config: Arc<ModuleConfig>,
+
     // Handler to use for diagnostics produced during codegen.
     pub diag_emitter: SharedEmitter,
     // LLVM passes added by plugins.
@@ -345,7 +315,7 @@ pub struct CodegenContext {
     // compiling incrementally
     pub incr_comp_session_dir: Option<PathBuf>,
     // Channel back to the main control thread to send messages to
-    coordinator_send: Sender<Message>,
+    coordinator_send: Sender<Box<Any + Send>>,
     // A reference to the TimeGraph so we can register timings. None means that
     // measuring is disabled.
     time_graph: Option<TimeGraph>,
@@ -355,6 +325,14 @@ impl CodegenContext {
     fn create_diag_handler(&self) -> Handler {
         Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone()))
     }
+
+    fn config(&self, kind: ModuleKind) -> &ModuleConfig {
+        match kind {
+            ModuleKind::Regular => &self.regular_module_config,
+            ModuleKind::Metadata => &self.metadata_module_config,
+            ModuleKind::Allocator => &self.allocator_module_config,
+        }
+    }
 }
 
 struct HandlerFreeVars<'a> {
@@ -414,8 +392,8 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
 unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
                                diag_handler: &Handler,
                                mtrans: ModuleTranslation,
-                               config: ModuleConfig,
-                               output_names: OutputFilenames)
+                               tm: TargetMachineRef,
+                               config: &ModuleConfig)
     -> Result<CompiledModule, FatalError>
 {
     let (llmod, llcx) = match mtrans.source {
@@ -425,8 +403,6 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
         }
     };
 
-    let tm = config.tm;
-
     let fv = HandlerFreeVars {
         cgcx,
         diag_handler,
@@ -440,7 +416,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
     let module_name = Some(&module_name[..]);
 
     if config.emit_no_opt_bc {
-        let out = output_names.temp_path_ext("no-opt.bc", module_name);
+        let out = cgcx.output_filenames.temp_path_ext("no-opt.bc", module_name);
         let out = path2cstr(&out);
         llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
     }
@@ -513,7 +489,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
         if cgcx.lto {
             time(cgcx.time_passes, "all lto passes", || {
                 let temp_no_opt_bc_filename =
-                    output_names.temp_path_ext("no-opt.lto.bc", module_name);
+                    cgcx.output_filenames.temp_path_ext("no-opt.lto.bc", module_name);
                 lto::run(cgcx,
                          diag_handler,
                          llmod,
@@ -522,7 +498,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
                          &temp_no_opt_bc_filename)
             })?;
             if config.emit_lto_bc {
-                let out = output_names.temp_path_ext("lto.bc", module_name);
+                let out = cgcx.output_filenames.temp_path_ext("lto.bc", module_name);
                 let out = path2cstr(&out);
                 llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
             }
@@ -558,8 +534,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
     let write_obj = config.emit_obj && !config.obj_is_bitcode;
     let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode;
 
-    let bc_out = output_names.temp_path(OutputType::Bitcode, module_name);
-    let obj_out = output_names.temp_path(OutputType::Object, module_name);
+    let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
+    let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
 
     if write_bc {
         let bc_out_c = path2cstr(&bc_out);
@@ -569,7 +545,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
     time(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()),
          || -> Result<(), FatalError> {
         if config.emit_ir {
-            let out = output_names.temp_path(OutputType::LlvmAssembly, module_name);
+            let out = cgcx.output_filenames.temp_path(OutputType::LlvmAssembly, module_name);
             let out = path2cstr(&out);
 
             extern "C" fn demangle_callback(input_ptr: *const c_char,
@@ -610,7 +586,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
         }
 
         if config.emit_asm {
-            let path = output_names.temp_path(OutputType::Assembly, module_name);
+            let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
 
             // We can't use the same module for asm and binary output, because that triggers
             // various errors like invalid IR or broken binaries, so we might have to clone the
@@ -667,19 +643,34 @@ fn need_crate_bitcode_for_rlib(sess: &Session) -> bool {
     sess.opts.output_types.contains_key(&OutputType::Exe)
 }
 
-pub fn start_async_translation(sess: &Session,
-                               crate_output: &OutputFilenames,
+pub fn start_async_translation(tcx: TyCtxt,
                                time_graph: Option<TimeGraph>,
-                               crate_name: Symbol,
                                link: LinkMeta,
                                metadata: EncodedMetadata,
-                               exported_symbols: Arc<ExportedSymbols>,
-                               no_builtins: bool,
-                               windows_subsystem: Option<String>,
-                               linker_info: LinkerInfo,
-                               crate_info: CrateInfo,
-                               no_integrated_as: bool)
+                               coordinator_receive: Receiver<Box<Any + Send>>)
                                -> OngoingCrateTranslation {
+    let sess = tcx.sess;
+    let crate_output = tcx.output_filenames(LOCAL_CRATE);
+    let crate_name = tcx.crate_name(LOCAL_CRATE);
+    let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins");
+    let subsystem = attr::first_attr_value_str_by_name(&tcx.hir.krate().attrs,
+                                                       "windows_subsystem");
+    let windows_subsystem = subsystem.map(|subsystem| {
+        if subsystem != "windows" && subsystem != "console" {
+            tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \
+                                     `windows` and `console` are allowed",
+                                    subsystem));
+        }
+        subsystem.to_string()
+    });
+
+    let no_integrated_as = tcx.sess.opts.cg.no_integrated_as ||
+        (tcx.sess.target.target.options.no_integrated_as &&
+         (crate_output.outputs.contains_key(&OutputType::Object) ||
+          crate_output.outputs.contains_key(&OutputType::Exe)));
+    let linker_info = LinkerInfo::new(tcx);
+    let crate_info = CrateInfo::new(tcx);
+
     let output_types_override = if no_integrated_as {
         OutputTypes::new(&[(OutputType::Assembly, None)])
     } else {
@@ -687,9 +678,9 @@ pub fn start_async_translation(sess: &Session,
     };
 
     // Figure out what we actually need to build.
-    let mut modules_config = ModuleConfig::new(sess, sess.opts.cg.passes.clone());
-    let mut metadata_config = ModuleConfig::new(sess, vec![]);
-    let mut allocator_config = ModuleConfig::new(sess, vec![]);
+    let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone());
+    let mut metadata_config = ModuleConfig::new(vec![]);
+    let mut allocator_config = ModuleConfig::new(vec![]);
 
     if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
         match *sanitizer {
@@ -774,17 +765,18 @@ pub fn start_async_translation(sess: &Session,
 
     let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
     let (trans_worker_send, trans_worker_receive) = channel();
-    let (coordinator_send, coordinator_receive) = channel();
 
-    let coordinator_thread = start_executing_work(sess,
+    let coordinator_thread = start_executing_work(tcx,
                                                   &crate_info,
                                                   shared_emitter,
                                                   trans_worker_send,
-                                                  coordinator_send.clone(),
                                                   coordinator_receive,
                                                   client,
                                                   time_graph.clone(),
-                                                  exported_symbols.clone());
+                                                  Arc::new(modules_config),
+                                                  Arc::new(metadata_config),
+                                                  Arc::new(allocator_config));
+
     OngoingCrateTranslation {
         crate_name,
         link,
@@ -794,16 +786,12 @@ pub fn start_async_translation(sess: &Session,
         no_integrated_as,
         crate_info,
 
-        regular_module_config: modules_config,
-        metadata_module_config: metadata_config,
-        allocator_module_config: allocator_config,
-
         time_graph,
-        output_filenames: crate_output.clone(),
-        coordinator_send,
+        coordinator_send: tcx.tx_to_llvm_workers.clone(),
         trans_worker_receive,
         shared_emitter_main,
-        future: coordinator_thread
+        future: coordinator_thread,
+        output_filenames: tcx.output_filenames(LOCAL_CRATE),
     }
 }
 
@@ -1004,8 +992,7 @@ pub fn dump_incremental_data(trans: &CrateTranslation) {
 
 struct WorkItem {
     mtrans: ModuleTranslation,
-    config: ModuleConfig,
-    output_names: OutputFilenames
+    tm: TargetMachine,
 }
 
 impl fmt::Debug for WorkItem {
@@ -1014,15 +1001,15 @@ impl fmt::Debug for WorkItem {
     }
 }
 
-fn build_work_item(mtrans: ModuleTranslation,
-                   config: ModuleConfig,
-                   output_names: OutputFilenames)
-                   -> WorkItem
-{
-    WorkItem {
-        mtrans,
-        config,
-        output_names,
+struct TargetMachine(TargetMachineRef);
+
+unsafe impl Send for TargetMachine {}
+
+impl Drop for TargetMachine {
+    fn drop(&mut self) {
+        unsafe {
+            llvm::LLVMRustDisposeTargetMachine(self.0);
+        }
     }
 }
 
@@ -1031,6 +1018,7 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
 {
     let diag_handler = cgcx.create_diag_handler();
     let module_name = work_item.mtrans.name.clone();
+    let config = cgcx.config(work_item.mtrans.kind);
 
     let pre_existing = match work_item.mtrans.source {
         ModuleSource::Translated(_) => None,
@@ -1043,7 +1031,7 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
                                         .unwrap();
         let name = &work_item.mtrans.name;
         for (kind, saved_file) in wp.saved_files {
-            let obj_out = work_item.output_names.temp_path(kind, Some(name));
+            let obj_out = cgcx.output_filenames.temp_path(kind, Some(name));
             let source_file = in_incr_comp_dir(&incr_comp_session_dir,
                                                &saved_file);
             debug!("copying pre-existing module `{}` from {:?} to {}",
@@ -1066,8 +1054,8 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
             kind: ModuleKind::Regular,
             pre_existing: true,
             symbol_name_hash: work_item.mtrans.symbol_name_hash,
-            emit_bc: work_item.config.emit_bc,
-            emit_obj: work_item.config.emit_obj,
+            emit_bc: config.emit_bc,
+            emit_obj: config.emit_obj,
         })
     } else {
         debug!("llvm-optimizing {:?}", module_name);
@@ -1076,8 +1064,8 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
             optimize_and_codegen(cgcx,
                                  &diag_handler,
                                  work_item.mtrans,
-                                 work_item.config,
-                                 work_item.output_names)
+                                 work_item.tm.0,
+                                 config)
         }
     }
 }
@@ -1092,8 +1080,8 @@ enum Message {
     TranslationDone {
         llvm_work_item: WorkItem,
         cost: u64,
-        is_last: bool,
     },
+    TranslationComplete,
     TranslateItem,
 }
 
@@ -1110,16 +1098,26 @@ enum MainThreadWorkerState {
     LLVMing,
 }
 
-fn start_executing_work(sess: &Session,
+fn start_executing_work(tcx: TyCtxt,
                         crate_info: &CrateInfo,
                         shared_emitter: SharedEmitter,
                         trans_worker_send: Sender<Message>,
-                        coordinator_send: Sender<Message>,
-                        coordinator_receive: Receiver<Message>,
+                        coordinator_receive: Receiver<Box<Any + Send>>,
                         jobserver: Client,
                         time_graph: Option<TimeGraph>,
-                        exported_symbols: Arc<ExportedSymbols>)
+                        modules_config: Arc<ModuleConfig>,
+                        metadata_config: Arc<ModuleConfig>,
+                        allocator_config: Arc<ModuleConfig>)
                         -> thread::JoinHandle<CompiledModules> {
+    let coordinator_send = tcx.tx_to_llvm_workers.clone();
+    let mut exported_symbols = FxHashMap();
+    exported_symbols.insert(LOCAL_CRATE, tcx.exported_symbols(LOCAL_CRATE));
+    for &cnum in tcx.crates().iter() {
+        exported_symbols.insert(cnum, tcx.exported_symbols(cnum));
+    }
+    let exported_symbols = Arc::new(exported_symbols);
+    let sess = tcx.sess;
+
     // First up, convert our jobserver into a helper thread so we can use normal
     // mpsc channels to manage our messages and such. Once we've got the helper
     // thread then request `n-1` tokens because all of our work items are ready
@@ -1132,7 +1130,7 @@ fn start_executing_work(sess: &Session,
     // tokens on `rx` above which will get managed in the main loop below.
     let coordinator_send2 = coordinator_send.clone();
     let helper = jobserver.into_helper_thread(move |token| {
-        drop(coordinator_send2.send(Message::Token(token)));
+        drop(coordinator_send2.send(Box::new(Message::Token(token))));
     }).expect("failed to spawn helper thread");
 
     let mut each_linked_rlib_for_lto = Vec::new();
@@ -1158,6 +1156,10 @@ fn start_executing_work(sess: &Session,
         coordinator_send,
         diag_emitter: shared_emitter.clone(),
         time_graph,
+        output_filenames: tcx.output_filenames(LOCAL_CRATE),
+        regular_module_config: modules_config,
+        metadata_module_config: metadata_config,
+        allocator_module_config: allocator_config,
     };
 
     // This is the "main loop" of parallel work happening for parallel codegen.
@@ -1307,7 +1309,7 @@ fn start_executing_work(sess: &Session,
         let mut translation_done = false;
 
         // This is the queue of LLVM work items that still need processing.
-        let mut work_items = Vec::new();
+        let mut work_items = Vec::<(WorkItem, u64)>::new();
 
         // This are the Jobserver Tokens we currently hold. Does not include
         // the implicit Token the compiler process owns no matter what.
@@ -1346,7 +1348,8 @@ fn start_executing_work(sess: &Session,
                             worker: get_worker_id(&mut free_worker_ids),
                             .. cgcx.clone()
                         };
-                        maybe_start_llvm_timer(&item, &mut llvm_start_time);
+                        maybe_start_llvm_timer(cgcx.config(item.mtrans.kind),
+                                               &mut llvm_start_time);
                         main_thread_worker_state = MainThreadWorkerState::LLVMing;
                         spawn_work(cgcx, item);
                     }
@@ -1362,7 +1365,8 @@ fn start_executing_work(sess: &Session,
                                 worker: get_worker_id(&mut free_worker_ids),
                                 .. cgcx.clone()
                             };
-                            maybe_start_llvm_timer(&item, &mut llvm_start_time);
+                            maybe_start_llvm_timer(cgcx.config(item.mtrans.kind),
+                                                   &mut llvm_start_time);
                             main_thread_worker_state = MainThreadWorkerState::LLVMing;
                             spawn_work(cgcx, item);
                         } else {
@@ -1392,7 +1396,8 @@ fn start_executing_work(sess: &Session,
             while work_items.len() > 0 && running < tokens.len() {
                 let (item, _) = work_items.pop().unwrap();
 
-                maybe_start_llvm_timer(&item, &mut llvm_start_time);
+                maybe_start_llvm_timer(cgcx.config(item.mtrans.kind),
+                                       &mut llvm_start_time);
 
                 let cgcx = CodegenContext {
                     worker: get_worker_id(&mut free_worker_ids),
@@ -1406,7 +1411,8 @@ fn start_executing_work(sess: &Session,
             // Relinquish accidentally acquired extra tokens
             tokens.truncate(running);
 
-            match coordinator_receive.recv().unwrap() {
+            let msg = coordinator_receive.recv().unwrap();
+            match *msg.downcast::<Message>().ok().unwrap() {
                 // Save the token locally and the next turn of the loop will use
                 // this to spawn a new unit of work, or it may get dropped
                 // immediately if we have no more work to spawn.
@@ -1433,7 +1439,7 @@ fn start_executing_work(sess: &Session,
                     }
                 }
 
-                Message::TranslationDone { llvm_work_item, cost, is_last } => {
+                Message::TranslationDone { llvm_work_item, cost } => {
                     // We keep the queue sorted by estimated processing cost,
                     // so that more expensive items are processed earlier. This
                     // is good for throughput as it gives the main thread more
@@ -1449,15 +1455,14 @@ fn start_executing_work(sess: &Session,
                     };
                     work_items.insert(insertion_index, (llvm_work_item, cost));
 
-                    if is_last {
-                        // If this is the last, don't request a token because
-                        // the trans worker thread will be free to handle this
-                        // immediately.
-                        translation_done = true;
-                    } else {
-                        helper.request_token();
-                    }
+                    helper.request_token();
+                    assert_eq!(main_thread_worker_state,
+                               MainThreadWorkerState::Translating);
+                    main_thread_worker_state = MainThreadWorkerState::Idle;
+                }
 
+                Message::TranslationComplete => {
+                    translation_done = true;
                     assert_eq!(main_thread_worker_state,
                                MainThreadWorkerState::Translating);
                     main_thread_worker_state = MainThreadWorkerState::Idle;
@@ -1535,11 +1540,11 @@ fn start_executing_work(sess: &Session,
         items_in_queue >= max_workers.saturating_sub(workers_running / 2)
     }
 
-    fn maybe_start_llvm_timer(work_item: &WorkItem,
+    fn maybe_start_llvm_timer(config: &ModuleConfig,
                               llvm_start_time: &mut Option<Instant>) {
         // We keep track of the -Ztime-passes output manually,
         // since the closure-based interface does not fit well here.
-        if work_item.config.time_passes {
+        if config.time_passes {
             if llvm_start_time.is_none() {
                 *llvm_start_time = Some(Instant::now());
             }
@@ -1564,7 +1569,7 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
         // Set up a destructor which will fire off a message that we're done as
         // we exit.
         struct Bomb {
-            coordinator_send: Sender<Message>,
+            coordinator_send: Sender<Box<Any + Send>>,
             result: Option<CompiledModule>,
             worker_id: usize,
         }
@@ -1575,10 +1580,10 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
                     None => Err(())
                 };
 
-                drop(self.coordinator_send.send(Message::Done {
+                drop(self.coordinator_send.send(Box::new(Message::Done {
                     result,
                     worker_id: self.worker_id,
-                }));
+                })));
             }
         }
 
@@ -1814,17 +1819,12 @@ pub struct OngoingCrateTranslation {
     linker_info: LinkerInfo,
     no_integrated_as: bool,
     crate_info: CrateInfo,
-
-    output_filenames: OutputFilenames,
-    regular_module_config: ModuleConfig,
-    metadata_module_config: ModuleConfig,
-    allocator_module_config: ModuleConfig,
-
     time_graph: Option<TimeGraph>,
-    coordinator_send: Sender<Message>,
+    coordinator_send: Sender<Box<Any + Send>>,
     trans_worker_receive: Receiver<Message>,
     shared_emitter_main: SharedEmitterMain,
     future: thread::JoinHandle<CompiledModules>,
+    output_filenames: Arc<OutputFilenames>,
 }
 
 impl OngoingCrateTranslation {
@@ -1892,38 +1892,21 @@ impl OngoingCrateTranslation {
         trans
     }
 
-    pub fn submit_translated_module_to_llvm(&self,
-                                            sess: &Session,
-                                            mtrans: ModuleTranslation,
-                                            cost: u64,
-                                            is_last: bool) {
-        let module_config = match mtrans.kind {
-            ModuleKind::Regular => self.regular_module_config.clone(sess),
-            ModuleKind::Metadata => self.metadata_module_config.clone(sess),
-            ModuleKind::Allocator => self.allocator_module_config.clone(sess),
-        };
-
-        let llvm_work_item = build_work_item(mtrans,
-                                             module_config,
-                                             self.output_filenames.clone());
-
-        drop(self.coordinator_send.send(Message::TranslationDone {
-            llvm_work_item,
-            cost,
-            is_last
-        }));
-    }
-
     pub fn submit_pre_translated_module_to_llvm(&self,
-                                                sess: &Session,
-                                                mtrans: ModuleTranslation,
-                                                is_last: bool) {
+                                                tcx: TyCtxt,
+                                                mtrans: ModuleTranslation) {
         self.wait_for_signal_to_translate_item();
-        self.check_for_errors(sess);
+        self.check_for_errors(tcx.sess);
 
         // These are generally cheap and won't through off scheduling.
         let cost = 0;
-        self.submit_translated_module_to_llvm(sess, mtrans, cost, is_last);
+        submit_translated_module_to_llvm(tcx, mtrans, cost);
+    }
+
+    pub fn translation_finished(&self, tcx: TyCtxt) {
+        self.wait_for_signal_to_translate_item();
+        self.check_for_errors(tcx.sess);
+        drop(self.coordinator_send.send(Box::new(Message::TranslationComplete)));
     }
 
     pub fn check_for_errors(&self, sess: &Session) {
@@ -1945,3 +1928,16 @@ impl OngoingCrateTranslation {
         }
     }
 }
+
+pub fn submit_translated_module_to_llvm(tcx: TyCtxt,
+                                        mtrans: ModuleTranslation,
+                                        cost: u64) {
+    let llvm_work_item = WorkItem {
+        mtrans,
+        tm: TargetMachine(create_target_machine(tcx.sess)),
+    };
+    drop(tcx.tx_to_llvm_workers.send(Box::new(Message::TranslationDone {
+        llvm_work_item,
+        cost,
+    })));
+}
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 026417682cc..d86f88d4c7d 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -28,23 +28,24 @@ use super::ModuleSource;
 use super::ModuleTranslation;
 use super::ModuleKind;
 
-use assert_module_sources;
+use assert_module_sources::{self, Disposition};
 use back::link;
-use back::linker::LinkerInfo;
-use back::symbol_export::{self, ExportedSymbols};
+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, DefId, LOCAL_CRATE};
 use rustc::middle::lang_items::StartFnLangItem;
+use rustc::middle::trans::{Linkage, Visibility, Stats};
 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::hir::map as hir_map;
 use rustc::util::common::{time, print_time_passes_entry};
-use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType};
+use rustc::session::config::{self, NoDebugInfo};
 use rustc::session::Session;
 use rustc_incremental::{self, IncrementalHashesMap};
 use abi;
@@ -60,30 +61,34 @@ use common::CrateContext;
 use common::{type_is_zero_size, val_ty};
 use common;
 use consts;
-use context::{self, LocalCrateContext, SharedCrateContext, Stats};
+use context::{self, LocalCrateContext, SharedCrateContext};
 use debuginfo;
 use declare;
 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;
-use rustc::util::nodemap::{NodeSet, FxHashMap, FxHashSet};
+use rustc::util::nodemap::{NodeSet, FxHashMap, FxHashSet, DefIdSet};
 use CrateInfo;
 
 use libc::c_uint;
+use std::any::Any;
+use std::cell::RefCell;
 use std::ffi::{CStr, CString};
 use std::str;
 use std::sync::Arc;
 use std::time::{Instant, Duration};
 use std::i32;
+use std::sync::mpsc;
 use syntax_pos::Span;
+use syntax_pos::symbol::InternedString;
 use syntax::attr;
 use rustc::hir;
 use syntax::ast;
@@ -98,7 +103,7 @@ pub struct StatRecorder<'a, 'tcx: 'a> {
 
 impl<'a, 'tcx> StatRecorder<'a, 'tcx> {
     pub fn new(ccx: &'a CrateContext<'a, 'tcx>, name: String) -> StatRecorder<'a, 'tcx> {
-        let istart = ccx.stats().n_llvm_insns.get();
+        let istart = ccx.stats().borrow().n_llvm_insns;
         StatRecorder {
             ccx,
             name: Some(name),
@@ -110,12 +115,12 @@ impl<'a, 'tcx> StatRecorder<'a, 'tcx> {
 impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> {
     fn drop(&mut self) {
         if self.ccx.sess().trans_stats() {
-            let iend = self.ccx.stats().n_llvm_insns.get();
-            self.ccx.stats().fn_stats.borrow_mut()
-                .push((self.name.take().unwrap(), iend - self.istart));
-            self.ccx.stats().n_fns.set(self.ccx.stats().n_fns.get() + 1);
+            let mut stats = self.ccx.stats().borrow_mut();
+            let iend = stats.n_llvm_insns;
+            stats.fn_stats.push((self.name.take().unwrap(), iend - self.istart));
+            stats.n_fns += 1;
             // Reset LLVM insn count to avoid compound costs.
-            self.ccx.stats().n_llvm_insns.set(self.istart);
+            stats.n_llvm_insns = self.istart;
         }
     }
 }
@@ -578,7 +583,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
     // release builds.
     info!("trans_instance({})", instance);
 
-    let fn_ty = common::instance_ty(ccx.shared(), &instance);
+    let fn_ty = common::instance_ty(ccx.tcx(), &instance);
     let sig = common::ty_fn_sig(ccx, fn_ty);
     let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
 
@@ -587,7 +592,7 @@ pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance
         None => bug!("Instance `{:?}` not already declared", instance)
     };
 
-    ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
+    ccx.stats().borrow_mut().n_closures += 1;
 
     // The `uwtable` attribute according to LLVM is:
     //
@@ -614,7 +619,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
@@ -624,17 +631,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,
     }
 }
@@ -886,8 +893,8 @@ fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter {
 ///
 /// This list is later used by linkers to determine the set of symbols needed to
 /// be exposed from a dynamic library and it's also encoded into the metadata.
-pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet {
-    reachable.iter().cloned().filter(|&id| {
+pub fn find_exported_symbols(tcx: TyCtxt) -> NodeSet {
+    tcx.reachable_set(LOCAL_CRATE).iter().cloned().filter(|&id| {
         // Next, we want to ignore some FFI functions that are not exposed from
         // this crate. Reachable FFI functions can be lumped into two
         // categories:
@@ -929,25 +936,15 @@ pub fn find_exported_symbols(tcx: TyCtxt, reachable: &NodeSet) -> NodeSet {
 }
 
 pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                             analysis: ty::CrateAnalysis,
                              incremental_hashes_map: IncrementalHashesMap,
-                             output_filenames: &OutputFilenames)
+                             rx: mpsc::Receiver<Box<Any + Send>>)
                              -> OngoingCrateTranslation {
     check_for_rustc_errors_attr(tcx);
 
-    // Be careful with this krate: obviously it gives access to the
-    // entire contents of the krate. So if you push any subtasks of
-    // `TransCrate`, you need to be careful to register "reads" of the
-    // particular items that will be processed.
-    let krate = tcx.hir.krate();
-    let ty::CrateAnalysis { reachable, .. } = analysis;
-    let check_overflow = tcx.sess.overflow_checks();
     let link_meta = link::build_link_meta(&incremental_hashes_map);
-    let exported_symbol_node_ids = find_exported_symbols(tcx, &reachable);
+    let exported_symbol_node_ids = find_exported_symbols(tcx);
 
-    let shared_ccx = SharedCrateContext::new(tcx,
-                                             check_overflow,
-                                             output_filenames);
+    let shared_ccx = SharedCrateContext::new(tcx);
     // Translate the metadata.
     let (metadata_llcx, metadata_llmod, metadata, metadata_incr_hashes) =
         time(tcx.sess.time_passes(), "write metadata", || {
@@ -964,34 +961,24 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         kind: ModuleKind::Metadata,
     };
 
-    let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
     let time_graph = if tcx.sess.opts.debugging_opts.trans_time_graph {
         Some(time_graph::TimeGraph::new())
     } else {
         None
     };
-    let crate_info = CrateInfo::new(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::empty();
-        let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols);
         let ongoing_translation = write::start_async_translation(
-            tcx.sess,
-            output_filenames,
+            tcx,
             time_graph.clone(),
-            tcx.crate_name(LOCAL_CRATE),
             link_meta,
             metadata,
-            Arc::new(empty_exported_symbols),
-            no_builtins,
-            None,
-            linker_info,
-            crate_info,
-            false);
+            rx);
 
-        ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, metadata_module, true);
+        ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module);
+        ongoing_translation.translation_finished(tcx);
 
         assert_and_save_dep_graph(tcx,
                                   incremental_hashes_map,
@@ -1003,46 +990,20 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         return ongoing_translation;
     }
 
-    let exported_symbols = Arc::new(ExportedSymbols::compute(tcx,
-                                                             &exported_symbol_node_ids));
-
     // 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, &exported_symbols);
+    let codegen_units =
+        shared_ccx.tcx().collect_and_partition_translation_items(LOCAL_CRATE).1;
+    let codegen_units = (*codegen_units).clone();
 
     assert!(codegen_units.len() <= 1 || !tcx.sess.lto());
 
-    let linker_info = LinkerInfo::new(&shared_ccx, &exported_symbols);
-    let subsystem = attr::first_attr_value_str_by_name(&krate.attrs,
-                                                       "windows_subsystem");
-    let windows_subsystem = subsystem.map(|subsystem| {
-        if subsystem != "windows" && subsystem != "console" {
-            tcx.sess.fatal(&format!("invalid windows subsystem `{}`, only \
-                                     `windows` and `console` are allowed",
-                                    subsystem));
-        }
-        subsystem.to_string()
-    });
-
-    let no_integrated_as = tcx.sess.opts.cg.no_integrated_as ||
-        (tcx.sess.target.target.options.no_integrated_as &&
-         (output_filenames.outputs.contains_key(&OutputType::Object) ||
-          output_filenames.outputs.contains_key(&OutputType::Exe)));
-
     let ongoing_translation = write::start_async_translation(
-        tcx.sess,
-        output_filenames,
+        tcx,
         time_graph.clone(),
-        tcx.crate_name(LOCAL_CRATE),
         link_meta,
         metadata,
-        exported_symbols.clone(),
-        no_builtins,
-        windows_subsystem,
-        linker_info,
-        crate_info,
-        no_integrated_as);
+        rx);
 
     // Translate an allocator shim, if any
     //
@@ -1080,18 +1041,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     };
 
     if let Some(allocator_module) = allocator_module {
-        ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess, allocator_module, false);
+        ongoing_translation.submit_pre_translated_module_to_llvm(tcx, allocator_module);
     }
 
-    let codegen_unit_count = codegen_units.len();
-    ongoing_translation.submit_pre_translated_module_to_llvm(tcx.sess,
-                                                             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());
+    ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module);
 
     // We sort the codegen units by size. This way we can schedule work for LLVM
     // a bit more efficiently. Note that "size" is defined rather crudely at the
@@ -1104,221 +1057,57 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     };
 
     let mut total_trans_time = Duration::new(0, 0);
+    let mut all_stats = Stats::default();
 
-    for (cgu_index, cgu) in codegen_units.into_iter().enumerate() {
+    for cgu in codegen_units.into_iter() {
         ongoing_translation.wait_for_signal_to_translate_item();
         ongoing_translation.check_for_errors(tcx.sess);
 
+        let _timing_guard = time_graph
+            .as_ref()
+            .map(|time_graph| time_graph.start(write::TRANS_WORKER_TIMELINE,
+                                               write::TRANS_WORK_PACKAGE_KIND));
         let start_time = Instant::now();
+        all_stats.extend(tcx.compile_codegen_unit(*cgu.name()));
+        total_trans_time += start_time.elapsed();
 
-        let module = {
-            let _timing_guard = time_graph
-                .as_ref()
-                .map(|time_graph| time_graph.start(write::TRANS_WORKER_TIMELINE,
-                                                   write::TRANS_WORK_PACKAGE_KIND));
-            let dep_node = cgu.work_product_dep_node();
-            let ((stats, module), _) =
-                tcx.dep_graph.with_task(dep_node,
-                                        AssertDepGraphSafe(&shared_ccx),
-                                        AssertDepGraphSafe((cgu,
-                                                            translation_items.clone(),
-                                                            exported_symbols.clone())),
-                                        module_translation);
-            all_stats.extend(stats);
-
-            if let Some(ref mut module_dispositions) = module_dispositions {
-                module_dispositions.push(module.disposition());
-            }
-
-            module
-        };
-
-        let time_to_translate = Instant::now().duration_since(start_time);
-
-        // We assume that the cost to run LLVM on a CGU is proportional to
-        // the time we needed for translating it.
-        let cost = time_to_translate.as_secs() * 1_000_000_000 +
-                   time_to_translate.subsec_nanos() as u64;
-
-        total_trans_time += time_to_translate;
-
-        let is_last_cgu = (cgu_index + 1) == codegen_unit_count;
-
-        ongoing_translation.submit_translated_module_to_llvm(tcx.sess,
-                                                             module,
-                                                             cost,
-                                                             is_last_cgu);
         ongoing_translation.check_for_errors(tcx.sess);
     }
 
+    ongoing_translation.translation_finished(tcx);
+
     // Since the main thread is sometimes blocked during trans, we keep track
     // -Ztime-passes output manually.
     print_time_passes_entry(tcx.sess.time_passes(),
                             "translate to LLVM IR",
                             total_trans_time);
 
-    if let Some(module_dispositions) = module_dispositions {
-        assert_module_sources::assert_module_sources(tcx, &module_dispositions);
-    }
-
-    fn module_translation<'a, 'tcx>(
-        scx: AssertDepGraphSafe<&SharedCrateContext<'a, 'tcx>>,
-        args: AssertDepGraphSafe<(CodegenUnit<'tcx>,
-                                  Arc<FxHashSet<TransItem<'tcx>>>,
-                                  Arc<ExportedSymbols>)>)
-        -> (Stats, ModuleTranslation)
-    {
-        // FIXME(#40304): We ought to be using the id as a key and some queries, I think.
-        let AssertDepGraphSafe(scx) = scx;
-        let AssertDepGraphSafe((cgu, crate_trans_items, exported_symbols)) = args;
-
-        let cgu_name = String::from(cgu.name());
-        let cgu_id = cgu.work_product_id();
-        let symbol_name_hash = cgu.compute_symbol_name_hash(scx);
-
-        // Check whether there is a previous work-product we can
-        // re-use.  Not only must the file exist, and the inputs not
-        // be dirty, but the hash of the symbols we will generate must
-        // be the same.
-        let previous_work_product =
-            scx.dep_graph().previous_work_product(&cgu_id).and_then(|work_product| {
-                if work_product.input_hash == symbol_name_hash {
-                    debug!("trans_reuse_previous_work_products: reusing {:?}", work_product);
-                    Some(work_product)
-                } else {
-                    if scx.sess().opts.debugging_opts.incremental_info {
-                        eprintln!("incremental: CGU `{}` invalidated because of \
-                                   changed partitioning hash.",
-                                   cgu.name());
-                    }
-                    debug!("trans_reuse_previous_work_products: \
-                            not reusing {:?} because hash changed to {:?}",
-                           work_product, symbol_name_hash);
-                    None
-                }
-            });
-
-        if let Some(buf) = previous_work_product {
-            // Don't need to translate this module.
-            let module = ModuleTranslation {
-                name: cgu_name,
-                symbol_name_hash,
-                source: ModuleSource::Preexisting(buf.clone()),
-                kind: ModuleKind::Regular,
-            };
-            return (Stats::default(), module);
-        }
-
-        // Instantiate translation items without filling out definitions yet...
-        let lcx = LocalCrateContext::new(scx, cgu, crate_trans_items, exported_symbols);
-        let module = {
-            let ccx = CrateContext::new(scx, &lcx);
-            let trans_items = ccx.codegen_unit()
-                                 .items_in_deterministic_order(ccx.tcx());
-            for &(trans_item, (linkage, visibility)) in &trans_items {
-                trans_item.predefine(&ccx, linkage, visibility);
-            }
-
-            // ... and now that we have everything pre-defined, fill out those definitions.
-            for &(trans_item, _) in &trans_items {
-                trans_item.define(&ccx);
-            }
-
-            // If this codegen unit contains the main function, also create the
-            // wrapper here
-            maybe_create_entry_wrapper(&ccx);
-
-            // Run replace-all-uses-with for statics that need it
-            for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() {
-                unsafe {
-                    let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g));
-                    llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
-                    llvm::LLVMDeleteGlobal(old_g);
-                }
-            }
-
-            // Create the llvm.used variable
-            // This variable has type [N x i8*] and is stored in the llvm.metadata section
-            if !ccx.used_statics().borrow().is_empty() {
-                let name = CString::new("llvm.used").unwrap();
-                let section = CString::new("llvm.metadata").unwrap();
-                let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow());
-
-                unsafe {
-                    let g = llvm::LLVMAddGlobal(ccx.llmod(),
-                                                val_ty(array).to_ref(),
-                                                name.as_ptr());
-                    llvm::LLVMSetInitializer(g, array);
-                    llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
-                    llvm::LLVMSetSection(g, section.as_ptr());
-                }
-            }
-
-            // Finalize debuginfo
-            if ccx.sess().opts.debuginfo != NoDebugInfo {
-                debuginfo::finalize(&ccx);
-            }
-
-            let llvm_module = ModuleLlvm {
-                llcx: ccx.llcx(),
-                llmod: ccx.llmod(),
-            };
-
-            // In LTO mode we inject the allocator shim into the existing
-            // module.
-            if ccx.sess().lto() {
-                if let Some(kind) = ccx.sess().allocator_kind.get() {
-                    time(ccx.sess().time_passes(), "write allocator module", || {
-                        unsafe {
-                            allocator::trans(ccx.tcx(), &llvm_module, kind);
-                        }
-                    });
-                }
-            }
-
-            // Adjust exported symbols for MSVC dllimport
-            if ccx.sess().target.target.options.is_like_msvc &&
-               ccx.sess().crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
-                create_imps(ccx.sess(), &llvm_module);
-            }
-
-            ModuleTranslation {
-                name: cgu_name,
-                symbol_name_hash,
-                source: ModuleSource::Translated(llvm_module),
-                kind: ModuleKind::Regular,
-            }
-        };
-
-        (lcx.into_stats(), module)
+    if tcx.sess.opts.incremental.is_some() {
+        DISPOSITIONS.with(|d| {
+            assert_module_sources::assert_module_sources(tcx, &d.borrow());
+        });
     }
 
     symbol_names_test::report_symbol_names(tcx);
 
     if shared_ccx.sess().trans_stats() {
         println!("--- trans stats ---");
-        println!("n_glues_created: {}", all_stats.n_glues_created.get());
-        println!("n_null_glues: {}", all_stats.n_null_glues.get());
-        println!("n_real_glues: {}", all_stats.n_real_glues.get());
+        println!("n_glues_created: {}", all_stats.n_glues_created);
+        println!("n_null_glues: {}", all_stats.n_null_glues);
+        println!("n_real_glues: {}", all_stats.n_real_glues);
 
-        println!("n_fns: {}", all_stats.n_fns.get());
-        println!("n_inlines: {}", all_stats.n_inlines.get());
-        println!("n_closures: {}", all_stats.n_closures.get());
+        println!("n_fns: {}", all_stats.n_fns);
+        println!("n_inlines: {}", all_stats.n_inlines);
+        println!("n_closures: {}", all_stats.n_closures);
         println!("fn stats:");
-        all_stats.fn_stats.borrow_mut().sort_by(|&(_, insns_a), &(_, insns_b)| {
-            insns_b.cmp(&insns_a)
-        });
-        for tuple in all_stats.fn_stats.borrow().iter() {
-            match *tuple {
-                (ref name, insns) => {
-                    println!("{} insns, {}", insns, *name);
-                }
-            }
+        all_stats.fn_stats.sort_by_key(|&(_, insns)| insns);
+        for &(ref name, insns) in all_stats.fn_stats.iter() {
+            println!("{} insns, {}", insns, *name);
         }
     }
 
     if shared_ccx.sess().count_llvm_insns() {
-        for (k, v) in all_stats.llvm_insns.borrow().iter() {
+        for (k, v) in all_stats.llvm_insns.iter() {
             println!("{:7} {}", *v, *k);
         }
     }
@@ -1332,6 +1121,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     ongoing_translation
 }
 
+// FIXME(#42293) hopefully once red/green is enabled we're testing everything
+// via a method that doesn't require this!
+thread_local!(static DISPOSITIONS: RefCell<Vec<(String, Disposition)>> = Default::default());
+
 fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                        incremental_hashes_map: IncrementalHashesMap,
                                        metadata_incr_hashes: EncodedMetadataHashes,
@@ -1396,13 +1189,15 @@ fn assert_symbols_are_distinct<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trans_i
     }
 }
 
-fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
-                                                     exported_symbols: &ExportedSymbols)
-                                                     -> (FxHashSet<TransItem<'tcx>>,
-                                                         Vec<CodegenUnit<'tcx>>) {
-    let time_passes = scx.sess().time_passes();
+fn collect_and_partition_translation_items<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    cnum: CrateNum,
+) -> (Arc<DefIdSet>, Arc<Vec<Arc<CodegenUnit<'tcx>>>>)
+{
+    assert_eq!(cnum, LOCAL_CRATE);
+    let time_passes = tcx.sess.time_passes();
 
-    let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items {
+    let collection_mode = match tcx.sess.opts.debugging_opts.print_trans_items {
         Some(ref s) => {
             let mode_string = s.to_lowercase();
             let mode_string = mode_string.trim();
@@ -1413,7 +1208,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
                     let message = format!("Unknown codegen-item collection mode '{}'. \
                                            Falling back to 'lazy' mode.",
                                            mode_string);
-                    scx.sess().warn(&message);
+                    tcx.sess.warn(&message);
                 }
 
                 TransItemCollectionMode::Lazy
@@ -1424,33 +1219,38 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
 
     let (items, inlining_map) =
         time(time_passes, "translation item collection", || {
-            collector::collect_crate_translation_items(&scx,
-                                                       exported_symbols,
-                                                       collection_mode)
+            collector::collect_crate_translation_items(tcx, collection_mode)
     });
 
-    assert_symbols_are_distinct(scx.tcx(), items.iter());
+    assert_symbols_are_distinct(tcx, items.iter());
 
-    let strategy = if scx.sess().opts.debugging_opts.incremental.is_some() {
+    let strategy = if tcx.sess.opts.debugging_opts.incremental.is_some() {
         PartitioningStrategy::PerModule
     } else {
-        PartitioningStrategy::FixedUnitCount(scx.sess().opts.cg.codegen_units)
+        PartitioningStrategy::FixedUnitCount(tcx.sess.opts.cg.codegen_units)
     };
 
     let codegen_units = time(time_passes, "codegen unit partitioning", || {
-        partitioning::partition(scx,
+        partitioning::partition(tcx,
                                 items.iter().cloned(),
                                 strategy,
-                                &inlining_map,
-                                exported_symbols)
+                                &inlining_map)
+            .into_iter()
+            .map(Arc::new)
+            .collect::<Vec<_>>()
     });
 
-    assert!(scx.tcx().sess.opts.cg.codegen_units == codegen_units.len() ||
-            scx.tcx().sess.opts.debugging_opts.incremental.is_some());
+    assert!(tcx.sess.opts.cg.codegen_units == codegen_units.len() ||
+            tcx.sess.opts.debugging_opts.incremental.is_some());
 
-    let translation_items: FxHashSet<TransItem<'tcx>> = items.iter().cloned().collect();
+    let translation_items: DefIdSet = items.iter().filter_map(|trans_item| {
+        match *trans_item {
+            TransItem::Fn(ref instance) => Some(instance.def_id()),
+            _ => None,
+        }
+    }).collect();
 
-    if scx.sess().opts.debugging_opts.print_trans_items.is_some() {
+    if tcx.sess.opts.debugging_opts.print_trans_items.is_some() {
         let mut item_to_cgus = FxHashMap();
 
         for cgu in &codegen_units {
@@ -1464,7 +1264,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
         let mut item_keys: Vec<_> = items
             .iter()
             .map(|i| {
-                let mut output = i.to_string(scx.tcx());
+                let mut output = i.to_string(tcx);
                 output.push_str(" @@");
                 let mut empty = Vec::new();
                 let cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
@@ -1475,17 +1275,17 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
                     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("[");
@@ -1503,11 +1303,11 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
         }
     }
 
-    (translation_items, codegen_units)
+    (Arc::new(translation_items), Arc::new(codegen_units))
 }
 
 impl CrateInfo {
-    pub fn new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CrateInfo {
+    pub fn new(tcx: TyCtxt) -> CrateInfo {
         let mut info = CrateInfo {
             panic_runtime: None,
             compiler_builtins: None,
@@ -1548,3 +1348,222 @@ impl CrateInfo {
         return info
     }
 }
+
+fn is_translated_function(tcx: TyCtxt, id: DefId) -> bool {
+    // FIXME(#42293) needs red/green tracking to avoid failing a bunch of
+    // existing tests
+    tcx.dep_graph.with_ignore(|| {
+        let (all_trans_items, _) =
+            tcx.collect_and_partition_translation_items(LOCAL_CRATE);
+        all_trans_items.contains(&id)
+    })
+}
+
+fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                  cgu: InternedString) -> Stats {
+    // FIXME(#42293) needs red/green tracking to avoid failing a bunch of
+    // existing tests
+    let cgu = tcx.dep_graph.with_ignore(|| {
+        tcx.codegen_unit(cgu)
+    });
+
+    let start_time = Instant::now();
+    let dep_node = cgu.work_product_dep_node();
+    let ((stats, module), _) =
+        tcx.dep_graph.with_task(dep_node,
+                                AssertDepGraphSafe(tcx),
+                                AssertDepGraphSafe(cgu),
+                                module_translation);
+    let time_to_translate = start_time.elapsed();
+
+    if tcx.sess.opts.incremental.is_some() {
+        DISPOSITIONS.with(|d| {
+            d.borrow_mut().push(module.disposition());
+        });
+    }
+
+    // We assume that the cost to run LLVM on a CGU is proportional to
+    // the time we needed for translating it.
+    let cost = time_to_translate.as_secs() * 1_000_000_000 +
+               time_to_translate.subsec_nanos() as u64;
+
+    write::submit_translated_module_to_llvm(tcx,
+                                            module,
+                                            cost);
+    return stats;
+
+    fn module_translation<'a, 'tcx>(
+        tcx: AssertDepGraphSafe<TyCtxt<'a, 'tcx, 'tcx>>,
+        args: AssertDepGraphSafe<Arc<CodegenUnit<'tcx>>>)
+        -> (Stats, ModuleTranslation)
+    {
+        // FIXME(#40304): We ought to be using the id as a key and some queries, I think.
+        let AssertDepGraphSafe(tcx) = tcx;
+        let AssertDepGraphSafe(cgu) = args;
+
+        let cgu_name = cgu.name().to_string();
+        let cgu_id = cgu.work_product_id();
+        let symbol_name_hash = cgu.compute_symbol_name_hash(tcx);
+
+        // Check whether there is a previous work-product we can
+        // re-use.  Not only must the file exist, and the inputs not
+        // be dirty, but the hash of the symbols we will generate must
+        // be the same.
+        let previous_work_product =
+            tcx.dep_graph.previous_work_product(&cgu_id).and_then(|work_product| {
+                if work_product.input_hash == symbol_name_hash {
+                    debug!("trans_reuse_previous_work_products: reusing {:?}", work_product);
+                    Some(work_product)
+                } else {
+                    if tcx.sess.opts.debugging_opts.incremental_info {
+                        eprintln!("incremental: CGU `{}` invalidated because of \
+                                   changed partitioning hash.",
+                                   cgu.name());
+                    }
+                    debug!("trans_reuse_previous_work_products: \
+                            not reusing {:?} because hash changed to {:?}",
+                           work_product, symbol_name_hash);
+                    None
+                }
+            });
+
+        if let Some(buf) = previous_work_product {
+            // Don't need to translate this module.
+            let module = ModuleTranslation {
+                name: cgu_name,
+                symbol_name_hash,
+                source: ModuleSource::Preexisting(buf.clone()),
+                kind: ModuleKind::Regular,
+            };
+            return (Stats::default(), module);
+        }
+
+        // Instantiate translation items without filling out definitions yet...
+        let scx = SharedCrateContext::new(tcx);
+        let lcx = LocalCrateContext::new(&scx, cgu);
+        let module = {
+            let ccx = CrateContext::new(&scx, &lcx);
+            let trans_items = ccx.codegen_unit()
+                                 .items_in_deterministic_order(ccx.tcx());
+            for &(trans_item, (linkage, visibility)) in &trans_items {
+                trans_item.predefine(&ccx, linkage, visibility);
+            }
+
+            // ... and now that we have everything pre-defined, fill out those definitions.
+            for &(trans_item, _) in &trans_items {
+                trans_item.define(&ccx);
+            }
+
+            // If this codegen unit contains the main function, also create the
+            // wrapper here
+            maybe_create_entry_wrapper(&ccx);
+
+            // Run replace-all-uses-with for statics that need it
+            for &(old_g, new_g) in ccx.statics_to_rauw().borrow().iter() {
+                unsafe {
+                    let bitcast = llvm::LLVMConstPointerCast(new_g, llvm::LLVMTypeOf(old_g));
+                    llvm::LLVMReplaceAllUsesWith(old_g, bitcast);
+                    llvm::LLVMDeleteGlobal(old_g);
+                }
+            }
+
+            // Create the llvm.used variable
+            // This variable has type [N x i8*] and is stored in the llvm.metadata section
+            if !ccx.used_statics().borrow().is_empty() {
+                let name = CString::new("llvm.used").unwrap();
+                let section = CString::new("llvm.metadata").unwrap();
+                let array = C_array(Type::i8(&ccx).ptr_to(), &*ccx.used_statics().borrow());
+
+                unsafe {
+                    let g = llvm::LLVMAddGlobal(ccx.llmod(),
+                                                val_ty(array).to_ref(),
+                                                name.as_ptr());
+                    llvm::LLVMSetInitializer(g, array);
+                    llvm::LLVMRustSetLinkage(g, llvm::Linkage::AppendingLinkage);
+                    llvm::LLVMSetSection(g, section.as_ptr());
+                }
+            }
+
+            // Finalize debuginfo
+            if ccx.sess().opts.debuginfo != NoDebugInfo {
+                debuginfo::finalize(&ccx);
+            }
+
+            let llvm_module = ModuleLlvm {
+                llcx: ccx.llcx(),
+                llmod: ccx.llmod(),
+            };
+
+            // In LTO mode we inject the allocator shim into the existing
+            // module.
+            if ccx.sess().lto() {
+                if let Some(kind) = ccx.sess().allocator_kind.get() {
+                    time(ccx.sess().time_passes(), "write allocator module", || {
+                        unsafe {
+                            allocator::trans(ccx.tcx(), &llvm_module, kind);
+                        }
+                    });
+                }
+            }
+
+            // Adjust exported symbols for MSVC dllimport
+            if ccx.sess().target.target.options.is_like_msvc &&
+               ccx.sess().crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
+                create_imps(ccx.sess(), &llvm_module);
+            }
+
+            ModuleTranslation {
+                name: cgu_name,
+                symbol_name_hash,
+                source: ModuleSource::Translated(llvm_module),
+                kind: ModuleKind::Regular,
+            }
+        };
+
+        (lcx.into_stats(), module)
+    }
+}
+
+pub fn provide_local(providers: &mut Providers) {
+    providers.collect_and_partition_translation_items =
+        collect_and_partition_translation_items;
+
+    providers.is_translated_function = is_translated_function;
+
+    providers.codegen_unit = |tcx, name| {
+        let (_, all) = tcx.collect_and_partition_translation_items(LOCAL_CRATE);
+        all.iter()
+            .find(|cgu| *cgu.name() == name)
+            .cloned()
+            .expect(&format!("failed to find cgu with name {:?}", name))
+    };
+    providers.compile_codegen_unit = compile_codegen_unit;
+}
+
+pub fn provide_extern(providers: &mut Providers) {
+    providers.is_translated_function = is_translated_function;
+}
+
+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/builder.rs b/src/librustc_trans/builder.rs
index 8a585e72f59..41a238ea8e3 100644
--- a/src/librustc_trans/builder.rs
+++ b/src/librustc_trans/builder.rs
@@ -101,11 +101,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
     fn count_insn(&self, category: &str) {
         if self.ccx.sess().trans_stats() {
-            self.ccx.stats().n_llvm_insns.set(self.ccx.stats().n_llvm_insns.get() + 1);
+            self.ccx.stats().borrow_mut().n_llvm_insns += 1;
         }
         if self.ccx.sess().count_llvm_insns() {
-            let mut h = self.ccx.stats().llvm_insns.borrow_mut();
-            *h.entry(category.to_string()).or_insert(0) += 1;
+            *self.ccx.stats()
+                .borrow_mut()
+                .llvm_insns
+                .entry(category.to_string())
+                .or_insert(0) += 1;
         }
     }
 
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index 246eb49ffa6..52e6dce24ed 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -23,7 +23,6 @@ use monomorphize::{self, Instance};
 use rustc::hir::def_id::DefId;
 use rustc::ty::TypeFoldable;
 use rustc::ty::subst::Substs;
-use trans_item::TransItem;
 use type_of;
 
 /// Translates a reference to a fn/method item, monomorphizing and
@@ -45,7 +44,7 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     assert!(!instance.substs.has_escaping_regions());
     assert!(!instance.substs.has_param_types());
 
-    let fn_ty = common::instance_ty(ccx.shared(), &instance);
+    let fn_ty = common::instance_ty(ccx.tcx(), &instance);
     if let Some(&llfn) = ccx.instances().borrow().get(&instance) {
         return llfn;
     }
@@ -53,35 +52,34 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let sym = tcx.symbol_name(instance);
     debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);
 
-    // This is subtle and surprising, but sometimes we have to bitcast
-    // the resulting fn pointer.  The reason has to do with external
-    // functions.  If you have two crates that both bind the same C
-    // library, they may not use precisely the same types: for
-    // example, they will probably each declare their own structs,
-    // which are distinct types from LLVM's point of view (nominal
-    // types).
-    //
-    // Now, if those two crates are linked into an application, and
-    // they contain inlined code, you can wind up with a situation
-    // where both of those functions wind up being loaded into this
-    // application simultaneously. In that case, the same function
-    // (from LLVM's point of view) requires two types. But of course
-    // LLVM won't allow one function to have two types.
-    //
-    // What we currently do, therefore, is declare the function with
-    // one of the two types (whichever happens to come first) and then
-    // bitcast as needed when the function is referenced to make sure
-    // it has the type we expect.
-    //
-    // This can occur on either a crate-local or crate-external
-    // reference. It also occurs when testing libcore and in some
-    // other weird situations. Annoying.
-
     // Create a fn pointer with the substituted signature.
     let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(ccx, fn_ty));
     let llptrty = type_of::type_of(ccx, fn_ptr_ty);
 
     let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
+        // This is subtle and surprising, but sometimes we have to bitcast
+        // the resulting fn pointer.  The reason has to do with external
+        // functions.  If you have two crates that both bind the same C
+        // library, they may not use precisely the same types: for
+        // example, they will probably each declare their own structs,
+        // which are distinct types from LLVM's point of view (nominal
+        // types).
+        //
+        // Now, if those two crates are linked into an application, and
+        // they contain inlined code, you can wind up with a situation
+        // where both of those functions wind up being loaded into this
+        // application simultaneously. In that case, the same function
+        // (from LLVM's point of view) requires two types. But of course
+        // LLVM won't allow one function to have two types.
+        //
+        // What we currently do, therefore, is declare the function with
+        // one of the two types (whichever happens to come first) and then
+        // bitcast as needed when the function is referenced to make sure
+        // it has the type we expect.
+        //
+        // This can occur on either a crate-local or crate-external
+        // reference. It also occurs when testing libcore and in some
+        // other weird situations. Annoying.
         if common::val_ty(llfn) != llptrty {
             debug!("get_fn: casting {:?} to {:?}", llfn, llptrty);
             consts::ptrcast(llfn, llptrty)
@@ -110,12 +108,45 @@ pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             attributes::unwind(llfn, true);
         }
 
+        // Apply an appropriate linkage/visibility value to our item that we
+        // just declared.
+        //
+        // This is sort of subtle. Inside our codegen unit we started off
+        // compilation by predefining all our own `TransItem` instances. That
+        // is, everything we're translating ourselves is already defined. That
+        // means that anything we're actually translating ourselves will have
+        // hit the above branch in `get_declared_value`. As a result, we're
+        // guaranteed here that we're declaring a symbol that won't get defined,
+        // or in other words we're referencing a foreign value.
+        //
+        // So because this is a foreign value we blanket apply an external
+        // linkage directive because it's coming from a different object file.
+        // The visibility here is where it gets tricky. This symbol could be
+        // referencing some foreign crate or foreign library (an `extern`
+        // block) in which case we want to leave the default visibility. We may
+        // also, though, have multiple codegen units.
+        //
+        // In the situation of multiple codegen units this function may be
+        // referencing a function from another codegen unit. If we're
+        // indeed referencing a symbol in another codegen unit then we're in one
+        // of two cases:
+        //
+        //  * This is a symbol defined in a foreign crate and we're just
+        //    monomorphizing in another codegen unit. In this case this symbols
+        //    is for sure not exported, so both codegen units will be using
+        //    hidden visibility. Hence, we apply a hidden visibility here.
+        //
+        //  * This is a symbol defined in our local crate. If the symbol in the
+        //    other codegen unit is also not exported then like with the foreign
+        //    case we apply a hidden visibility. If the symbol is exported from
+        //    the foreign object file, however, then we leave this at the
+        //    default visibility as we'll just import it naturally.
         unsafe {
             llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::ExternalLinkage);
 
-            if ccx.crate_trans_items().contains(&TransItem::Fn(instance)) {
-                if let Some(node_id) = tcx.hir.as_local_node_id(instance_def_id) {
-                    if !ccx.exported_symbols().local_exports().contains(&node_id) {
+            if ccx.tcx().is_translated_function(instance_def_id) {
+                if instance_def_id.is_local() {
+                    if !ccx.tcx().is_exported_symbol(instance_def_id) {
                         llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
                     }
                 } else {
@@ -148,5 +179,5 @@ pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                     substs: &'tcx Substs<'tcx>)
                                     -> ValueRef
 {
-    get_fn(ccx, monomorphize::resolve(ccx.shared(), def_id, substs))
+    get_fn(ccx, monomorphize::resolve(ccx.tcx(), def_id, substs))
 }
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index f0d8c7e9bfb..6fa69de74b0 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -202,15 +202,13 @@ use rustc::ty::adjustment::CustomCoerceUnsized;
 use rustc::mir::{self, Location};
 use rustc::mir::visit::Visitor as MirVisitor;
 
-use context::SharedCrateContext;
-use common::{def_ty, instance_ty};
+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;
-use back::symbol_export::ExportedSymbols;
 
 #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
 pub enum TransItemCollectionMode {
@@ -294,15 +292,14 @@ impl<'tcx> InliningMap<'tcx> {
     }
 }
 
-pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
-                                                 exported_symbols: &ExportedSymbols,
+pub fn collect_crate_translation_items<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                  mode: TransItemCollectionMode)
                                                  -> (FxHashSet<TransItem<'tcx>>,
                                                      InliningMap<'tcx>) {
     // We are not tracking dependencies of this pass as it has to be re-executed
     // every time no matter what.
-    scx.tcx().dep_graph.with_ignore(|| {
-        let roots = collect_roots(scx, exported_symbols, mode);
+    tcx.dep_graph.with_ignore(|| {
+        let roots = collect_roots(tcx, mode);
 
         debug!("Building translation item graph, beginning at roots");
         let mut visited = FxHashSet();
@@ -310,7 +307,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 't
         let mut inlining_map = InliningMap::new();
 
         for root in roots {
-            collect_items_rec(scx,
+            collect_items_rec(tcx,
                               root,
                               &mut visited,
                               &mut recursion_depths,
@@ -323,8 +320,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 't
 
 // Find all non-generic items by walking the HIR. These items serve as roots to
 // start monomorphizing from.
-fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
-                           exported_symbols: &ExportedSymbols,
+fn collect_roots<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            mode: TransItemCollectionMode)
                            -> Vec<TransItem<'tcx>> {
     debug!("Collecting roots");
@@ -332,25 +328,24 @@ fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
     {
         let mut visitor = RootCollector {
-            scx,
+            tcx,
             mode,
-            exported_symbols,
             output: &mut roots,
         };
 
-        scx.tcx().hir.krate().visit_all_item_likes(&mut visitor);
+        tcx.hir.krate().visit_all_item_likes(&mut visitor);
     }
 
     // We can only translate items that are instantiable - items all of
     // whose predicates hold. Luckily, items that aren't instantiable
     // can't actually be used, so we can just skip translating them.
-    roots.retain(|root| root.is_instantiable(scx.tcx()));
+    roots.retain(|root| root.is_instantiable(tcx));
 
     roots
 }
 
 // Collect all monomorphized translation items reachable from `starting_point`
-fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
+fn collect_items_rec<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                    starting_point: TransItem<'tcx>,
                                    visited: &mut FxHashSet<TransItem<'tcx>>,
                                    recursion_depths: &mut DefIdMap<usize>,
@@ -359,54 +354,54 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
         // We've been here already, no need to search again.
         return;
     }
-    debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx.tcx()));
+    debug!("BEGIN collect_items_rec({})", starting_point.to_string(tcx));
 
     let mut neighbors = Vec::new();
     let recursion_depth_reset;
 
     match starting_point {
         TransItem::Static(node_id) => {
-            let def_id = scx.tcx().hir.local_def_id(node_id);
-            let instance = Instance::mono(scx.tcx(), def_id);
+            let def_id = tcx.hir.local_def_id(node_id);
+            let instance = Instance::mono(tcx, def_id);
 
             // Sanity check whether this ended up being collected accidentally
-            debug_assert!(should_trans_locally(scx.tcx(), &instance));
+            debug_assert!(should_trans_locally(tcx, &instance));
 
-            let ty = instance_ty(scx, &instance);
-            visit_drop_use(scx, ty, true, &mut neighbors);
+            let ty = instance_ty(tcx, &instance);
+            visit_drop_use(tcx, ty, true, &mut neighbors);
 
             recursion_depth_reset = None;
 
-            collect_neighbours(scx, instance, true, &mut neighbors);
+            collect_neighbours(tcx, instance, true, &mut neighbors);
         }
         TransItem::Fn(instance) => {
             // Sanity check whether this ended up being collected accidentally
-            debug_assert!(should_trans_locally(scx.tcx(), &instance));
+            debug_assert!(should_trans_locally(tcx, &instance));
 
             // Keep track of the monomorphization recursion depth
-            recursion_depth_reset = Some(check_recursion_limit(scx.tcx(),
+            recursion_depth_reset = Some(check_recursion_limit(tcx,
                                                                instance,
                                                                recursion_depths));
-            check_type_length_limit(scx.tcx(), instance);
+            check_type_length_limit(tcx, instance);
 
-            collect_neighbours(scx, instance, false, &mut neighbors);
+            collect_neighbours(tcx, instance, false, &mut neighbors);
         }
         TransItem::GlobalAsm(..) => {
             recursion_depth_reset = None;
         }
     }
 
-    record_accesses(scx.tcx(), starting_point, &neighbors[..], inlining_map);
+    record_accesses(tcx, starting_point, &neighbors[..], inlining_map);
 
     for neighbour in neighbors {
-        collect_items_rec(scx, neighbour, visited, recursion_depths, inlining_map);
+        collect_items_rec(tcx, neighbour, visited, recursion_depths, inlining_map);
     }
 
     if let Some((def_id, depth)) = recursion_depth_reset {
         recursion_depths.insert(def_id, depth);
     }
 
-    debug!("END collect_items_rec({})", starting_point.to_string(scx.tcx()));
+    debug!("END collect_items_rec({})", starting_point.to_string(tcx));
 }
 
 fn record_accesses<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -494,7 +489,7 @@ fn check_type_length_limit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 }
 
 struct MirNeighborCollector<'a, 'tcx: 'a> {
-    scx: &'a SharedCrateContext<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     mir: &'a mir::Mir<'tcx>,
     output: &'a mut Vec<TransItem<'tcx>>,
     param_substs: &'tcx Substs<'tcx>,
@@ -511,49 +506,49 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
             // have to instantiate all methods of the trait being cast to, so we
             // can build the appropriate vtable.
             mir::Rvalue::Cast(mir::CastKind::Unsize, ref operand, target_ty) => {
-                let target_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
-                                                                        &target_ty);
-                let source_ty = operand.ty(self.mir, self.scx.tcx());
-                let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
-                                                                        &source_ty);
-                let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx,
+                let target_ty = self.tcx.trans_apply_param_substs(self.param_substs,
+                                                                  &target_ty);
+                let source_ty = operand.ty(self.mir, self.tcx);
+                let source_ty = self.tcx.trans_apply_param_substs(self.param_substs,
+                                                                  &source_ty);
+                let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.tcx,
                                                                             source_ty,
                                                                             target_ty);
                 // This could also be a different Unsize instruction, like
                 // from a fixed sized array to a slice. But we are only
                 // interested in things that produce a vtable.
                 if target_ty.is_trait() && !source_ty.is_trait() {
-                    create_trans_items_for_vtable_methods(self.scx,
+                    create_trans_items_for_vtable_methods(self.tcx,
                                                           target_ty,
                                                           source_ty,
                                                           self.output);
                 }
             }
             mir::Rvalue::Cast(mir::CastKind::ReifyFnPointer, ref operand, _) => {
-                let fn_ty = operand.ty(self.mir, self.scx.tcx());
-                let fn_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
-                                                                    &fn_ty);
-                visit_fn_use(self.scx, fn_ty, false, &mut self.output);
+                let fn_ty = operand.ty(self.mir, self.tcx);
+                let fn_ty = self.tcx.trans_apply_param_substs(self.param_substs,
+                                                              &fn_ty);
+                visit_fn_use(self.tcx, fn_ty, false, &mut self.output);
             }
             mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => {
-                let source_ty = operand.ty(self.mir, self.scx.tcx());
-                let source_ty = self.scx.tcx().trans_apply_param_substs(self.param_substs,
-                                                                        &source_ty);
+                let source_ty = operand.ty(self.mir, self.tcx);
+                let source_ty = self.tcx.trans_apply_param_substs(self.param_substs,
+                                                                  &source_ty);
                 match source_ty.sty {
                     ty::TyClosure(def_id, substs) => {
                         let instance = monomorphize::resolve_closure(
-                            self.scx, def_id, substs, ty::ClosureKind::FnOnce);
+                            self.tcx, def_id, substs, ty::ClosureKind::FnOnce);
                         self.output.push(create_fn_trans_item(instance));
                     }
                     _ => bug!(),
                 }
             }
             mir::Rvalue::NullaryOp(mir::NullOp::Box, _) => {
-                let tcx = self.scx.tcx();
+                let tcx = self.tcx;
                 let exchange_malloc_fn_def_id = tcx
                     .lang_items()
                     .require(ExchangeMallocFnLangItem)
-                    .unwrap_or_else(|e| self.scx.sess().fatal(&e));
+                    .unwrap_or_else(|e| tcx.sess.fatal(&e));
                 let instance = Instance::mono(tcx, exchange_malloc_fn_def_id);
                 if should_trans_locally(tcx, &instance) {
                     self.output.push(create_fn_trans_item(instance));
@@ -569,10 +564,10 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
         debug!("visiting const {:?} @ {:?}", *constant, location);
 
         if let ConstVal::Unevaluated(def_id, substs) = constant.val {
-            let substs = self.scx.tcx().trans_apply_param_substs(self.param_substs,
-                                                                 &substs);
-            let instance = monomorphize::resolve(self.scx, def_id, substs);
-            collect_neighbours(self.scx, instance, true, self.output);
+            let substs = self.tcx.trans_apply_param_substs(self.param_substs,
+                                                           &substs);
+            let instance = monomorphize::resolve(self.tcx, def_id, substs);
+            collect_neighbours(self.tcx, instance, true, self.output);
         }
 
         self.super_const(constant);
@@ -584,15 +579,15 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                              location: Location) {
         debug!("visiting terminator {:?} @ {:?}", kind, location);
 
-        let tcx = self.scx.tcx();
+        let tcx = self.tcx;
         match *kind {
             mir::TerminatorKind::Call { ref func, .. } => {
                 let callee_ty = func.ty(self.mir, tcx);
                 let callee_ty = tcx.trans_apply_param_substs(self.param_substs, &callee_ty);
 
                 let constness = match (self.const_context, &callee_ty.sty) {
-                    (true, &ty::TyFnDef(def_id, substs)) if self.scx.tcx().is_const_fn(def_id) => {
-                        let instance = monomorphize::resolve(self.scx, def_id, substs);
+                    (true, &ty::TyFnDef(def_id, substs)) if self.tcx.is_const_fn(def_id) => {
+                        let instance = monomorphize::resolve(self.tcx, def_id, substs);
                         Some(instance)
                     }
                     _ => None
@@ -602,20 +597,20 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                     // If this is a const fn, called from a const context, we
                     // have to visit its body in order to find any fn reifications
                     // it might contain.
-                    collect_neighbours(self.scx,
+                    collect_neighbours(self.tcx,
                                        const_fn_instance,
                                        true,
                                        self.output);
                 } else {
-                    visit_fn_use(self.scx, callee_ty, true, &mut self.output);
+                    visit_fn_use(self.tcx, callee_ty, true, &mut self.output);
                 }
             }
             mir::TerminatorKind::Drop { ref location, .. } |
             mir::TerminatorKind::DropAndReplace { ref location, .. } => {
-                let ty = location.ty(self.mir, self.scx.tcx())
-                    .to_ty(self.scx.tcx());
+                let ty = location.ty(self.mir, self.tcx)
+                    .to_ty(self.tcx);
                 let ty = tcx.trans_apply_param_substs(self.param_substs, &ty);
-                visit_drop_use(self.scx, ty, true, self.output);
+                visit_drop_use(self.tcx, ty, true, self.output);
             }
             mir::TerminatorKind::Goto { .. } |
             mir::TerminatorKind::SwitchInt { .. } |
@@ -636,7 +631,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                     location: Location) {
         debug!("visiting static {:?} @ {:?}", static_.def_id, location);
 
-        let tcx = self.scx.tcx();
+        let tcx = self.tcx;
         let instance = Instance::mono(tcx, static_.def_id);
         if should_trans_locally(tcx, &instance) {
             let node_id = tcx.hir.as_local_node_id(static_.def_id).unwrap();
@@ -647,33 +642,33 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
     }
 }
 
-fn visit_drop_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+fn visit_drop_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             ty: Ty<'tcx>,
                             is_direct_call: bool,
                             output: &mut Vec<TransItem<'tcx>>)
 {
-    let instance = monomorphize::resolve_drop_in_place(scx, ty);
-    visit_instance_use(scx, instance, is_direct_call, output);
+    let instance = monomorphize::resolve_drop_in_place(tcx, ty);
+    visit_instance_use(tcx, instance, is_direct_call, output);
 }
 
-fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+fn visit_fn_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           ty: Ty<'tcx>,
                           is_direct_call: bool,
                           output: &mut Vec<TransItem<'tcx>>)
 {
     if let ty::TyFnDef(def_id, substs) = ty.sty {
-        let instance = monomorphize::resolve(scx, def_id, substs);
-        visit_instance_use(scx, instance, is_direct_call, output);
+        let instance = monomorphize::resolve(tcx, def_id, substs);
+        visit_instance_use(tcx, instance, is_direct_call, output);
     }
 }
 
-fn visit_instance_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+fn visit_instance_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 instance: ty::Instance<'tcx>,
                                 is_direct_call: bool,
                                 output: &mut Vec<TransItem<'tcx>>)
 {
     debug!("visit_item_use({:?}, is_direct_call={:?})", instance, is_direct_call);
-    if !should_trans_locally(scx.tcx(), &instance) {
+    if !should_trans_locally(tcx, &instance) {
         return
     }
 
@@ -775,15 +770,15 @@ fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instan
 ///
 /// Finally, there is also the case of custom unsizing coercions, e.g. for
 /// smart pointers such as `Rc` and `Arc`.
-fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+fn find_vtable_types_for_unsizing<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                             source_ty: Ty<'tcx>,
                                             target_ty: Ty<'tcx>)
                                             -> (Ty<'tcx>, Ty<'tcx>) {
     let ptr_vtable = |inner_source: Ty<'tcx>, inner_target: Ty<'tcx>| {
-        if !scx.type_is_sized(inner_source) {
+        if !type_is_sized(tcx, inner_source) {
             (inner_source, inner_target)
         } else {
-            scx.tcx().struct_lockstep_tails(inner_source, inner_target)
+            tcx.struct_lockstep_tails(inner_source, inner_target)
         }
     };
     match (&source_ty.sty, &target_ty.sty) {
@@ -804,7 +799,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             assert_eq!(source_adt_def, target_adt_def);
 
             let kind =
-                monomorphize::custom_coerce_unsize_info(scx, source_ty, target_ty);
+                monomorphize::custom_coerce_unsize_info(tcx, source_ty, target_ty);
 
             let coerce_index = match kind {
                 CustomCoerceUnsized::Struct(i) => i
@@ -816,10 +811,10 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             assert!(coerce_index < source_fields.len() &&
                     source_fields.len() == target_fields.len());
 
-            find_vtable_types_for_unsizing(scx,
-                                           source_fields[coerce_index].ty(scx.tcx(),
+            find_vtable_types_for_unsizing(tcx,
+                                           source_fields[coerce_index].ty(tcx,
                                                                           source_substs),
-                                           target_fields[coerce_index].ty(scx.tcx(),
+                                           target_fields[coerce_index].ty(tcx,
                                                                           target_substs))
         }
         _ => bug!("find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}",
@@ -835,7 +830,7 @@ fn create_fn_trans_item<'a, 'tcx>(instance: Instance<'tcx>) -> TransItem<'tcx> {
 
 /// Creates a `TransItem` for each method that is referenced by the vtable for
 /// the given trait/impl pair.
-fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+fn create_trans_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                    trait_ty: Ty<'tcx>,
                                                    impl_ty: Ty<'tcx>,
                                                    output: &mut Vec<TransItem<'tcx>>) {
@@ -844,19 +839,19 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
 
     if let ty::TyDynamic(ref trait_ty, ..) = trait_ty.sty {
         if let Some(principal) = trait_ty.principal() {
-            let poly_trait_ref = principal.with_self_ty(scx.tcx(), impl_ty);
+            let poly_trait_ref = principal.with_self_ty(tcx, impl_ty);
             assert!(!poly_trait_ref.has_escaping_regions());
 
             // Walk all methods of the trait, including those of its supertraits
-            let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref);
+            let methods = traits::get_vtable_methods(tcx, poly_trait_ref);
             let methods = methods.filter_map(|method| method)
-                .map(|(def_id, substs)| monomorphize::resolve(scx, def_id, substs))
-                .filter(|&instance| should_trans_locally(scx.tcx(), &instance))
+                .map(|(def_id, substs)| monomorphize::resolve(tcx, def_id, substs))
+                .filter(|&instance| should_trans_locally(tcx, &instance))
                 .map(|instance| create_fn_trans_item(instance));
             output.extend(methods);
         }
         // Also add the destructor
-        visit_drop_use(scx, impl_ty, false, output);
+        visit_drop_use(tcx, impl_ty, false, output);
     }
 }
 
@@ -865,8 +860,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
 //=-----------------------------------------------------------------------------
 
 struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> {
-    scx: &'b SharedCrateContext<'a, 'tcx>,
-    exported_symbols: &'b ExportedSymbols,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     mode: TransItemCollectionMode,
     output: &'b mut Vec<TransItem<'tcx>>,
 }
@@ -886,7 +880,7 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
 
             hir::ItemImpl(..) => {
                 if self.mode == TransItemCollectionMode::Eager {
-                    create_trans_items_for_default_impls(self.scx,
+                    create_trans_items_for_default_impls(self.tcx,
                                                          item,
                                                          self.output);
                 }
@@ -897,25 +891,25 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
             hir::ItemUnion(_, ref generics) => {
                 if !generics.is_parameterized() {
                     if self.mode == TransItemCollectionMode::Eager {
-                        let def_id = self.scx.tcx().hir.local_def_id(item.id);
+                        let def_id = self.tcx.hir.local_def_id(item.id);
                         debug!("RootCollector: ADT drop-glue for {}",
-                               def_id_to_string(self.scx.tcx(), def_id));
+                               def_id_to_string(self.tcx, def_id));
 
-                        let ty = def_ty(self.scx, def_id, Substs::empty());
-                        visit_drop_use(self.scx, ty, true, self.output);
+                        let ty = def_ty(self.tcx, def_id, Substs::empty());
+                        visit_drop_use(self.tcx, ty, true, self.output);
                     }
                 }
             }
             hir::ItemGlobalAsm(..) => {
                 debug!("RootCollector: ItemGlobalAsm({})",
-                       def_id_to_string(self.scx.tcx(),
-                                        self.scx.tcx().hir.local_def_id(item.id)));
+                       def_id_to_string(self.tcx,
+                                        self.tcx.hir.local_def_id(item.id)));
                 self.output.push(TransItem::GlobalAsm(item.id));
             }
             hir::ItemStatic(..) => {
                 debug!("RootCollector: ItemStatic({})",
-                       def_id_to_string(self.scx.tcx(),
-                                        self.scx.tcx().hir.local_def_id(item.id)));
+                       def_id_to_string(self.tcx,
+                                        self.tcx.hir.local_def_id(item.id)));
                 self.output.push(TransItem::Static(item.id));
             }
             hir::ItemConst(..) => {
@@ -923,12 +917,11 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
                 // actually used somewhere. Just declaring them is insufficient.
             }
             hir::ItemFn(..) => {
-                let tcx = self.scx.tcx();
+                let tcx = self.tcx;
                 let def_id = tcx.hir.local_def_id(item.id);
 
                 if (self.mode == TransItemCollectionMode::Eager ||
-                    !tcx.is_const_fn(def_id) ||
-                    self.exported_symbols.local_exports().contains(&item.id)) &&
+                    !tcx.is_const_fn(def_id) || tcx.is_exported_symbol(def_id)) &&
                    !item_has_type_parameters(tcx, def_id) {
 
                     debug!("RootCollector: ItemFn({})",
@@ -949,12 +942,12 @@ impl<'b, 'a, 'v> ItemLikeVisitor<'v> for RootCollector<'b, 'a, 'v> {
     fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
         match ii.node {
             hir::ImplItemKind::Method(hir::MethodSig { .. }, _) => {
-                let tcx = self.scx.tcx();
+                let tcx = self.tcx;
                 let def_id = tcx.hir.local_def_id(ii.id);
 
                 if (self.mode == TransItemCollectionMode::Eager ||
                     !tcx.is_const_fn(def_id) ||
-                    self.exported_symbols.local_exports().contains(&ii.id)) &&
+                    tcx.is_exported_symbol(def_id)) &&
                    !item_has_type_parameters(tcx, def_id) {
                     debug!("RootCollector: MethodImplItem({})",
                            def_id_to_string(tcx, def_id));
@@ -973,10 +966,9 @@ fn item_has_type_parameters<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId
     generics.parent_types as usize + generics.types.len() > 0
 }
 
-fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+fn create_trans_items_for_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                   item: &'tcx hir::Item,
                                                   output: &mut Vec<TransItem<'tcx>>) {
-    let tcx = scx.tcx();
     match item.node {
         hir::ItemImpl(_,
                       _,
@@ -1009,7 +1001,7 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
                     }
 
                     let instance =
-                        monomorphize::resolve(scx, method.def_id, callee_substs);
+                        monomorphize::resolve(tcx, method.def_id, callee_substs);
 
                     let trans_item = create_fn_trans_item(instance);
                     if trans_item.is_instantiable(tcx) && should_trans_locally(tcx, &instance) {
@@ -1025,15 +1017,15 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(scx: &SharedCrateContext<'a, '
 }
 
 /// Scan the MIR in order to find function calls, closures, and drop-glue
-fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+fn collect_neighbours<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                 instance: Instance<'tcx>,
                                 const_context: bool,
                                 output: &mut Vec<TransItem<'tcx>>)
 {
-    let mir = scx.tcx().instance_mir(instance.def);
+    let mir = tcx.instance_mir(instance.def);
 
     let mut visitor = MirNeighborCollector {
-        scx,
+        tcx,
         mir: &mir,
         output,
         param_substs: instance.substs,
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 67c95b92e52..52607904f73 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -26,6 +26,7 @@ use machine;
 use monomorphize;
 use type_::Type;
 use value::Value;
+use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::{Layout, LayoutTyper};
 use rustc::ty::subst::{Kind, Subst, Substs};
@@ -37,7 +38,7 @@ use std::iter;
 use syntax::abi::Abi;
 use syntax::attr;
 use syntax::symbol::InternedString;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
 pub use context::{CrateContext, SharedCrateContext};
 
@@ -140,6 +141,18 @@ pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
     !layout.is_unsized() && layout.size(ccx).bytes() == 0
 }
 
+pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
+    ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All))
+}
+
+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 type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
+    ty.is_freeze(tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
+}
+
 /*
 * A note on nomenclature of linking: "extern", "foreign", and "upcall".
 *
@@ -573,20 +586,20 @@ pub fn is_inline_instance<'a, 'tcx>(
 }
 
 /// Given a DefId and some Substs, produces the monomorphic item type.
-pub fn def_ty<'a, 'tcx>(shared: &SharedCrateContext<'a, 'tcx>,
+pub fn def_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         def_id: DefId,
                         substs: &'tcx Substs<'tcx>)
                         -> Ty<'tcx>
 {
-    let ty = shared.tcx().type_of(def_id);
-    shared.tcx().trans_apply_param_substs(substs, &ty)
+    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>(shared: &SharedCrateContext<'a, 'tcx>,
+pub fn instance_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              instance: &ty::Instance<'tcx>)
                              -> Ty<'tcx>
 {
-    let ty = instance.def.def_ty(shared.tcx());
-    shared.tcx().trans_apply_param_substs(instance.substs, &ty)
+    let ty = instance.def.def_ty(tcx);
+    tcx.trans_apply_param_substs(instance.substs, &ty)
 }
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index bad8a8655d0..78ece020d1d 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;
@@ -109,7 +109,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
         return g;
     }
 
-    let ty = common::instance_ty(ccx.shared(), &instance);
+    let ty = common::instance_ty(ccx.tcx(), &instance);
     let g = if let Some(id) = ccx.tcx().hir.as_local_node_id(def_id) {
 
         let llty = type_of::type_of(ccx, ty);
@@ -130,7 +130,7 @@ pub fn get_static(ccx: &CrateContext, def_id: DefId) -> ValueRef {
 
                 let g = declare::define_global(ccx, &sym[..], llty).unwrap();
 
-                if !ccx.exported_symbols().local_exports().contains(&id) {
+                if !ccx.tcx().is_exported_symbol(def_id) {
                     unsafe {
                         llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden);
                     }
@@ -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
@@ -269,7 +269,7 @@ pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         };
 
         let instance = Instance::mono(ccx.tcx(), def_id);
-        let ty = common::instance_ty(ccx.shared(), &instance);
+        let ty = common::instance_ty(ccx.tcx(), &instance);
         let llty = type_of::type_of(ccx, ty);
         let g = if val_llty == llty {
             g
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 4211be362ef..8b18bf2e1ff 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use common;
 use llvm;
 use llvm::{ContextRef, ModuleRef, ValueRef};
 use rustc::dep_graph::{DepGraph, DepGraphSafe};
@@ -16,20 +17,19 @@ use rustc::hir::def_id::DefId;
 use rustc::traits;
 use debuginfo;
 use callee;
-use back::symbol_export::ExportedSymbols;
 use base;
 use declare;
 use monomorphize::Instance;
 
 use partitioning::CodegenUnit;
-use trans_item::TransItem;
 use type_::Type;
 use rustc_data_structures::base_n;
-use rustc::session::config::{self, NoDebugInfo, OutputFilenames};
+use rustc::middle::trans::Stats;
 use rustc::session::Session;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::session::config::{self, NoDebugInfo};
 use rustc::ty::layout::{LayoutCx, LayoutError, LayoutTyper, TyLayout};
-use rustc::util::nodemap::{FxHashMap, FxHashSet};
+use rustc::ty::{self, Ty, TyCtxt};
+use rustc::util::nodemap::FxHashMap;
 
 use std::ffi::{CStr, CString};
 use std::cell::{Cell, RefCell};
@@ -39,39 +39,8 @@ use std::str;
 use std::sync::Arc;
 use std::marker::PhantomData;
 use syntax::symbol::InternedString;
-use syntax_pos::DUMMY_SP;
 use abi::Abi;
 
-#[derive(Clone, Default)]
-pub struct Stats {
-    pub n_glues_created: Cell<usize>,
-    pub n_null_glues: Cell<usize>,
-    pub n_real_glues: Cell<usize>,
-    pub n_fns: Cell<usize>,
-    pub n_inlines: Cell<usize>,
-    pub n_closures: Cell<usize>,
-    pub n_llvm_insns: Cell<usize>,
-    pub llvm_insns: RefCell<FxHashMap<String, usize>>,
-    // (ident, llvm-instructions)
-    pub fn_stats: RefCell<Vec<(String, usize)> >,
-}
-
-impl Stats {
-    pub fn extend(&mut self, stats: Stats) {
-        self.n_glues_created.set(self.n_glues_created.get() + stats.n_glues_created.get());
-        self.n_null_glues.set(self.n_null_glues.get() + stats.n_null_glues.get());
-        self.n_real_glues.set(self.n_real_glues.get() + stats.n_real_glues.get());
-        self.n_fns.set(self.n_fns.get() + stats.n_fns.get());
-        self.n_inlines.set(self.n_inlines.get() + stats.n_inlines.get());
-        self.n_closures.set(self.n_closures.get() + stats.n_closures.get());
-        self.n_llvm_insns.set(self.n_llvm_insns.get() + stats.n_llvm_insns.get());
-        self.llvm_insns.borrow_mut().extend(
-            stats.llvm_insns.borrow().iter()
-                                     .map(|(key, value)| (key.clone(), value.clone())));
-        self.fn_stats.borrow_mut().append(&mut *stats.fn_stats.borrow_mut());
-    }
-}
-
 /// The shared portion of a `CrateContext`.  There is one `SharedCrateContext`
 /// per crate.  The data here is shared between all compilation units of the
 /// crate, so it must not contain references to any LLVM data structures
@@ -79,10 +48,7 @@ impl Stats {
 pub struct SharedCrateContext<'a, 'tcx: 'a> {
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     check_overflow: bool,
-
     use_dll_storage_attrs: bool,
-
-    output_filenames: &'a OutputFilenames,
 }
 
 /// The local portion of a `CrateContext`.  There is one `LocalCrateContext`
@@ -92,14 +58,8 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
 pub struct LocalCrateContext<'a, 'tcx: 'a> {
     llmod: ModuleRef,
     llcx: ContextRef,
-    stats: Stats,
-    codegen_unit: CodegenUnit<'tcx>,
-
-    /// The translation items of the whole crate.
-    crate_trans_items: Arc<FxHashSet<TransItem<'tcx>>>,
-
-    /// Information about which symbols are exported from the crate.
-    exported_symbols: Arc<ExportedSymbols>,
+    stats: RefCell<Stats>,
+    codegen_unit: Arc<CodegenUnit<'tcx>>,
 
     /// Cache instances of monomorphic and polymorphic items
     instances: RefCell<FxHashMap<Instance<'tcx>, ValueRef>>,
@@ -261,10 +221,7 @@ pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (Cont
 }
 
 impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
-    pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>,
-               check_overflow: bool,
-               output_filenames: &'b OutputFilenames)
-               -> SharedCrateContext<'b, 'tcx> {
+    pub fn new(tcx: TyCtxt<'b, 'tcx, 'tcx>) -> SharedCrateContext<'b, 'tcx> {
         // An interesting part of Windows which MSVC forces our hand on (and
         // apparently MinGW didn't) is the usage of `dllimport` and `dllexport`
         // attributes in LLVM IR as well as native dependencies (in C these
@@ -310,27 +267,28 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
         // start) and then strongly recommending static linkage on MSVC!
         let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc;
 
+        let check_overflow = tcx.sess.overflow_checks();
+
         SharedCrateContext {
             tcx,
             check_overflow,
             use_dll_storage_attrs,
-            output_filenames,
         }
     }
 
     pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
-        ty.needs_drop(self.tcx, ty::ParamEnv::empty(traits::Reveal::All))
+        common::type_needs_drop(self.tcx, ty)
     }
 
     pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_sized(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
+        common::type_is_sized(self.tcx, ty)
     }
 
     pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
-        ty.is_freeze(self.tcx, ty::ParamEnv::empty(traits::Reveal::All), DUMMY_SP)
+        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
     }
 
@@ -345,17 +303,11 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
     pub fn use_dll_storage_attrs(&self) -> bool {
         self.use_dll_storage_attrs
     }
-
-    pub fn output_filenames(&self) -> &OutputFilenames {
-        self.output_filenames
-    }
 }
 
 impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
     pub fn new(shared: &SharedCrateContext<'a, 'tcx>,
-               codegen_unit: CodegenUnit<'tcx>,
-               crate_trans_items: Arc<FxHashSet<TransItem<'tcx>>>,
-               exported_symbols: Arc<ExportedSymbols>,)
+               codegen_unit: Arc<CodegenUnit<'tcx>>)
                -> LocalCrateContext<'a, 'tcx> {
         unsafe {
             // Append ".rs" to LLVM module identifier.
@@ -385,10 +337,8 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
             let local_ccx = LocalCrateContext {
                 llmod,
                 llcx,
-                stats: Stats::default(),
+                stats: RefCell::new(Stats::default()),
                 codegen_unit,
-                crate_trans_items,
-                exported_symbols,
                 instances: RefCell::new(FxHashMap()),
                 vtables: RefCell::new(FxHashMap()),
                 const_cstr_cache: RefCell::new(FxHashMap()),
@@ -452,7 +402,7 @@ impl<'a, 'tcx> LocalCrateContext<'a, 'tcx> {
     }
 
     pub fn into_stats(self) -> Stats {
-        self.stats
+        self.stats.into_inner()
     }
 }
 
@@ -465,7 +415,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
     }
 
@@ -495,14 +445,6 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.local().codegen_unit
     }
 
-    pub fn crate_trans_items(&self) -> &FxHashSet<TransItem<'tcx>> {
-        &self.local().crate_trans_items
-    }
-
-    pub fn exported_symbols(&self) -> &ExportedSymbols {
-        &self.local().exported_symbols
-    }
-
     pub fn td(&self) -> llvm::TargetDataRef {
         unsafe { llvm::LLVMRustGetModuleDataLayout(self.llmod()) }
     }
@@ -545,7 +487,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
         &self.local().lltypes
     }
 
-    pub fn stats<'a>(&'a self) -> &'a Stats {
+    pub fn stats<'a>(&'a self) -> &'a RefCell<Stats> {
         &self.local().stats
     }
 
diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_trans/debuginfo/metadata.rs
index 3c87bc293b5..8a89bfee4ac 100644
--- a/src/librustc_trans/debuginfo/metadata.rs
+++ b/src/librustc_trans/debuginfo/metadata.rs
@@ -822,9 +822,9 @@ pub fn compile_unit_metadata(scc: &SharedCrateContext,
 
             let gcov_cu_info = [
                 path_to_mdstring(debug_context.llcontext,
-                                 &scc.output_filenames().with_extension("gcno")),
+                                 &scc.tcx().output_filenames(LOCAL_CRATE).with_extension("gcno")),
                 path_to_mdstring(debug_context.llcontext,
-                                 &scc.output_filenames().with_extension("gcda")),
+                                 &scc.tcx().output_filenames(LOCAL_CRATE).with_extension("gcda")),
                 cu_desc_metadata,
             ];
             let gcov_metadata = llvm::LLVMMDNodeInContext(debug_context.llcontext,
@@ -1803,7 +1803,7 @@ pub fn create_global_var_metadata(cx: &CrateContext,
     };
 
     let is_local_to_unit = is_node_local_to_unit(cx, node_id);
-    let variable_type = common::def_ty(cx.shared(), node_def_id, Substs::empty());
+    let variable_type = common::def_ty(cx.tcx(), node_def_id, Substs::empty());
     let type_metadata = type_metadata(cx, variable_type, span);
     let var_name = tcx.item_name(node_def_id).to_string();
     let linkage_name = mangled_name_of_item(cx, node_def_id, "");
diff --git a/src/librustc_trans/debuginfo/mod.rs b/src/librustc_trans/debuginfo/mod.rs
index 83366c13453..7e2ac95cd84 100644
--- a/src/librustc_trans/debuginfo/mod.rs
+++ b/src/librustc_trans/debuginfo/mod.rs
@@ -428,7 +428,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             // If the method does *not* belong to a trait, proceed
             if cx.tcx().trait_id_of_impl(impl_def_id).is_none() {
                 let impl_self_ty =
-                    common::def_ty(cx.shared(), impl_def_id, instance.substs);
+                    common::def_ty(cx.tcx(), impl_def_id, instance.substs);
 
                 // Only "class" methods are generally understood by LLVM,
                 // so avoid methods on other types (e.g. `<*mut T>::null`).
diff --git a/src/librustc_trans/debuginfo/utils.rs b/src/librustc_trans/debuginfo/utils.rs
index 7529139c05a..ad4fdfca726 100644
--- a/src/librustc_trans/debuginfo/utils.rs
+++ b/src/librustc_trans/debuginfo/utils.rs
@@ -37,7 +37,8 @@ pub fn is_node_local_to_unit(cx: &CrateContext, node_id: ast::NodeId) -> bool
     // visible). It might better to use the `exported_items` set from
     // `driver::CrateAnalysis` in the future, but (atm) this set is not
     // available in the translation pass.
-    !cx.exported_symbols().local_exports().contains(&node_id)
+    let def_id = cx.tcx().hir.local_def_id(node_id);
+    !cx.tcx().is_exported_symbol(def_id)
 }
 
 #[allow(non_snake_case)]
diff --git a/src/librustc_trans/diagnostics.rs b/src/librustc_trans/diagnostics.rs
index df71fd4b19b..84858676891 100644
--- a/src/librustc_trans/diagnostics.rs
+++ b/src/librustc_trans/diagnostics.rs
@@ -46,4 +46,28 @@ extern "platform-intrinsic" {
 unsafe { simd_add(i32x1(0), i32x1(1)); } // ok!
 ```
 "##,
+
+E0558: r##"
+The `export_name` attribute was malformed.
+
+Erroneous code example:
+
+```ignore (error-emitted-at-codegen-which-cannot-be-handled-by-compile_fail)
+#[export_name] // error: export_name attribute has invalid format
+pub fn something() {}
+
+fn main() {}
+```
+
+The `export_name` attribute expects a string in order to determine the name of
+the exported symbol. Example:
+
+```
+#[export_name = "some_function"] // ok!
+pub fn something() {}
+
+fn main() {}
+```
+"##,
+
 }
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 39394979713..453b98a1d74 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -14,15 +14,15 @@
 
 use std;
 
-use llvm;
-use llvm::{ValueRef};
-use rustc::ty::{self, Ty};
-use rustc::ty::layout::LayoutTyper;
+use builder::Builder;
 use common::*;
+use llvm::{ValueRef};
+use llvm;
 use meth;
 use monomorphize;
+use rustc::ty::layout::LayoutTyper;
+use rustc::ty::{self, Ty};
 use value::Value;
-use builder::Builder;
 
 pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &Builder<'a, 'tcx>, t: Ty<'tcx>, info: ValueRef)
                                        -> (ValueRef, ValueRef) {
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 256200a6e95..4cbc98d26de 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -64,7 +64,6 @@ extern crate serialize;
 extern crate gcc; // Used to locate MSVC, not gcc :)
 
 pub use base::trans_crate;
-pub use back::symbol_names::provide;
 
 pub use metadata::LlvmMetadataLoader;
 pub use llvm_util::{init, target_features, print_version, print_passes, print, enable_llvm_debug};
@@ -72,8 +71,11 @@ pub use llvm_util::{init, target_features, print_version, print_passes, print, e
 use std::rc::Rc;
 
 use rustc::hir::def_id::CrateNum;
-use rustc::util::nodemap::{FxHashSet, FxHashMap};
 use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource};
+use rustc::ty::maps::Providers;
+use rustc::util::nodemap::{FxHashSet, FxHashMap};
+
+mod diagnostics;
 
 pub mod back {
     mod archive;
@@ -87,8 +89,6 @@ pub mod back {
     mod rpath;
 }
 
-mod diagnostics;
-
 mod abi;
 mod adt;
 mod allocator;
@@ -247,3 +247,15 @@ pub struct CrateInfo {
 }
 
 __build_diagnostic_array! { librustc_trans, DIAGNOSTICS }
+
+pub fn provide_local(providers: &mut Providers) {
+    back::symbol_names::provide(providers);
+    back::symbol_export::provide_local(providers);
+    base::provide_local(providers);
+}
+
+pub fn provide_extern(providers: &mut Providers) {
+    back::symbol_names::provide(providers);
+    back::symbol_export::provide_extern(providers);
+    base::provide_extern(providers);
+}
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index 9abfbb3279c..88407947f0e 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -80,7 +80,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     let nullptr = C_null(Type::nil(ccx).ptr_to());
 
     let mut components: Vec<_> = [
-        callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.shared(), ty)),
+        callee::get_fn(ccx, monomorphize::resolve_drop_in_place(ccx.tcx(), ty)),
         C_usize(ccx, ccx.size_of(ty)),
         C_usize(ccx, ccx.align_of(ty) as u64)
     ].iter().cloned().collect();
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index 1105da43618..9246822b339 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -265,7 +265,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
             mir::TerminatorKind::Drop { ref location, target, unwind } => {
                 let ty = location.ty(self.mir, bcx.tcx()).to_ty(bcx.tcx());
                 let ty = self.monomorphize(&ty);
-                let drop_fn = monomorphize::resolve_drop_in_place(bcx.ccx.shared(), ty);
+                let drop_fn = monomorphize::resolve_drop_in_place(bcx.ccx.tcx(), ty);
 
                 if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def {
                     // we don't actually need to drop anything.
@@ -429,7 +429,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
 
                 let (instance, mut llfn) = match callee.ty.sty {
                     ty::TyFnDef(def_id, substs) => {
-                        (Some(monomorphize::resolve(bcx.ccx.shared(), def_id, substs)),
+                        (Some(monomorphize::resolve(bcx.ccx.tcx(), def_id, substs)),
                          None)
                     }
                     ty::TyFnPtr(_) => {
@@ -546,7 +546,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                     };
 
                     let callee_ty = common::instance_ty(
-                        bcx.ccx.shared(), instance.as_ref().unwrap());
+                        bcx.ccx.tcx(), instance.as_ref().unwrap());
                     trans_intrinsic_call(&bcx, callee_ty, &fn_ty, &llargs, dest,
                                          terminator.source_info.span);
 
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 4c3326a466d..9232d73f832 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -261,7 +261,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                  substs: &'tcx Substs<'tcx>,
                  args: IndexVec<mir::Local, Result<Const<'tcx>, ConstEvalErr<'tcx>>>)
                  -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
-        let instance = monomorphize::resolve(ccx.shared(), def_id, substs);
+        let instance = monomorphize::resolve(ccx.tcx(), def_id, substs);
         let mir = ccx.tcx().instance_mir(instance.def);
         MirConstContext::new(ccx, &mir, instance.substs, args).trans()
     }
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index 20ed4ab50a0..822431eba42 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -222,7 +222,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                         match operand.ty.sty {
                             ty::TyClosure(def_id, substs) => {
                                 let instance = monomorphize::resolve_closure(
-                                    bcx.ccx.shared(), def_id, substs, ty::ClosureKind::FnOnce);
+                                    bcx.ccx.tcx(), def_id, substs, ty::ClosureKind::FnOnce);
                                 OperandValue::Immediate(callee::get_fn(bcx.ccx, instance))
                             }
                             _ => {
diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs
index 309177d9ff6..2be7a81b1cd 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans/monomorphize.rs
@@ -85,27 +85,26 @@ fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind,
 }
 
 pub fn resolve_closure<'a, 'tcx> (
-    scx: &SharedCrateContext<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId,
     substs: ty::ClosureSubsts<'tcx>,
     requested_kind: ty::ClosureKind)
     -> Instance<'tcx>
 {
-    let actual_kind = scx.tcx().closure_kind(def_id);
+    let actual_kind = tcx.closure_kind(def_id);
 
     match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
-        Ok(true) => fn_once_adapter_instance(scx.tcx(), def_id, substs),
+        Ok(true) => fn_once_adapter_instance(tcx, def_id, substs),
         _ => Instance::new(def_id, substs.substs)
     }
 }
 
 fn resolve_associated_item<'a, 'tcx>(
-    scx: &SharedCrateContext<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     trait_item: &ty::AssociatedItem,
     trait_id: DefId,
     rcvr_substs: &'tcx Substs<'tcx>
 ) -> Instance<'tcx> {
-    let tcx = scx.tcx();
     let def_id = trait_item.def_id;
     debug!("resolve_associated_item(trait_item={:?}, \
                                     trait_id={:?}, \
@@ -132,7 +131,7 @@ fn resolve_associated_item<'a, 'tcx>(
         }
         traits::VtableClosure(closure_data) => {
             let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap();
-            resolve_closure(scx, closure_data.closure_def_id, closure_data.substs,
+            resolve_closure(tcx, closure_data.closure_def_id, closure_data.substs,
                             trait_closure_kind)
         }
         traits::VtableFnPointer(ref data) => {
@@ -163,21 +162,21 @@ fn resolve_associated_item<'a, 'tcx>(
 /// The point where linking happens. Resolve a (def_id, substs)
 /// pair to an instance.
 pub fn resolve<'a, 'tcx>(
-    scx: &SharedCrateContext<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     def_id: DefId,
     substs: &'tcx Substs<'tcx>
 ) -> Instance<'tcx> {
     debug!("resolve(def_id={:?}, substs={:?})",
            def_id, substs);
-    let result = if let Some(trait_def_id) = scx.tcx().trait_of_item(def_id) {
+    let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) {
         debug!(" => associated item, attempting to find impl");
-        let item = scx.tcx().associated_item(def_id);
-        resolve_associated_item(scx, &item, trait_def_id, substs)
+        let item = tcx.associated_item(def_id);
+        resolve_associated_item(tcx, &item, trait_def_id, substs)
     } else {
-        let item_type = def_ty(scx, def_id, substs);
+        let item_type = def_ty(tcx, def_id, substs);
         let def = match item_type.sty {
             ty::TyFnDef(..) if {
-                    let f = item_type.fn_sig(scx.tcx());
+                    let f = item_type.fn_sig(tcx);
                     f.abi() == Abi::RustIntrinsic ||
                     f.abi() == Abi::PlatformIntrinsic
                 } =>
@@ -186,9 +185,9 @@ pub fn resolve<'a, 'tcx>(
                 ty::InstanceDef::Intrinsic(def_id)
             }
             _ => {
-                if Some(def_id) == scx.tcx().lang_items().drop_in_place_fn() {
+                if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
                     let ty = substs.type_at(0);
-                    if scx.type_needs_drop(ty) {
+                    if type_needs_drop(tcx, ty) {
                         debug!(" => nontrivial drop glue");
                         ty::InstanceDef::DropGlue(def_id, Some(ty))
                     } else {
@@ -209,27 +208,27 @@ pub fn resolve<'a, 'tcx>(
 }
 
 pub fn resolve_drop_in_place<'a, 'tcx>(
-    scx: &SharedCrateContext<'a, 'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
     ty: Ty<'tcx>)
     -> ty::Instance<'tcx>
 {
-    let def_id = scx.tcx().require_lang_item(DropInPlaceFnLangItem);
-    let substs = scx.tcx().intern_substs(&[Kind::from(ty)]);
-    resolve(scx, def_id, substs)
+    let def_id = tcx.require_lang_item(DropInPlaceFnLangItem);
+    let substs = tcx.intern_substs(&[Kind::from(ty)]);
+    resolve(tcx, def_id, substs)
 }
 
-pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx>,
-                                             source_ty: Ty<'tcx>,
-                                             target_ty: Ty<'tcx>)
-                                             -> CustomCoerceUnsized {
+pub fn custom_coerce_unsize_info<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                                           source_ty: Ty<'tcx>,
+                                           target_ty: Ty<'tcx>)
+                                           -> CustomCoerceUnsized {
     let trait_ref = ty::Binder(ty::TraitRef {
-        def_id: scx.tcx().lang_items().coerce_unsized_trait().unwrap(),
-        substs: scx.tcx().mk_substs_trait(source_ty, &[target_ty])
+        def_id: tcx.lang_items().coerce_unsized_trait().unwrap(),
+        substs: tcx.mk_substs_trait(source_ty, &[target_ty])
     });
 
-    match scx.tcx().trans_fulfill_obligation(DUMMY_SP, trait_ref) {
+    match tcx.trans_fulfill_obligation(DUMMY_SP, trait_ref) {
         traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
-            scx.tcx().coerce_unsized_info(impl_def_id).custom_kind.unwrap()
+            tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap()
         }
         vtable => {
             bug!("invalid CoerceUnsized vtable: {:?}", vtable);
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index 26256fa78dd..9b617c35d93 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -102,14 +102,12 @@
 //! source-level module, functions from the same module will be available for
 //! inlining, even when they are not marked #[inline].
 
-use back::symbol_export::ExportedSymbols;
 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::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 +117,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,57 +129,36 @@ 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)>,
-}
+pub trait CodegenUnitExt<'tcx> {
+    fn as_codegen_unit(&self) -> &CodegenUnit<'tcx>;
 
-impl<'tcx> CodegenUnit<'tcx> {
-    pub fn new(name: InternedString,
-               items: FxHashMap<TransItem<'tcx>, (llvm::Linkage, llvm::Visibility)>)
-               -> Self {
-        CodegenUnit {
-            name,
-            items,
-        }
+    fn contains_item(&self, item: &TransItem<'tcx>) -> bool {
+        self.items().contains_key(item)
     }
 
-    pub fn empty(name: InternedString) -> Self {
-        Self::new(name, FxHashMap())
+    fn name<'a>(&'a self) -> &'a InternedString
+        where 'tcx: 'a,
+    {
+        &self.as_codegen_unit().name()
     }
 
-    pub fn contains_item(&self, item: &TransItem<'tcx>) -> bool {
-        self.items.contains_key(item)
+    fn items(&self) -> &FxHashMap<TransItem<'tcx>, (Linkage, Visibility)> {
+        &self.as_codegen_unit().items()
     }
 
-    pub fn name(&self) -> &str {
-        &self.name
-    }
-
-    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, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> u64 {
         let mut state = IchHasher::new();
-        let all_items = self.items_in_deterministic_order(scx.tcx());
+        let all_items = self.items_in_deterministic_order(tcx);
         for (item, (linkage, visibility)) in all_items {
-            let symbol_name = item.symbol_name(scx.tcx());
+            let symbol_name = item.symbol_name(tcx);
             symbol_name.len().hash(&mut state);
             symbol_name.hash(&mut state);
             linkage.hash(&mut state);
@@ -188,10 +167,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 +188,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,25 +196,26 @@ 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";
 
-pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
+pub fn partition<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                               trans_items: I,
                               strategy: PartitioningStrategy,
-                              inlining_map: &InliningMap<'tcx>,
-                              exported_symbols: &ExportedSymbols)
+                              inlining_map: &InliningMap<'tcx>)
                               -> Vec<CodegenUnit<'tcx>>
     where I: Iterator<Item = TransItem<'tcx>>
 {
-    let tcx = scx.tcx();
-
     // In the first step, we place all regular translation items into their
     // respective 'home' codegen unit. Regular translation items are all
     // functions and statics defined in the local crate.
-    let mut initial_partitioning = place_root_translation_items(scx,
-                                                                exported_symbols,
+    let mut initial_partitioning = place_root_translation_items(tcx,
                                                                 trans_items);
 
     debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter());
@@ -269,13 +249,13 @@ pub fn partition<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
     } = post_inlining;
 
     result.sort_by(|cgu1, cgu2| {
-        (&cgu1.name[..]).cmp(&cgu2.name[..])
+        cgu1.name().cmp(cgu2.name())
     });
 
-    if scx.sess().opts.enable_dep_node_debug_strs() {
+    if tcx.sess.opts.enable_dep_node_debug_strs() {
         for cgu in &result {
             let dep_node = cgu.work_product_dep_node();
-            scx.tcx().dep_graph.register_dep_node_debug_str(dep_node,
+            tcx.dep_graph.register_dep_node_debug_str(dep_node,
                                                             || cgu.name().to_string());
         }
     }
@@ -304,15 +284,11 @@ struct PostInliningPartitioning<'tcx> {
     internalization_candidates: FxHashSet<TransItem<'tcx>>,
 }
 
-fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
-                                             exported_symbols: &ExportedSymbols,
+fn place_root_translation_items<'a, 'tcx, I>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                              trans_items: I)
                                              -> PreInliningPartitioning<'tcx>
     where I: Iterator<Item = TransItem<'tcx>>
 {
-    let tcx = scx.tcx();
-    let exported_symbols = exported_symbols.local_exports();
-
     let mut roots = FxHashSet();
     let mut codegen_units = FxHashMap();
     let is_incremental_build = tcx.sess.opts.incremental.is_some();
@@ -322,7 +298,7 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, 'tcx>,
         let is_root = trans_item.instantiation_mode(tcx) == InstantiationMode::GloballyShared;
 
         if is_root {
-            let characteristic_def_id = characteristic_def_id_of_trans_item(scx, trans_item);
+            let characteristic_def_id = characteristic_def_id_of_trans_item(tcx, trans_item);
             let is_volatile = is_incremental_build &&
                               trans_item.is_generic_fn();
 
@@ -332,29 +308,29 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, '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) => {
                             let visibility = match instance.def {
                                 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
+                                    if def_id.is_local() {
+                                        if tcx.is_exported_symbol(def_id) {
+                                            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(..) |
@@ -368,23 +344,24 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, '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
+                            let def_id = tcx.hir.local_def_id(node_id);
+                            let visibility = if tcx.is_exported_symbol(def_id) {
+                                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);
         }
     }
@@ -394,7 +371,7 @@ fn place_root_translation_items<'a, 'tcx, I>(scx: &SharedCrateContext<'a, '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 {
@@ -417,17 +394,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
@@ -435,8 +412,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));
     }
 }
 
@@ -457,20 +434,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: \
@@ -478,8 +452,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 {
@@ -490,7 +466,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,
                         });
@@ -498,7 +474,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()
                         });
                     }
                 }
@@ -536,8 +512,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));
             }
         }
 
@@ -561,10 +537,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
@@ -587,15 +563,14 @@ 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);
         }
     }
 }
 
-fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+fn characteristic_def_id_of_trans_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                                  trans_item: TransItem<'tcx>)
                                                  -> Option<DefId> {
-    let tcx = scx.tcx();
     match trans_item {
         TransItem::Fn(instance) => {
             let def_id = match instance.def {
@@ -621,7 +596,7 @@ fn characteristic_def_id_of_trans_item<'a, 'tcx>(scx: &SharedCrateContext<'a, 't
             if let Some(impl_def_id) = tcx.impl_of_method(def_id) {
                 // This is a method within an inherent impl, find out what the
                 // self-type is:
-                let impl_self_ty = common::def_ty(scx, impl_def_id, instance.substs);
+                let impl_self_ty = common::def_ty(tcx, impl_def_id, instance.substs);
                 if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
                     return Some(def_id);
                 }
@@ -679,9 +654,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 1f27eb9fcb3..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.shared(), &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.shared(), &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
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index fd0167be2b9..0c0748cf673 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -176,6 +176,11 @@ pub fn run_core(search_paths: SearchPaths,
     let arena = DroplessArena::new();
     let arenas = GlobalArenas::new();
     let hir_map = hir_map::map_crate(&mut hir_forest, defs);
+    let output_filenames = driver::build_output_filenames(&input,
+                                                          &None,
+                                                          &None,
+                                                          &[],
+                                                          &sess);
 
     abort_on_err(driver::phase_3_run_analysis_passes(&sess,
                                                      &*cstore,
@@ -185,7 +190,8 @@ pub fn run_core(search_paths: SearchPaths,
                                                      &arena,
                                                      &arenas,
                                                      &name,
-                                                     |tcx, analysis, _, result| {
+                                                     &output_filenames,
+                                                     |tcx, analysis, _, _, result| {
         if let Err(_) = result {
             sess.fatal("Compilation failed, aborting rustdoc");
         }
diff --git a/src/libsyntax/attr.rs b/src/libsyntax/attr.rs
index 03907eed900..36ab3737f38 100644
--- a/src/libsyntax/attr.rs
+++ b/src/libsyntax/attr.rs
@@ -506,30 +506,6 @@ pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
     first_attr_value_str_by_name(attrs, "crate_name")
 }
 
-/// Find the value of #[export_name=*] attribute and check its validity.
-pub fn find_export_name_attr(diag: &Handler, attrs: &[Attribute]) -> Option<Symbol> {
-    attrs.iter().fold(None, |ia,attr| {
-        if attr.check_name("export_name") {
-            if let s@Some(_) = attr.value_str() {
-                s
-            } else {
-                struct_span_err!(diag, attr.span, E0558,
-                                 "export_name attribute has invalid format")
-                    .span_label(attr.span, "did you mean #[export_name=\"*\"]?")
-                    .emit();
-                None
-            }
-        } else {
-            ia
-        }
-    })
-}
-
-pub fn contains_extern_indicator(diag: &Handler, attrs: &[Attribute]) -> bool {
-    contains_name(attrs, "no_mangle") ||
-        find_export_name_attr(diag, attrs).is_some()
-}
-
 #[derive(Copy, Clone, PartialEq)]
 pub enum InlineAttr {
     None,
diff --git a/src/libsyntax/diagnostic_list.rs b/src/libsyntax/diagnostic_list.rs
index 46dec73c962..b29883670bd 100644
--- a/src/libsyntax/diagnostic_list.rs
+++ b/src/libsyntax/diagnostic_list.rs
@@ -219,29 +219,6 @@ Erroneous code example:
 Delete the offending feature attribute.
 "##,
 
-E0558: r##"
-The `export_name` attribute was malformed.
-
-Erroneous code example:
-
-```compile_fail,E0558
-#[export_name] // error: export_name attribute has invalid format
-pub fn something() {}
-
-fn main() {}
-```
-
-The `export_name` attribute expects a string in order to determine the name of
-the exported symbol. Example:
-
-```
-#[export_name = "some_function"] // ok!
-pub fn something() {}
-
-fn main() {}
-```
-"##,
-
 E0565: r##"
 A literal was used in an attribute that doesn't support literals.