about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-05-09 23:50:10 -0700
committerbors <bors@rust-lang.org>2016-05-09 23:50:10 -0700
commit1939b76903eb8a4aa02dadc52353541637e3b98c (patch)
tree6615e19eead271fd8ac35916327ba49dc62578ef
parenta4d2424cc304e97f553c6d8eef17a24dc2f12c01 (diff)
parent118cc9e8e1fd72ea59c44c99a3ef3cc8abf9bbaf (diff)
downloadrust-1939b76903eb8a4aa02dadc52353541637e3b98c.tar.gz
rust-1939b76903eb8a4aa02dadc52353541637e3b98c.zip
Auto merge of #33473 - michaelwoerister:split-cratecontext, r=nikomatsakis
Preparatory refactorings for collector-driven trans.

This is a set of refactorings that allows to do translation item collection and partitioning before LocalCrateContext instances or LLVM modules are generated. As a consequence we can now create LocalCrateContexts already with knowledge of the codegen unit it will be used for. This is a preparation step for driving trans by the results of codegen unit partitioning.
-rw-r--r--src/librustc_trans/back/write.rs3
-rw-r--r--src/librustc_trans/base.rs91
-rw-r--r--src/librustc_trans/callee.rs2
-rw-r--r--src/librustc_trans/collector.rs400
-rw-r--r--src/librustc_trans/common.rs127
-rw-r--r--src/librustc_trans/consts.rs2
-rw-r--r--src/librustc_trans/context.rs336
-rw-r--r--src/librustc_trans/expr.rs4
-rw-r--r--src/librustc_trans/glue.rs30
-rw-r--r--src/librustc_trans/meth.rs16
-rw-r--r--src/librustc_trans/mir/block.rs2
-rw-r--r--src/librustc_trans/mir/constant.rs2
-rw-r--r--src/librustc_trans/partitioning.rs21
13 files changed, 541 insertions, 495 deletions
diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs
index 9f7a794185a..cf81777be26 100644
--- a/src/librustc_trans/back/write.rs
+++ b/src/librustc_trans/back/write.rs
@@ -639,7 +639,8 @@ pub fn run_passes(sess: &Session,
     }
 
     // Sanity check
-    assert!(trans.modules.len() == sess.opts.cg.codegen_units);
+    assert!(trans.modules.len() == sess.opts.cg.codegen_units ||
+            sess.opts.debugging_opts.incremental.is_some());
 
     let tm = create_target_machine(sess);
 
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index cbb4be5b300..191b14f8a41 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -68,7 +68,7 @@ use common::{node_id_type, fulfill_obligation};
 use common::{type_is_immediate, type_is_zero_size, val_ty};
 use common;
 use consts;
-use context::SharedCrateContext;
+use context::{SharedCrateContext, CrateContextList};
 use controlflow;
 use datum;
 use debuginfo::{self, DebugLoc, ToDebugLoc};
@@ -81,7 +81,7 @@ use machine::{llalign_of_min, llsize_of, llsize_of_real};
 use meth;
 use mir;
 use monomorphize::{self, Instance};
-use partitioning::{self, PartitioningStrategy, InstantiationMode};
+use partitioning::{self, PartitioningStrategy, InstantiationMode, CodegenUnit};
 use symbol_names_test;
 use tvec;
 use type_::Type;
@@ -664,7 +664,7 @@ pub fn coerce_unsized_into<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     }
 }
 
-pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
+pub fn custom_coerce_unsize_info<'scx, 'tcx>(scx: &SharedCrateContext<'scx, 'tcx>,
                                              source_ty: Ty<'tcx>,
                                              target_ty: Ty<'tcx>)
                                              -> CustomCoerceUnsized {
@@ -674,13 +674,13 @@ pub fn custom_coerce_unsize_info<'ccx, 'tcx>(ccx: &CrateContext<'ccx, 'tcx>,
                                    subst::VecPerParamSpace::empty());
 
     let trait_ref = ty::Binder(ty::TraitRef {
-        def_id: ccx.tcx().lang_items.coerce_unsized_trait().unwrap(),
-        substs: ccx.tcx().mk_substs(trait_substs)
+        def_id: scx.tcx().lang_items.coerce_unsized_trait().unwrap(),
+        substs: scx.tcx().mk_substs(trait_substs)
     });
 
-    match fulfill_obligation(ccx, DUMMY_SP, trait_ref) {
+    match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
         traits::VtableImpl(traits::VtableImplData { impl_def_id, .. }) => {
-            ccx.tcx().custom_coerce_unsized_kind(impl_def_id)
+            scx.tcx().custom_coerce_unsized_kind(impl_def_id)
         }
         vtable => {
             bug!("invalid CoerceUnsized vtable: {:?}", vtable);
@@ -1824,7 +1824,7 @@ pub fn trans_closure<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                closure_env: closure::ClosureEnv) {
     ccx.stats().n_closures.set(ccx.stats().n_closures.get() + 1);
 
-    if collector::collecting_debug_information(ccx) {
+    if collector::collecting_debug_information(ccx.shared()) {
         ccx.record_translation_item_as_generated(TransItem::Fn(instance));
     }
 
@@ -2188,7 +2188,8 @@ pub fn update_linkage(ccx: &CrateContext,
             // `llval` is a translation of an item defined in a separate
             // compilation unit.  This only makes sense if there are at least
             // two compilation units.
-            assert!(ccx.sess().opts.cg.codegen_units > 1);
+            assert!(ccx.sess().opts.cg.codegen_units > 1 ||
+                    ccx.sess().opts.debugging_opts.incremental.is_some());
             // `llval` is a copy of something defined elsewhere, so use
             // `AvailableExternallyLinkage` to avoid duplicating code in the
             // output.
@@ -2524,7 +2525,7 @@ pub fn write_metadata<'a, 'tcx>(cx: &SharedCrateContext<'a, 'tcx>,
 
 /// Find any symbols that are defined in one compilation unit, but not declared
 /// in any other compilation unit.  Give these symbols internal linkage.
-fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) {
+fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) {
     unsafe {
         let mut declared = HashSet::new();
 
@@ -2579,12 +2580,12 @@ fn internalize_symbols(cx: &SharedCrateContext, reachable: &HashSet<&str>) {
 // when using MSVC linker.  We do this only for data, as linker can fix up
 // code references on its own.
 // See #26591, #27438
-fn create_imps(cx: &SharedCrateContext) {
+fn create_imps(cx: &CrateContextList) {
     // The x86 ABI seems to require that leading underscores are added to symbol
     // names, so we need an extra underscore on 32-bit. There's also a leading
     // '\x01' here which disables LLVM's symbol mangling (e.g. no extra
     // underscores added in front).
-    let prefix = if cx.sess().target.target.target_pointer_width == "32" {
+    let prefix = if cx.shared().sess().target.target.target_pointer_width == "32" {
         "\x01__imp__"
     } else {
         "\x01__imp_"
@@ -2661,10 +2662,10 @@ fn iter_functions(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 filter_reachable_ids(ccx: &SharedCrateContext) -> NodeSet {
-    ccx.reachable().iter().map(|x| *x).filter(|id| {
+pub fn filter_reachable_ids(scx: &SharedCrateContext) -> NodeSet {
+    scx.reachable().iter().map(|x| *x).filter(|id| {
         // First, only worry about nodes which have a symbol name
-        ccx.item_symbols().borrow().contains_key(id)
+        scx.item_symbols().borrow().contains_key(id)
     }).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
@@ -2679,9 +2680,9 @@ pub fn filter_reachable_ids(ccx: &SharedCrateContext) -> NodeSet {
         //
         // As a result, if this id is an FFI item (foreign item) then we only
         // let it through if it's included statically.
-        match ccx.tcx().map.get(id) {
+        match scx.tcx().map.get(id) {
             hir_map::NodeForeignItem(..) => {
-                ccx.sess().cstore.is_statically_included_foreign_item(id)
+                scx.sess().cstore.is_statically_included_foreign_item(id)
             }
             _ => true,
         }
@@ -2716,10 +2717,7 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>,
 
     let link_meta = link::build_link_meta(&tcx, name);
 
-    let codegen_units = tcx.sess.opts.cg.codegen_units;
-    let shared_ccx = SharedCrateContext::new(&link_meta.crate_name,
-                                             codegen_units,
-                                             tcx,
+    let shared_ccx = SharedCrateContext::new(tcx,
                                              &mir_map,
                                              export_map,
                                              Sha256::new(),
@@ -2728,9 +2726,15 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>,
                                              check_overflow,
                                              check_dropflag);
 
+    let codegen_units = collect_and_partition_translation_items(&shared_ccx);
+    let codegen_unit_count = codegen_units.len();
+    assert!(tcx.sess.opts.cg.codegen_units == codegen_unit_count ||
+            tcx.sess.opts.debugging_opts.incremental.is_some());
+
+    let crate_context_list = CrateContextList::new(&shared_ccx, codegen_units);
+
     {
-        let ccx = shared_ccx.get_ccx(0);
-        collect_translation_items(&ccx);
+        let ccx = crate_context_list.get_ccx(0);
 
         // Translate all items. See `TransModVisitor` for
         // details on why we walk in this particular way.
@@ -2740,12 +2744,12 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>,
             krate.visit_all_items(&mut TransModVisitor { ccx: &ccx });
         }
 
-        collector::print_collection_results(&ccx);
+        collector::print_collection_results(ccx.shared());
 
         symbol_names_test::report_symbol_names(&ccx);
     }
 
-    for ccx in shared_ccx.iter() {
+    for ccx in crate_context_list.iter() {
         if ccx.sess().opts.debuginfo != NoDebugInfo {
             debuginfo::finalize(&ccx);
         }
@@ -2794,7 +2798,7 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>,
         }
     }
 
-    let modules = shared_ccx.iter()
+    let modules = crate_context_list.iter()
         .map(|ccx| ModuleTranslation { llcx: ccx.llcx(), llmod: ccx.llmod() })
         .collect();
 
@@ -2820,14 +2824,14 @@ pub fn trans_crate<'tcx>(tcx: &TyCtxt<'tcx>,
         }
     }
 
-    if codegen_units > 1 {
-        internalize_symbols(&shared_ccx,
+    if codegen_unit_count > 1 {
+        internalize_symbols(&crate_context_list,
                             &reachable_symbols.iter().map(|x| &x[..]).collect());
     }
 
     if sess.target.target.options.is_like_msvc &&
        sess.crate_types.borrow().iter().any(|ct| *ct == config::CrateTypeRlib) {
-        create_imps(&shared_ccx);
+        create_imps(&crate_context_list);
     }
 
     let metadata_module = ModuleTranslation {
@@ -2912,10 +2916,11 @@ impl<'a, 'tcx, 'v> Visitor<'v> for TransItemsWithinModVisitor<'a, 'tcx> {
     }
 }
 
-fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
-    let time_passes = ccx.sess().time_passes();
+fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>)
+                                                     -> Vec<CodegenUnit<'tcx>> {
+    let time_passes = scx.sess().time_passes();
 
-    let collection_mode = match ccx.sess().opts.debugging_opts.print_trans_items {
+    let collection_mode = match scx.sess().opts.debugging_opts.print_trans_items {
         Some(ref s) => {
             let mode_string = s.to_lowercase();
             let mode_string = mode_string.trim();
@@ -2926,7 +2931,7 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
                     let message = format!("Unknown codegen-item collection mode '{}'. \
                                            Falling back to 'lazy' mode.",
                                            mode_string);
-                    ccx.sess().warn(&message);
+                    scx.sess().warn(&message);
                 }
 
                 TransItemCollectionMode::Lazy
@@ -2936,27 +2941,27 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
     };
 
     let (items, reference_map) = time(time_passes, "translation item collection", || {
-        collector::collect_crate_translation_items(&ccx, collection_mode)
+        collector::collect_crate_translation_items(scx, collection_mode)
     });
 
-    let strategy = if ccx.sess().opts.debugging_opts.incremental.is_some() {
+    let strategy = if scx.sess().opts.debugging_opts.incremental.is_some() {
         PartitioningStrategy::PerModule
     } else {
-        PartitioningStrategy::FixedUnitCount(ccx.sess().opts.cg.codegen_units)
+        PartitioningStrategy::FixedUnitCount(scx.sess().opts.cg.codegen_units)
     };
 
     let codegen_units = time(time_passes, "codegen unit partitioning", || {
-        partitioning::partition(ccx.tcx(),
+        partitioning::partition(scx.tcx(),
                                 items.iter().cloned(),
                                 strategy,
                                 &reference_map)
     });
 
-    if ccx.sess().opts.debugging_opts.print_trans_items.is_some() {
+    if scx.sess().opts.debugging_opts.print_trans_items.is_some() {
         let mut item_to_cgus = HashMap::new();
 
-        for cgu in codegen_units {
-            for (trans_item, linkage) in cgu.items {
+        for cgu in &codegen_units {
+            for (&trans_item, &linkage) in &cgu.items {
                 item_to_cgus.entry(trans_item)
                             .or_insert(Vec::new())
                             .push((cgu.name.clone(), linkage));
@@ -2966,7 +2971,7 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
         let mut item_keys: Vec<_> = items
             .iter()
             .map(|i| {
-                let mut output = i.to_string(ccx);
+                let mut output = i.to_string(scx.tcx());
                 output.push_str(" @@");
                 let mut empty = Vec::new();
                 let mut cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
@@ -3005,10 +3010,12 @@ fn collect_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
             println!("TRANS_ITEM {}", item);
         }
 
-        let mut ccx_map = ccx.translation_items().borrow_mut();
+        let mut ccx_map = scx.translation_items().borrow_mut();
 
         for cgi in items {
             ccx_map.insert(cgi, TransItemState::PredictedButNotGenerated);
         }
     }
+
+    codegen_units
 }
diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs
index f5288220b2e..db605e4dc5d 100644
--- a/src/librustc_trans/callee.rs
+++ b/src/librustc_trans/callee.rs
@@ -156,7 +156,7 @@ impl<'tcx> Callee<'tcx> {
         let trait_id = method_item.container().id();
         let trait_ref = ty::Binder(substs.to_trait_ref(tcx, trait_id));
         let trait_ref = infer::normalize_associated_type(tcx, &trait_ref);
-        match common::fulfill_obligation(ccx, DUMMY_SP, trait_ref) {
+        match common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref) {
             traits::VtableImpl(vtable_impl) => {
                 let impl_did = vtable_impl.impl_def_id;
                 let mname = tcx.item_name(def_id);
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index a0311ec6066..ba924d6ae3e 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -210,9 +210,8 @@ use syntax::{attr, errors};
 use syntax::parse::token;
 
 use base::{custom_coerce_unsize_info, llvm_linkage_by_name};
-use context::CrateContext;
-use common::{fulfill_obligation, normalize_and_test_predicates,
-                    type_is_sized};
+use context::SharedCrateContext;
+use common::{fulfill_obligation, normalize_and_test_predicates, type_is_sized};
 use glue::{self, DropGlueKind};
 use llvm;
 use meth;
@@ -320,14 +319,14 @@ impl<'tcx> ReferenceMap<'tcx> {
     }
 }
 
-pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+pub fn collect_crate_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                                  mode: TransItemCollectionMode)
                                                  -> (FnvHashSet<TransItem<'tcx>>,
                                                      ReferenceMap<'tcx>) {
     // We are not tracking dependencies of this pass as it has to be re-executed
     // every time no matter what.
-    ccx.tcx().dep_graph.with_ignore(|| {
-        let roots = collect_roots(ccx, mode);
+    scx.tcx().dep_graph.with_ignore(|| {
+        let roots = collect_roots(scx, mode);
 
         debug!("Building translation item graph, beginning at roots");
         let mut visited = FnvHashSet();
@@ -335,7 +334,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         let mut reference_map = ReferenceMap::new();
 
         for root in roots {
-            collect_items_rec(ccx,
+            collect_items_rec(scx,
                               root,
                               &mut visited,
                               &mut recursion_depths,
@@ -348,7 +347,7 @@ pub fn collect_crate_translation_items<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 // Find all non-generic items by walking the HIR. These items serve as roots to
 // start monomorphizing from.
-fn collect_roots<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+fn collect_roots<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                            mode: TransItemCollectionMode)
                            -> Vec<TransItem<'tcx>> {
     debug!("Collecting roots");
@@ -356,20 +355,20 @@ fn collect_roots<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     {
         let mut visitor = RootCollector {
-            ccx: ccx,
+            scx: scx,
             mode: mode,
             output: &mut roots,
             enclosing_item: None,
         };
 
-        ccx.tcx().map.krate().visit_all_items(&mut visitor);
+        scx.tcx().map.krate().visit_all_items(&mut visitor);
     }
 
     roots
 }
 
 // Collect all monomorphized translation items reachable from `starting_point`
-fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
+fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
                                    starting_point: TransItem<'tcx>,
                                    visited: &mut FnvHashSet<TransItem<'tcx>>,
                                    recursion_depths: &mut DefIdMap<usize>,
@@ -378,36 +377,36 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
         // We've been here already, no need to search again.
         return;
     }
-    debug!("BEGIN collect_items_rec({})", starting_point.to_string(ccx));
+    debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx.tcx()));
 
     let mut neighbors = Vec::new();
     let recursion_depth_reset;
 
     match starting_point {
         TransItem::DropGlue(t) => {
-            find_drop_glue_neighbors(ccx, t, &mut neighbors);
+            find_drop_glue_neighbors(scx, t, &mut neighbors);
             recursion_depth_reset = None;
         }
         TransItem::Static(node_id) => {
-            let def_id = ccx.tcx().map.local_def_id(node_id);
-            let ty = ccx.tcx().lookup_item_type(def_id).ty;
-            let ty = glue::get_drop_glue_type(ccx, ty);
+            let def_id = scx.tcx().map.local_def_id(node_id);
+            let ty = scx.tcx().lookup_item_type(def_id).ty;
+            let ty = glue::get_drop_glue_type(scx.tcx(), ty);
             neighbors.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
             recursion_depth_reset = None;
         }
         TransItem::Fn(instance) => {
             // Keep track of the monomorphization recursion depth
-            recursion_depth_reset = Some(check_recursion_limit(ccx,
+            recursion_depth_reset = Some(check_recursion_limit(scx.tcx(),
                                                                instance,
                                                                recursion_depths));
 
             // Scan the MIR in order to find function calls, closures, and
             // drop-glue
-            let mir = errors::expect(ccx.sess().diagnostic(), ccx.get_mir(instance.def),
+            let mir = errors::expect(scx.sess().diagnostic(), scx.get_mir(instance.def),
                 || format!("Could not find MIR for function: {}", instance));
 
             let mut visitor = MirNeighborCollector {
-                ccx: ccx,
+                scx: scx,
                 mir: &mir,
                 output: &mut neighbors,
                 param_substs: instance.substs
@@ -420,36 +419,36 @@ fn collect_items_rec<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
         }
     }
 
-    record_references(ccx, starting_point, &neighbors[..], reference_map);
+    record_references(scx.tcx(), starting_point, &neighbors[..], reference_map);
 
     for neighbour in neighbors {
-        collect_items_rec(ccx, neighbour, visited, recursion_depths, reference_map);
+        collect_items_rec(scx, neighbour, visited, recursion_depths, reference_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(ccx));
+    debug!("END collect_items_rec({})", starting_point.to_string(scx.tcx()));
 }
 
-fn record_references<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                               caller: TransItem<'tcx>,
-                               callees: &[TransItem<'tcx>],
-                               reference_map: &mut ReferenceMap<'tcx>) {
+fn record_references<'tcx>(tcx: &TyCtxt<'tcx>,
+                           caller: TransItem<'tcx>,
+                           callees: &[TransItem<'tcx>],
+                           reference_map: &mut ReferenceMap<'tcx>) {
     let iter = callees.into_iter()
                       .map(|callee| {
                         let is_inlining_candidate = callee.is_from_extern_crate() ||
-                                                    callee.requests_inline(ccx.tcx());
+                                                    callee.requests_inline(tcx);
                         (*callee, is_inlining_candidate)
                       });
     reference_map.record_references(caller, iter);
 }
 
-fn check_recursion_limit<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
-                                       instance: Instance<'tcx>,
-                                       recursion_depths: &mut DefIdMap<usize>)
-                                       -> (DefId, usize) {
+fn check_recursion_limit<'tcx>(tcx: &TyCtxt<'tcx>,
+                               instance: Instance<'tcx>,
+                               recursion_depths: &mut DefIdMap<usize>)
+                               -> (DefId, usize) {
     let recursion_depth = recursion_depths.get(&instance.def)
                                           .map(|x| *x)
                                           .unwrap_or(0);
@@ -458,13 +457,13 @@ fn check_recursion_limit<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
     // Code that needs to instantiate the same function recursively
     // more than the recursion limit is assumed to be causing an
     // infinite expansion.
-    if recursion_depth > ccx.sess().recursion_limit.get() {
+    if recursion_depth > tcx.sess.recursion_limit.get() {
         let error = format!("reached the recursion limit while instantiating `{}`",
                             instance);
-        if let Some(node_id) = ccx.tcx().map.as_local_node_id(instance.def) {
-            ccx.sess().span_fatal(ccx.tcx().map.span(node_id), &error);
+        if let Some(node_id) = tcx.map.as_local_node_id(instance.def) {
+            tcx.sess.span_fatal(tcx.map.span(node_id), &error);
         } else {
-            ccx.sess().fatal(&error);
+            tcx.sess.fatal(&error);
         }
     }
 
@@ -474,7 +473,7 @@ fn check_recursion_limit<'a, 'tcx: 'a>(ccx: &CrateContext<'a, 'tcx>,
 }
 
 struct MirNeighborCollector<'a, 'tcx: 'a> {
-    ccx: &'a CrateContext<'a, 'tcx>,
+    scx: &'a SharedCrateContext<'a, 'tcx>,
     mir: &'a mir::Mir<'tcx>,
     output: &'a mut Vec<TransItem<'tcx>>,
     param_substs: &'tcx Substs<'tcx>
@@ -488,8 +487,8 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
         match *rvalue {
             mir::Rvalue::Aggregate(mir::AggregateKind::Closure(def_id,
                                                                ref substs), _) => {
-                assert!(can_have_local_instance(self.ccx, def_id));
-                let trans_item = create_fn_trans_item(self.ccx,
+                assert!(can_have_local_instance(self.scx.tcx(), def_id));
+                let trans_item = create_fn_trans_item(self.scx.tcx(),
                                                       def_id,
                                                       substs.func_substs,
                                                       self.param_substs);
@@ -499,21 +498,21 @@ 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 = monomorphize::apply_param_substs(self.ccx.tcx(),
+                let target_ty = monomorphize::apply_param_substs(self.scx.tcx(),
                                                                  self.param_substs,
                                                                  &target_ty);
-                let source_ty = self.mir.operand_ty(self.ccx.tcx(), operand);
-                let source_ty = monomorphize::apply_param_substs(self.ccx.tcx(),
+                let source_ty = self.mir.operand_ty(self.scx.tcx(), operand);
+                let source_ty = monomorphize::apply_param_substs(self.scx.tcx(),
                                                                  self.param_substs,
                                                                  &source_ty);
-                let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.ccx,
+                let (source_ty, target_ty) = find_vtable_types_for_unsizing(self.scx,
                                                                             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.ccx,
+                    create_trans_items_for_vtable_methods(self.scx,
                                                           target_ty,
                                                           source_ty,
                                                           self.output);
@@ -521,15 +520,15 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
             }
             mir::Rvalue::Box(_) => {
                 let exchange_malloc_fn_def_id =
-                    self.ccx
+                    self.scx
                         .tcx()
                         .lang_items
                         .require(ExchangeMallocFnLangItem)
-                        .unwrap_or_else(|e| self.ccx.sess().fatal(&e));
+                        .unwrap_or_else(|e| self.scx.sess().fatal(&e));
 
-                assert!(can_have_local_instance(self.ccx, exchange_malloc_fn_def_id));
+                assert!(can_have_local_instance(self.scx.tcx(), exchange_malloc_fn_def_id));
                 let exchange_malloc_fn_trans_item =
-                    create_fn_trans_item(self.ccx,
+                    create_fn_trans_item(self.scx.tcx(),
                                          exchange_malloc_fn_def_id,
                                          &Substs::empty(),
                                          self.param_substs);
@@ -548,14 +547,14 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
         debug!("visiting lvalue {:?}", *lvalue);
 
         if let mir_visit::LvalueContext::Drop = context {
-            let ty = self.mir.lvalue_ty(self.ccx.tcx(), lvalue)
-                             .to_ty(self.ccx.tcx());
+            let ty = self.mir.lvalue_ty(self.scx.tcx(), lvalue)
+                             .to_ty(self.scx.tcx());
 
-            let ty = monomorphize::apply_param_substs(self.ccx.tcx(),
+            let ty = monomorphize::apply_param_substs(self.scx.tcx(),
                                                       self.param_substs,
                                                       &ty);
-            let ty = self.ccx.tcx().erase_regions(&ty);
-            let ty = glue::get_drop_glue_type(self.ccx, ty);
+            let ty = self.scx.tcx().erase_regions(&ty);
+            let ty = glue::get_drop_glue_type(self.scx.tcx(), ty);
             self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
         }
 
@@ -583,7 +582,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
             //
             // Calling do_static_dispatch() here will map the def_id of
             // `std::cmp::partial_cmp` to the def_id of `i32::partial_cmp<i32>`
-            let dispatched = do_static_dispatch(self.ccx,
+            let dispatched = do_static_dispatch(self.scx,
                                                 callee_def_id,
                                                 callee_substs,
                                                 self.param_substs);
@@ -594,9 +593,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                 // object shim or a closure that is handled differently),
                 // we check if the callee is something that will actually
                 // result in a translation item ...
-                if can_result_in_trans_item(self.ccx, callee_def_id) {
+                if can_result_in_trans_item(self.scx.tcx(), callee_def_id) {
                     // ... and create one if it does.
-                    let trans_item = create_fn_trans_item(self.ccx,
+                    let trans_item = create_fn_trans_item(self.scx.tcx(),
                                                           callee_def_id,
                                                           callee_substs,
                                                           self.param_substs);
@@ -607,21 +606,21 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
 
         self.super_operand(operand);
 
-        fn can_result_in_trans_item<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                              def_id: DefId)
-                                              -> bool {
-            if !match ccx.tcx().lookup_item_type(def_id).ty.sty {
+        fn can_result_in_trans_item<'tcx>(tcx: &TyCtxt<'tcx>,
+                                          def_id: DefId)
+                                          -> bool {
+            if !match tcx.lookup_item_type(def_id).ty.sty {
                 ty::TyFnDef(def_id, _, _) => {
                     // Some constructors also have type TyFnDef but they are
                     // always instantiated inline and don't result in
                     // translation item. Same for FFI functions.
-                    match ccx.tcx().map.get_if_local(def_id) {
+                    match tcx.map.get_if_local(def_id) {
                         Some(hir_map::NodeVariant(_))    |
                         Some(hir_map::NodeStructCtor(_)) |
                         Some(hir_map::NodeForeignItem(_)) => false,
                         Some(_) => true,
                         None => {
-                            ccx.sess().cstore.variant_kind(def_id).is_none()
+                            tcx.sess.cstore.variant_kind(def_id).is_none()
                         }
                     }
                 }
@@ -631,21 +630,21 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
                 return false;
             }
 
-            can_have_local_instance(ccx, def_id)
+            can_have_local_instance(tcx, def_id)
         }
     }
 }
 
-fn can_have_local_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                     def_id: DefId)
-                                     -> bool {
+fn can_have_local_instance<'tcx>(tcx: &TyCtxt<'tcx>,
+                                 def_id: DefId)
+                                 -> bool {
     // Take a look if we have the definition available. If not, we
     // will not emit code for this item in the local crate, and thus
     // don't create a translation item for it.
-    def_id.is_local() || ccx.sess().cstore.is_item_mir_available(def_id)
+    def_id.is_local() || tcx.sess.cstore.is_item_mir_available(def_id)
 }
 
-fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                       dg: DropGlueKind<'tcx>,
                                       output: &mut Vec<TransItem<'tcx>>) {
     let ty = match dg {
@@ -657,19 +656,19 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         }
     };
 
-    debug!("find_drop_glue_neighbors: {}", type_to_string(ccx, ty));
+    debug!("find_drop_glue_neighbors: {}", type_to_string(scx.tcx(), ty));
 
     // Make sure the exchange_free_fn() lang-item gets translated if
     // there is a boxed value.
     if let ty::TyBox(_) = ty.sty {
-        let exchange_free_fn_def_id = ccx.tcx()
+        let exchange_free_fn_def_id = scx.tcx()
                                          .lang_items
                                          .require(ExchangeFreeFnLangItem)
-                                         .unwrap_or_else(|e| ccx.sess().fatal(&e));
+                                         .unwrap_or_else(|e| scx.sess().fatal(&e));
 
-        assert!(can_have_local_instance(ccx, exchange_free_fn_def_id));
+        assert!(can_have_local_instance(scx.tcx(), exchange_free_fn_def_id));
         let exchange_free_fn_trans_item =
-            create_fn_trans_item(ccx,
+            create_fn_trans_item(scx.tcx(),
                                  exchange_free_fn_def_id,
                                  &Substs::empty(),
                                  &Substs::empty());
@@ -688,12 +687,12 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     if let Some(destructor_did) = destructor_did {
         use rustc::ty::ToPolyTraitRef;
 
-        let drop_trait_def_id = ccx.tcx()
+        let drop_trait_def_id = scx.tcx()
                                    .lang_items
                                    .drop_trait()
                                    .unwrap();
 
-        let self_type_substs = ccx.tcx().mk_substs(
+        let self_type_substs = scx.tcx().mk_substs(
             Substs::empty().with_self_ty(ty));
 
         let trait_ref = ty::TraitRef {
@@ -701,13 +700,13 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             substs: self_type_substs,
         }.to_poly_trait_ref();
 
-        let substs = match fulfill_obligation(ccx, DUMMY_SP, trait_ref) {
+        let substs = match fulfill_obligation(scx, DUMMY_SP, trait_ref) {
             traits::VtableImpl(data) => data.substs,
             _ => bug!()
         };
 
-        if can_have_local_instance(ccx, destructor_did) {
-            let trans_item = create_fn_trans_item(ccx,
+        if can_have_local_instance(scx.tcx(), destructor_did) {
+            let trans_item = create_fn_trans_item(scx.tcx(),
                                                   destructor_did,
                                                   substs,
                                                   &Substs::empty());
@@ -738,35 +737,35 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         ty::TyStruct(ref adt_def, substs) |
         ty::TyEnum(ref adt_def, substs) => {
             for field in adt_def.all_fields() {
-                let field_type = monomorphize::apply_param_substs(ccx.tcx(),
+                let field_type = monomorphize::apply_param_substs(scx.tcx(),
                                                                   substs,
                                                                   &field.unsubst_ty());
-                let field_type = glue::get_drop_glue_type(ccx, field_type);
+                let field_type = glue::get_drop_glue_type(scx.tcx(), field_type);
 
-                if glue::type_needs_drop(ccx.tcx(), field_type) {
+                if glue::type_needs_drop(scx.tcx(), field_type) {
                     output.push(TransItem::DropGlue(DropGlueKind::Ty(field_type)));
                 }
             }
         }
         ty::TyClosure(_, ref substs) => {
             for upvar_ty in &substs.upvar_tys {
-                let upvar_ty = glue::get_drop_glue_type(ccx, upvar_ty);
-                if glue::type_needs_drop(ccx.tcx(), upvar_ty) {
+                let upvar_ty = glue::get_drop_glue_type(scx.tcx(), upvar_ty);
+                if glue::type_needs_drop(scx.tcx(), upvar_ty) {
                     output.push(TransItem::DropGlue(DropGlueKind::Ty(upvar_ty)));
                 }
             }
         }
         ty::TyBox(inner_type)      |
         ty::TyArray(inner_type, _) => {
-            let inner_type = glue::get_drop_glue_type(ccx, inner_type);
-            if glue::type_needs_drop(ccx.tcx(), inner_type) {
+            let inner_type = glue::get_drop_glue_type(scx.tcx(), inner_type);
+            if glue::type_needs_drop(scx.tcx(), inner_type) {
                 output.push(TransItem::DropGlue(DropGlueKind::Ty(inner_type)));
             }
         }
         ty::TyTuple(ref args) => {
             for arg in args {
-                let arg = glue::get_drop_glue_type(ccx, arg);
-                if glue::type_needs_drop(ccx.tcx(), arg) {
+                let arg = glue::get_drop_glue_type(scx.tcx(), arg);
+                if glue::type_needs_drop(scx.tcx(), arg) {
                     output.push(TransItem::DropGlue(DropGlueKind::Ty(arg)));
                 }
             }
@@ -780,25 +779,25 @@ fn find_drop_glue_neighbors<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 }
 
-fn do_static_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                 fn_def_id: DefId,
                                 fn_substs: &'tcx Substs<'tcx>,
                                 param_substs: &'tcx Substs<'tcx>)
                                 -> Option<(DefId, &'tcx Substs<'tcx>)> {
     debug!("do_static_dispatch(fn_def_id={}, fn_substs={:?}, param_substs={:?})",
-           def_id_to_string(ccx, fn_def_id),
+           def_id_to_string(scx.tcx(), fn_def_id),
            fn_substs,
            param_substs);
 
-    let is_trait_method = ccx.tcx().trait_of_item(fn_def_id).is_some();
+    let is_trait_method = scx.tcx().trait_of_item(fn_def_id).is_some();
 
     if is_trait_method {
-        match ccx.tcx().impl_or_trait_item(fn_def_id) {
+        match scx.tcx().impl_or_trait_item(fn_def_id) {
             ty::MethodTraitItem(ref method) => {
                 match method.container {
                     ty::TraitContainer(trait_def_id) => {
                         debug!(" => trait method, attempting to find impl");
-                        do_static_trait_method_dispatch(ccx,
+                        do_static_trait_method_dispatch(scx,
                                                         method,
                                                         trait_def_id,
                                                         fn_substs,
@@ -823,19 +822,19 @@ fn do_static_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 // Given a trait-method and substitution information, find out the actual
 // implementation of the trait method.
-fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                              trait_method: &ty::Method,
                                              trait_id: DefId,
                                              callee_substs: &'tcx Substs<'tcx>,
                                              param_substs: &'tcx Substs<'tcx>)
                                              -> Option<(DefId, &'tcx Substs<'tcx>)> {
-    let tcx = ccx.tcx();
+    let tcx = scx.tcx();
     debug!("do_static_trait_method_dispatch(trait_method={}, \
                                             trait_id={}, \
                                             callee_substs={:?}, \
                                             param_substs={:?}",
-           def_id_to_string(ccx, trait_method.def_id),
-           def_id_to_string(ccx, trait_id),
+           def_id_to_string(scx.tcx(), trait_method.def_id),
+           def_id_to_string(scx.tcx(), trait_id),
            callee_substs,
            param_substs);
 
@@ -844,7 +843,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                                        callee_substs);
 
     let trait_ref = ty::Binder(rcvr_substs.to_trait_ref(tcx, trait_id));
-    let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
+    let vtbl = fulfill_obligation(scx, DUMMY_SP, trait_ref);
 
     // Now that we know which impl is being used, we can dispatch to
     // the actual function:
@@ -912,7 +911,7 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 ///
 /// 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>(ccx: &CrateContext<'a, 'tcx>,
+fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                             source_ty: ty::Ty<'tcx>,
                                             target_ty: ty::Ty<'tcx>)
                                             -> (ty::Ty<'tcx>, ty::Ty<'tcx>) {
@@ -926,10 +925,10 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
          &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => {
             let (inner_source, inner_target) = (a, b);
 
-            if !type_is_sized(ccx.tcx(), inner_source) {
+            if !type_is_sized(scx.tcx(), inner_source) {
                 (inner_source, inner_target)
             } else {
-                ccx.tcx().struct_lockstep_tails(inner_source, inner_target)
+                scx.tcx().struct_lockstep_tails(inner_source, inner_target)
             }
         }
 
@@ -937,7 +936,7 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
          &ty::TyStruct(target_adt_def, target_substs)) => {
             assert_eq!(source_adt_def, target_adt_def);
 
-            let kind = custom_coerce_unsize_info(ccx, source_ty, target_ty);
+            let kind = custom_coerce_unsize_info(scx, source_ty, target_ty);
 
             let coerce_index = match kind {
                 CustomCoerceUnsized::Struct(i) => i
@@ -949,10 +948,10 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             assert!(coerce_index < source_fields.len() &&
                     source_fields.len() == target_fields.len());
 
-            find_vtable_types_for_unsizing(ccx,
-                                           source_fields[coerce_index].ty(ccx.tcx(),
+            find_vtable_types_for_unsizing(scx,
+                                           source_fields[coerce_index].ty(scx.tcx(),
                                                                           source_substs),
-                                           target_fields[coerce_index].ty(ccx.tcx(),
+                                           target_fields[coerce_index].ty(scx.tcx(),
                                                                           target_substs))
         }
         _ => bug!("find_vtable_types_for_unsizing: invalid coercion {:?} -> {:?}",
@@ -961,61 +960,59 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     }
 }
 
-fn create_fn_trans_item<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                  def_id: DefId,
-                                  fn_substs: &Substs<'tcx>,
-                                  param_substs: &Substs<'tcx>)
-                                  -> TransItem<'tcx>
-{
+fn create_fn_trans_item<'tcx>(tcx: &TyCtxt<'tcx>,
+                              def_id: DefId,
+                              fn_substs: &Substs<'tcx>,
+                              param_substs: &Substs<'tcx>)
+                              -> TransItem<'tcx> {
     debug!("create_fn_trans_item(def_id={}, fn_substs={:?}, param_substs={:?})",
-            def_id_to_string(ccx, def_id),
+            def_id_to_string(tcx, def_id),
             fn_substs,
             param_substs);
 
     // We only get here, if fn_def_id either designates a local item or
     // an inlineable external item. Non-inlineable external items are
     // ignored because we don't want to generate any code for them.
-    let concrete_substs = monomorphize::apply_param_substs(ccx.tcx(),
+    let concrete_substs = monomorphize::apply_param_substs(tcx,
                                                            param_substs,
                                                            fn_substs);
-    let concrete_substs = ccx.tcx().erase_regions(&concrete_substs);
+    let concrete_substs = tcx.erase_regions(&concrete_substs);
 
     let trans_item =
         TransItem::Fn(Instance::new(def_id,
-                                    &ccx.tcx().mk_substs(concrete_substs)));
-
+                                    &tcx.mk_substs(concrete_substs)));
     return trans_item;
 }
 
 /// 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>(ccx: &CrateContext<'a, 'tcx>,
+fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                                    trait_ty: ty::Ty<'tcx>,
                                                    impl_ty: ty::Ty<'tcx>,
                                                    output: &mut Vec<TransItem<'tcx>>) {
     assert!(!trait_ty.needs_subst() && !impl_ty.needs_subst());
 
     if let ty::TyTrait(ref trait_ty) = trait_ty.sty {
-        let poly_trait_ref = trait_ty.principal_trait_ref_with_self_ty(ccx.tcx(),
+        let poly_trait_ref = trait_ty.principal_trait_ref_with_self_ty(scx.tcx(),
                                                                        impl_ty);
 
         // Walk all methods of the trait, including those of its supertraits
-        for trait_ref in traits::supertraits(ccx.tcx(), poly_trait_ref) {
-            let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
+        for trait_ref in traits::supertraits(scx.tcx(), poly_trait_ref) {
+            let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref);
             match vtable {
                 traits::VtableImpl(
                     traits::VtableImplData {
                         impl_def_id,
                         substs,
                         nested: _ }) => {
-                    let items = meth::get_vtable_methods(ccx, impl_def_id, substs)
+                    let items = meth::get_vtable_methods(scx.tcx(), impl_def_id, substs)
                         .into_iter()
                         // filter out None values
                         .filter_map(|opt_impl_method| opt_impl_method)
                         // create translation items
                         .filter_map(|impl_method| {
-                            if can_have_local_instance(ccx, impl_method.method.def_id) {
-                                Some(create_fn_trans_item(ccx,
+                            if can_have_local_instance(scx.tcx(), impl_method.method.def_id) {
+                                Some(create_fn_trans_item(scx.tcx(),
                                                           impl_method.method.def_id,
                                                           &impl_method.substs,
                                                           &Substs::empty()))
@@ -1038,7 +1035,7 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 //=-----------------------------------------------------------------------------
 
 struct RootCollector<'b, 'a: 'b, 'tcx: 'a + 'b> {
-    ccx: &'b CrateContext<'a, 'tcx>,
+    scx: &'b SharedCrateContext<'a, 'tcx>,
     mode: TransItemCollectionMode,
     output: &'b mut Vec<TransItem<'tcx>>,
     enclosing_item: Option<&'tcx hir::Item>,
@@ -1063,7 +1060,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
 
             hir::ItemImpl(..) => {
                 if self.mode == TransItemCollectionMode::Eager {
-                    create_trans_items_for_default_impls(self.ccx,
+                    create_trans_items_for_default_impls(self.scx.tcx(),
                                                          item,
                                                          self.output);
                 }
@@ -1073,35 +1070,35 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
             hir::ItemStruct(_, ref generics)      => {
                 if !generics.is_parameterized() {
                     let ty = {
-                        let tables = self.ccx.tcx().tables.borrow();
+                        let tables = self.scx.tcx().tables.borrow();
                         tables.node_types[&item.id]
                     };
 
                     if self.mode == TransItemCollectionMode::Eager {
                         debug!("RootCollector: ADT drop-glue for {}",
-                               def_id_to_string(self.ccx,
-                                                self.ccx.tcx().map.local_def_id(item.id)));
+                               def_id_to_string(self.scx.tcx(),
+                                                self.scx.tcx().map.local_def_id(item.id)));
 
-                        let ty = glue::get_drop_glue_type(self.ccx, ty);
+                        let ty = glue::get_drop_glue_type(self.scx.tcx(), ty);
                         self.output.push(TransItem::DropGlue(DropGlueKind::Ty(ty)));
                     }
                 }
             }
             hir::ItemStatic(..) => {
                 debug!("RootCollector: ItemStatic({})",
-                       def_id_to_string(self.ccx,
-                                        self.ccx.tcx().map.local_def_id(item.id)));
+                       def_id_to_string(self.scx.tcx(),
+                                        self.scx.tcx().map.local_def_id(item.id)));
                 self.output.push(TransItem::Static(item.id));
             }
             hir::ItemFn(_, _, constness, _, ref generics, _) => {
                 if !generics.is_type_parameterized() &&
                    constness == hir::Constness::NotConst {
-                    let def_id = self.ccx.tcx().map.local_def_id(item.id);
+                    let def_id = self.scx.tcx().map.local_def_id(item.id);
 
                     debug!("RootCollector: ItemFn({})",
-                           def_id_to_string(self.ccx, def_id));
+                           def_id_to_string(self.scx.tcx(), def_id));
 
-                    let instance = Instance::mono(self.ccx.tcx(), def_id);
+                    let instance = Instance::mono(self.scx.tcx(), def_id);
                     self.output.push(TransItem::Fn(instance));
                 }
             }
@@ -1118,7 +1115,7 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
                 constness,
                 ..
             }, _) if constness == hir::Constness::NotConst => {
-                let hir_map = &self.ccx.tcx().map;
+                let hir_map = &self.scx.tcx().map;
                 let parent_node_id = hir_map.get_parent_node(ii.id);
                 let is_impl_generic = match hir_map.expect_item(parent_node_id) {
                     &hir::Item {
@@ -1133,12 +1130,12 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
                 };
 
                 if !generics.is_type_parameterized() && !is_impl_generic {
-                    let def_id = self.ccx.tcx().map.local_def_id(ii.id);
+                    let def_id = self.scx.tcx().map.local_def_id(ii.id);
 
                     debug!("RootCollector: MethodImplItem({})",
-                           def_id_to_string(self.ccx, def_id));
+                           def_id_to_string(self.scx.tcx(), def_id));
 
-                    let instance = Instance::mono(self.ccx.tcx(), def_id);
+                    let instance = Instance::mono(self.scx.tcx(), def_id);
                     self.output.push(TransItem::Fn(instance));
                 }
             }
@@ -1149,9 +1146,9 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
     }
 }
 
-fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                                  item: &'tcx hir::Item,
-                                                  output: &mut Vec<TransItem<'tcx>>) {
+fn create_trans_items_for_default_impls<'tcx>(tcx: &TyCtxt<'tcx>,
+                                              item: &'tcx hir::Item,
+                                              output: &mut Vec<TransItem<'tcx>>) {
     match item.node {
         hir::ItemImpl(_,
                       _,
@@ -1163,11 +1160,10 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                 return
             }
 
-            let tcx = ccx.tcx();
             let impl_def_id = tcx.map.local_def_id(item.id);
 
             debug!("create_trans_items_for_default_impls(item={})",
-                   def_id_to_string(ccx, impl_def_id));
+                   def_id_to_string(tcx, impl_def_id));
 
             if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
                 let default_impls = tcx.provided_trait_methods(trait_ref.def_id);
@@ -1194,13 +1190,13 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     assert!(mth.is_provided);
 
                     let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
-                    if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
+                    if !normalize_and_test_predicates(tcx, predicates.into_vec()) {
                         continue;
                     }
 
-                    if can_have_local_instance(ccx, default_impl.def_id) {
-                        let empty_substs = ccx.tcx().mk_substs(ccx.tcx().erase_regions(mth.substs));
-                        let item = create_fn_trans_item(ccx,
+                    if can_have_local_instance(tcx, default_impl.def_id) {
+                        let empty_substs = tcx.mk_substs(tcx.erase_regions(mth.substs));
+                        let item = create_fn_trans_item(tcx,
                                                         default_impl.def_id,
                                                         callee_substs,
                                                         empty_substs);
@@ -1229,9 +1225,9 @@ fn create_trans_items_for_default_impls<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 /// Same as `unique_type_name()` but with the result pushed onto the given
 /// `output` parameter.
-pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                                       t: ty::Ty<'tcx>,
-                                       output: &mut String) {
+pub fn push_unique_type_name<'tcx>(tcx: &TyCtxt<'tcx>,
+                                   t: ty::Ty<'tcx>,
+                                   output: &mut String) {
     match t.sty {
         ty::TyBool              => output.push_str("bool"),
         ty::TyChar              => output.push_str("char"),
@@ -1250,13 +1246,13 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         ty::TyFloat(ast::FloatTy::F64) => output.push_str("f64"),
         ty::TyStruct(adt_def, substs) |
         ty::TyEnum(adt_def, substs) => {
-            push_item_name(cx, adt_def.did, output);
-            push_type_params(cx, &substs.types, &[], output);
+            push_item_name(tcx, adt_def.did, output);
+            push_type_params(tcx, &substs.types, &[], output);
         },
         ty::TyTuple(ref component_types) => {
             output.push('(');
             for &component_type in component_types {
-                push_unique_type_name(cx, component_type, output);
+                push_unique_type_name(tcx, component_type, output);
                 output.push_str(", ");
             }
             if !component_types.is_empty() {
@@ -1267,7 +1263,7 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         },
         ty::TyBox(inner_type) => {
             output.push_str("Box<");
-            push_unique_type_name(cx, inner_type, output);
+            push_unique_type_name(tcx, inner_type, output);
             output.push('>');
         },
         ty::TyRawPtr(ty::TypeAndMut { ty: inner_type, mutbl } ) => {
@@ -1277,7 +1273,7 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 hir::MutMutable => output.push_str("mut "),
             }
 
-            push_unique_type_name(cx, inner_type, output);
+            push_unique_type_name(tcx, inner_type, output);
         },
         ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => {
             output.push('&');
@@ -1285,22 +1281,22 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 output.push_str("mut ");
             }
 
-            push_unique_type_name(cx, inner_type, output);
+            push_unique_type_name(tcx, inner_type, output);
         },
         ty::TyArray(inner_type, len) => {
             output.push('[');
-            push_unique_type_name(cx, inner_type, output);
+            push_unique_type_name(tcx, inner_type, output);
             output.push_str(&format!("; {}", len));
             output.push(']');
         },
         ty::TySlice(inner_type) => {
             output.push('[');
-            push_unique_type_name(cx, inner_type, output);
+            push_unique_type_name(tcx, inner_type, output);
             output.push(']');
         },
         ty::TyTrait(ref trait_data) => {
-            push_item_name(cx, trait_data.principal.skip_binder().def_id, output);
-            push_type_params(cx,
+            push_item_name(tcx, trait_data.principal.skip_binder().def_id, output);
+            push_type_params(tcx,
                              &trait_data.principal.skip_binder().substs.types,
                              &trait_data.bounds.projection_bounds,
                              output);
@@ -1319,10 +1315,10 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
 
             output.push_str("fn(");
 
-            let sig = cx.tcx().erase_late_bound_regions(sig);
+            let sig = tcx.erase_late_bound_regions(sig);
             if !sig.inputs.is_empty() {
                 for &parameter_type in &sig.inputs {
-                    push_unique_type_name(cx, parameter_type, output);
+                    push_unique_type_name(tcx, parameter_type, output);
                     output.push_str(", ");
                 }
                 output.pop();
@@ -1343,7 +1339,7 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 ty::FnConverging(result_type) if result_type.is_nil() => {}
                 ty::FnConverging(result_type) => {
                     output.push_str(" -> ");
-                    push_unique_type_name(cx, result_type, output);
+                    push_unique_type_name(tcx, result_type, output);
                 }
                 ty::FnDiverging => {
                     output.push_str(" -> !");
@@ -1351,11 +1347,11 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             }
         },
         ty::TyClosure(def_id, ref closure_substs) => {
-            push_item_name(cx, def_id, output);
+            push_item_name(tcx, def_id, output);
             output.push_str("{");
             output.push_str(&format!("{}:{}", def_id.krate, def_id.index.as_usize()));
             output.push_str("}");
-            push_type_params(cx, &closure_substs.func_substs.types, &[], output);
+            push_type_params(tcx, &closure_substs.func_substs.types, &[], output);
         }
         ty::TyError |
         ty::TyInfer(_) |
@@ -1367,17 +1363,17 @@ pub fn push_unique_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     }
 }
 
-fn push_item_name(ccx: &CrateContext,
+fn push_item_name(tcx: &TyCtxt,
                   def_id: DefId,
                   output: &mut String) {
-    let def_path = ccx.tcx().def_path(def_id);
+    let def_path = tcx.def_path(def_id);
 
     // some_crate::
-    output.push_str(&ccx.tcx().crate_name(def_path.krate));
+    output.push_str(&tcx.crate_name(def_path.krate));
     output.push_str("::");
 
     // foo::bar::ItemName::
-    for part in ccx.tcx().def_path(def_id).data {
+    for part in tcx.def_path(def_id).data {
         output.push_str(&format!("{}[{}]::",
                         part.data.as_interned_str(),
                         part.disambiguator));
@@ -1388,10 +1384,10 @@ fn push_item_name(ccx: &CrateContext,
     output.pop();
 }
 
-fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
-                              types: &'tcx subst::VecPerParamSpace<Ty<'tcx>>,
-                              projections: &[ty::PolyProjectionPredicate<'tcx>],
-                              output: &mut String) {
+fn push_type_params<'tcx>(tcx: &TyCtxt<'tcx>,
+                          types: &'tcx subst::VecPerParamSpace<Ty<'tcx>>,
+                          projections: &[ty::PolyProjectionPredicate<'tcx>],
+                          output: &mut String) {
     if types.is_empty() && projections.is_empty() {
         return;
     }
@@ -1399,7 +1395,7 @@ fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     output.push('<');
 
     for &type_parameter in types {
-        push_unique_type_name(cx, type_parameter, output);
+        push_unique_type_name(tcx, type_parameter, output);
         output.push_str(", ");
     }
 
@@ -1408,7 +1404,7 @@ fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         let name = token::get_ident_interner().get(projection.projection_ty.item_name);
         output.push_str(&name[..]);
         output.push_str("=");
-        push_unique_type_name(cx, projection.ty, output);
+        push_unique_type_name(tcx, projection.ty, output);
         output.push_str(", ");
     }
 
@@ -1418,24 +1414,24 @@ fn push_type_params<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
     output.push('>');
 }
 
-fn push_instance_as_string<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                     instance: Instance<'tcx>,
-                                     output: &mut String) {
-    push_item_name(ccx, instance.def, output);
-    push_type_params(ccx, &instance.substs.types, &[], output);
+fn push_instance_as_string<'tcx>(tcx: &TyCtxt<'tcx>,
+                                 instance: Instance<'tcx>,
+                                 output: &mut String) {
+    push_item_name(tcx, instance.def, output);
+    push_type_params(tcx, &instance.substs.types, &[], output);
 }
 
-pub fn def_id_to_string(ccx: &CrateContext, def_id: DefId) -> String {
+pub fn def_id_to_string(tcx: &TyCtxt, def_id: DefId) -> String {
     let mut output = String::new();
-    push_item_name(ccx, def_id, &mut output);
+    push_item_name(tcx, def_id, &mut output);
     output
 }
 
-fn type_to_string<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                            ty: ty::Ty<'tcx>)
-                            -> String {
+fn type_to_string<'tcx>(tcx: &TyCtxt<'tcx>,
+                        ty: ty::Ty<'tcx>)
+                        -> String {
     let mut output = String::new();
-    push_unique_type_name(ccx, ty, &mut output);
+    push_unique_type_name(tcx, ty, &mut output);
     output
 }
 
@@ -1492,8 +1488,8 @@ impl<'tcx> TransItem<'tcx> {
         }
     }
 
-    pub fn to_string<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> String {
-        let hir_map = &ccx.tcx().map;
+    pub fn to_string(&self, tcx: &TyCtxt<'tcx>) -> String {
+        let hir_map = &tcx.map;
 
         return match *self {
             TransItem::DropGlue(dg) => {
@@ -1502,26 +1498,26 @@ impl<'tcx> TransItem<'tcx> {
                     DropGlueKind::Ty(_) => s.push_str("drop-glue "),
                     DropGlueKind::TyContents(_) => s.push_str("drop-glue-contents "),
                 };
-                push_unique_type_name(ccx, dg.ty(), &mut s);
+                push_unique_type_name(tcx, dg.ty(), &mut s);
                 s
             }
             TransItem::Fn(instance) => {
-                to_string_internal(ccx, "fn ", instance)
+                to_string_internal(tcx, "fn ", instance)
             },
             TransItem::Static(node_id) => {
                 let def_id = hir_map.local_def_id(node_id);
-                let instance = Instance::mono(ccx.tcx(), def_id);
-                to_string_internal(ccx, "static ", instance)
+                let instance = Instance::mono(tcx, def_id);
+                to_string_internal(tcx, "static ", instance)
             },
         };
 
-        fn to_string_internal<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                        prefix: &str,
-                                        instance: Instance<'tcx>)
-                                        -> String {
+        fn to_string_internal<'tcx>(tcx: &TyCtxt<'tcx>,
+                                    prefix: &str,
+                                    instance: Instance<'tcx>)
+                                    -> String {
             let mut result = String::with_capacity(32);
             result.push_str(prefix);
-            push_instance_as_string(ccx, instance, &mut result);
+            push_instance_as_string(tcx, instance, &mut result);
             result
         }
     }
@@ -1550,15 +1546,15 @@ pub enum TransItemState {
     NotPredictedButGenerated,
 }
 
-pub fn collecting_debug_information(ccx: &CrateContext) -> bool {
+pub fn collecting_debug_information(scx: &SharedCrateContext) -> bool {
     return cfg!(debug_assertions) &&
-           ccx.sess().opts.debugging_opts.print_trans_items.is_some();
+           scx.sess().opts.debugging_opts.print_trans_items.is_some();
 }
 
-pub fn print_collection_results<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
+pub fn print_collection_results<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) {
     use std::hash::{Hash, SipHasher, Hasher};
 
-    if !collecting_debug_information(ccx) {
+    if !collecting_debug_information(scx) {
         return;
     }
 
@@ -1568,14 +1564,14 @@ pub fn print_collection_results<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
         s.finish()
     }
 
-    let trans_items = ccx.translation_items().borrow();
+    let trans_items = scx.translation_items().borrow();
 
     {
         // Check for duplicate item keys
         let mut item_keys = FnvHashMap();
 
         for (item, item_state) in trans_items.iter() {
-            let k = item.to_string(&ccx);
+            let k = item.to_string(scx.tcx());
 
             if item_keys.contains_key(&k) {
                 let prev: (TransItem, TransItemState) = item_keys[&k];
@@ -1603,7 +1599,7 @@ pub fn print_collection_results<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>) {
     let mut generated = FnvHashSet();
 
     for (item, item_state) in trans_items.iter() {
-        let item_key = item.to_string(&ccx);
+        let item_key = item.to_string(scx.tcx());
 
         match *item_state {
             TransItemState::PredictedAndGenerated => {
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index 2b7345453d7..dc1928a5e07 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -20,6 +20,7 @@ use rustc::cfg;
 use rustc::hir::def::Def;
 use rustc::hir::def_id::DefId;
 use rustc::infer;
+use rustc::util::common::MemoizationMap;
 use middle::lang_items::LangItem;
 use rustc::ty::subst::Substs;
 use abi::{Abi, FnType};
@@ -54,7 +55,7 @@ use syntax::codemap::{DUMMY_SP, Span};
 use syntax::parse::token::InternedString;
 use syntax::parse::token;
 
-pub use context::CrateContext;
+pub use context::{CrateContext, SharedCrateContext};
 
 /// Is the type's representation size known at compile time?
 pub fn type_is_sized<'tcx>(tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
@@ -1049,92 +1050,86 @@ pub fn expr_ty_adjusted<'blk, 'tcx>(bcx: &BlockS<'blk, 'tcx>, ex: &hir::Expr) ->
 /// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we
 /// do not (necessarily) resolve all nested obligations on the impl. Note that type check should
 /// guarantee to us that all nested obligations *could be* resolved if we wanted to.
-pub fn fulfill_obligation<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+pub fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                                     span: Span,
                                     trait_ref: ty::PolyTraitRef<'tcx>)
                                     -> traits::Vtable<'tcx, ()>
 {
-    let tcx = ccx.tcx();
+    let tcx = scx.tcx();
 
     // Remove any references to regions; this helps improve caching.
     let trait_ref = tcx.erase_regions(&trait_ref);
 
-    // First check the cache.
-    match ccx.trait_cache().borrow().get(&trait_ref) {
-        Some(vtable) => {
-            info!("Cache hit: {:?}", trait_ref);
-            return (*vtable).clone();
-        }
-        None => { }
-    }
-
-    debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}",
-           trait_ref, trait_ref.def_id());
-
-
-    // Do the initial selection for the obligation. This yields the
-    // shallow result we are looking for -- that is, what specific impl.
-    let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any);
-    let mut selcx = SelectionContext::new(&infcx);
-
-    let obligation =
-        traits::Obligation::new(traits::ObligationCause::misc(span, ast::DUMMY_NODE_ID),
-                                trait_ref.to_poly_trait_predicate());
-    let selection = match selcx.select(&obligation) {
-        Ok(Some(selection)) => selection,
-        Ok(None) => {
-            // Ambiguity can happen when monomorphizing during trans
-            // expands to some humongo type that never occurred
-            // statically -- this humongo type can then overflow,
-            // leading to an ambiguous result. So report this as an
-            // overflow bug, since I believe this is the only case
-            // where ambiguity can result.
-            debug!("Encountered ambiguity selecting `{:?}` during trans, \
-                    presuming due to overflow",
-                   trait_ref);
-            ccx.sess().span_fatal(
-                span,
-                "reached the recursion limit during monomorphization (selection ambiguity)");
-        }
-        Err(e) => {
-            span_bug!(
-                span,
-                "Encountered error `{:?}` selecting `{:?}` during trans",
-                e,
-                trait_ref)
-        }
-    };
-
-    // Currently, we use a fulfillment context to completely resolve
-    // all nested obligations. This is because they can inform the
-    // inference of the impl's type parameters.
-    let mut fulfill_cx = traits::FulfillmentContext::new();
-    let vtable = selection.map(|predicate| {
-        fulfill_cx.register_predicate_obligation(&infcx, predicate);
-    });
-    let vtable = infer::drain_fulfillment_cx_or_panic(
-        span, &infcx, &mut fulfill_cx, &vtable
-    );
+    scx.trait_cache().memoize(trait_ref, || {
+        debug!("trans fulfill_obligation: trait_ref={:?} def_id={:?}",
+               trait_ref, trait_ref.def_id());
+
+        // Do the initial selection for the obligation. This yields the
+        // shallow result we are looking for -- that is, what specific impl.
+        let infcx = infer::normalizing_infer_ctxt(tcx,
+                                                  &tcx.tables,
+                                                  ProjectionMode::Any);
+        let mut selcx = SelectionContext::new(&infcx);
+
+        let obligation_cause = traits::ObligationCause::misc(span,
+                                                             ast::DUMMY_NODE_ID);
+        let obligation = traits::Obligation::new(obligation_cause,
+                                                 trait_ref.to_poly_trait_predicate());
+
+        let selection = match selcx.select(&obligation) {
+            Ok(Some(selection)) => selection,
+            Ok(None) => {
+                // Ambiguity can happen when monomorphizing during trans
+                // expands to some humongo type that never occurred
+                // statically -- this humongo type can then overflow,
+                // leading to an ambiguous result. So report this as an
+                // overflow bug, since I believe this is the only case
+                // where ambiguity can result.
+                debug!("Encountered ambiguity selecting `{:?}` during trans, \
+                        presuming due to overflow",
+                       trait_ref);
+                tcx.sess.span_fatal(
+                    span,
+                    "reached the recursion limit during monomorphization \
+                     (selection ambiguity)");
+            }
+            Err(e) => {
+                span_bug!(
+                    span,
+                    "Encountered error `{:?}` selecting `{:?}` during trans",
+                    e,
+                    trait_ref)
+            }
+        };
 
-    info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
+        // Currently, we use a fulfillment context to completely resolve
+        // all nested obligations. This is because they can inform the
+        // inference of the impl's type parameters.
+        let mut fulfill_cx = traits::FulfillmentContext::new();
+        let vtable = selection.map(|predicate| {
+            fulfill_cx.register_predicate_obligation(&infcx, predicate);
+        });
+        let vtable = infer::drain_fulfillment_cx_or_panic(
+            span, &infcx, &mut fulfill_cx, &vtable
+        );
 
-    ccx.trait_cache().borrow_mut().insert(trait_ref, vtable.clone());
+        info!("Cache miss: {:?} => {:?}", trait_ref, vtable);
 
-    vtable
+        vtable
+    })
 }
 
 /// Normalizes the predicates and checks whether they hold.  If this
 /// returns false, then either normalize encountered an error or one
 /// of the predicates did not hold. Used when creating vtables to
 /// check for unsatisfiable methods.
-pub fn normalize_and_test_predicates<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                               predicates: Vec<ty::Predicate<'tcx>>)
-                                               -> bool
+pub fn normalize_and_test_predicates<'tcx>(tcx: &TyCtxt<'tcx>,
+                                           predicates: Vec<ty::Predicate<'tcx>>)
+                                           -> bool
 {
     debug!("normalize_and_test_predicates(predicates={:?})",
            predicates);
 
-    let tcx = ccx.tcx();
     let infcx = infer::normalizing_infer_ctxt(tcx, &tcx.tables, ProjectionMode::Any);
     let mut selcx = SelectionContext::new(&infcx);
     let mut fulfill_cx = traits::FulfillmentContext::new();
diff --git a/src/librustc_trans/consts.rs b/src/librustc_trans/consts.rs
index 09d38e8946b..2811148abd6 100644
--- a/src/librustc_trans/consts.rs
+++ b/src/librustc_trans/consts.rs
@@ -1133,7 +1133,7 @@ pub fn trans_static(ccx: &CrateContext,
                     attrs: &[ast::Attribute])
                     -> Result<ValueRef, ConstEvalErr> {
 
-    if collector::collecting_debug_information(ccx) {
+    if collector::collecting_debug_information(ccx.shared()) {
         ccx.record_translation_item_as_generated(TransItem::Static(id));
     }
 
diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs
index 2ee880fa3d8..24095929f4f 100644
--- a/src/librustc_trans/context.rs
+++ b/src/librustc_trans/context.rs
@@ -28,6 +28,7 @@ use mir::CachedMir;
 use monomorphize::Instance;
 
 use collector::{TransItem, TransItemState};
+use partitioning::CodegenUnit;
 use type_::{Type, TypeNames};
 use rustc::ty::subst::{Substs, VecPerParamSpace};
 use rustc::ty::{self, Ty, TyCtxt};
@@ -64,8 +65,6 @@ pub struct Stats {
 /// crate, so it must not contain references to any LLVM data structures
 /// (aside from metadata-related ones).
 pub struct SharedCrateContext<'a, 'tcx: 'a> {
-    local_ccxs: Vec<LocalCrateContext<'tcx>>,
-
     metadata_llmod: ModuleRef,
     metadata_llcx: ContextRef,
 
@@ -86,6 +85,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
     use_dll_storage_attrs: bool,
 
     translation_items: RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>>,
+    trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
 }
 
 /// The local portion of a `CrateContext`.  There is one `LocalCrateContext`
@@ -95,7 +95,8 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> {
 pub struct LocalCrateContext<'tcx> {
     llmod: ModuleRef,
     llcx: ContextRef,
-    tn: TypeNames,
+    tn: TypeNames, // FIXME: This seems to be largely unused.
+    codegen_unit: CodegenUnit<'tcx>,
     needs_unwind_cleanup_cache: RefCell<FnvHashMap<Ty<'tcx>, bool>>,
     fn_pointer_shims: RefCell<FnvHashMap<Ty<'tcx>, ValueRef>>,
     drop_glues: RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>>,
@@ -171,8 +172,6 @@ pub struct LocalCrateContext<'tcx> {
 
     /// Depth of the current type-of computation - used to bail out
     type_of_depth: Cell<usize>,
-
-    trait_cache: RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>>,
 }
 
 // Implement DepTrackingMapConfig for `trait_cache`
@@ -184,23 +183,66 @@ impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> {
     type Key = ty::PolyTraitRef<'tcx>;
     type Value = traits::Vtable<'tcx, ()>;
     fn to_dep_node(key: &ty::PolyTraitRef<'tcx>) -> DepNode<DefId> {
-        ty::tls::with(|tcx| {
-            let lifted_key = tcx.lift(key).unwrap();
-            lifted_key.to_poly_trait_predicate().dep_node()
-        })
+        key.to_poly_trait_predicate().dep_node()
+    }
+}
+
+/// This list owns a number of LocalCrateContexts and binds them to their common
+/// SharedCrateContext. This type just exists as a convenience, something to
+/// pass around all LocalCrateContexts with and get an iterator over them.
+pub struct CrateContextList<'a, 'tcx: 'a> {
+    shared: &'a SharedCrateContext<'a, 'tcx>,
+    local_ccxs: Vec<LocalCrateContext<'tcx>>,
+}
+
+impl<'a, 'tcx: 'a> CrateContextList<'a, 'tcx> {
+
+    pub fn new(shared_ccx: &'a SharedCrateContext<'a, 'tcx>,
+               codegen_units: Vec<CodegenUnit<'tcx>>)
+               -> CrateContextList<'a, 'tcx> {
+        CrateContextList {
+            shared: shared_ccx,
+            local_ccxs: codegen_units.into_iter().map(|codegen_unit| {
+                LocalCrateContext::new(shared_ccx, codegen_unit)
+            }).collect()
+        }
+    }
+
+    pub fn iter<'b>(&'b self) -> CrateContextIterator<'b, 'tcx> {
+        CrateContextIterator {
+            shared: self.shared,
+            index: 0,
+            local_ccxs: &self.local_ccxs[..]
+        }
+    }
+
+    pub fn get_ccx<'b>(&'b self, index: usize) -> CrateContext<'b, 'tcx> {
+        CrateContext {
+            shared: self.shared,
+            index: index,
+            local_ccxs: &self.local_ccxs[..],
+        }
+    }
+
+    pub fn shared(&self) -> &'a SharedCrateContext<'a, 'tcx> {
+        self.shared
     }
 }
 
+/// A CrateContext value binds together one LocalCrateContext with the
+/// SharedCrateContext. It exists as a convenience wrapper, so we don't have to
+/// pass around (SharedCrateContext, LocalCrateContext) tuples all over trans.
 pub struct CrateContext<'a, 'tcx: 'a> {
     shared: &'a SharedCrateContext<'a, 'tcx>,
-    local: &'a LocalCrateContext<'tcx>,
-    /// The index of `local` in `shared.local_ccxs`.  This is used in
+    local_ccxs: &'a [LocalCrateContext<'tcx>],
+    /// The index of `local` in `local_ccxs`.  This is used in
     /// `maybe_iter(true)` to identify the original `LocalCrateContext`.
     index: usize,
 }
 
 pub struct CrateContextIterator<'a, 'tcx: 'a> {
     shared: &'a SharedCrateContext<'a, 'tcx>,
+    local_ccxs: &'a [LocalCrateContext<'tcx>],
     index: usize,
 }
 
@@ -208,7 +250,7 @@ impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> {
     type Item = CrateContext<'a, 'tcx>;
 
     fn next(&mut self) -> Option<CrateContext<'a, 'tcx>> {
-        if self.index >= self.shared.local_ccxs.len() {
+        if self.index >= self.local_ccxs.len() {
             return None;
         }
 
@@ -217,8 +259,8 @@ impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> {
 
         Some(CrateContext {
             shared: self.shared,
-            local: &self.shared.local_ccxs[index],
             index: index,
+            local_ccxs: self.local_ccxs,
         })
     }
 }
@@ -226,6 +268,7 @@ impl<'a, 'tcx> Iterator for CrateContextIterator<'a,'tcx> {
 /// The iterator produced by `CrateContext::maybe_iter`.
 pub struct CrateContextMaybeIterator<'a, 'tcx: 'a> {
     shared: &'a SharedCrateContext<'a, 'tcx>,
+    local_ccxs: &'a [LocalCrateContext<'tcx>],
     index: usize,
     single: bool,
     origin: usize,
@@ -235,20 +278,20 @@ impl<'a, 'tcx> Iterator for CrateContextMaybeIterator<'a, 'tcx> {
     type Item = (CrateContext<'a, 'tcx>, bool);
 
     fn next(&mut self) -> Option<(CrateContext<'a, 'tcx>, bool)> {
-        if self.index >= self.shared.local_ccxs.len() {
+        if self.index >= self.local_ccxs.len() {
             return None;
         }
 
         let index = self.index;
         self.index += 1;
         if self.single {
-            self.index = self.shared.local_ccxs.len();
+            self.index = self.local_ccxs.len();
         }
 
         let ccx = CrateContext {
             shared: self.shared,
-            local: &self.shared.local_ccxs[index],
             index: index,
+            local_ccxs: self.local_ccxs
         };
         Some((ccx, index == self.origin))
     }
@@ -288,9 +331,7 @@ unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextR
 }
 
 impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
-    pub fn new(crate_name: &str,
-               local_count: usize,
-               tcx: &'b TyCtxt<'tcx>,
+    pub fn new(tcx: &'b TyCtxt<'tcx>,
                mir_map: &'b MirMap<'tcx>,
                export_map: ExportMap,
                symbol_hasher: Sha256,
@@ -348,8 +389,7 @@ 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 mut shared_ccx = SharedCrateContext {
-            local_ccxs: Vec::with_capacity(local_count),
+        SharedCrateContext {
             metadata_llmod: metadata_llmod,
             metadata_llcx: metadata_llcx,
             export_map: export_map,
@@ -378,55 +418,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
             available_drop_glues: RefCell::new(FnvHashMap()),
             use_dll_storage_attrs: use_dll_storage_attrs,
             translation_items: RefCell::new(FnvHashMap()),
-        };
-
-        for i in 0..local_count {
-            // Append ".rs" to crate name as LLVM module identifier.
-            //
-            // LLVM code generator emits a ".file filename" directive
-            // for ELF backends. Value of the "filename" is set as the
-            // LLVM module identifier.  Due to a LLVM MC bug[1], LLVM
-            // crashes if the module identifier is same as other symbols
-            // such as a function name in the module.
-            // 1. http://llvm.org/bugs/show_bug.cgi?id=11479
-            let llmod_id = format!("{}.{}.rs", crate_name, i);
-            let local_ccx = LocalCrateContext::new(&shared_ccx, &llmod_id[..]);
-            shared_ccx.local_ccxs.push(local_ccx);
-        }
-
-        shared_ccx
-    }
-
-    pub fn iter<'a>(&'a self) -> CrateContextIterator<'a, 'tcx> {
-        CrateContextIterator {
-            shared: self,
-            index: 0,
+            trait_cache: RefCell::new(DepTrackingMap::new(tcx.dep_graph.clone())),
         }
     }
 
-    pub fn get_ccx<'a>(&'a self, index: usize) -> CrateContext<'a, 'tcx> {
-        CrateContext {
-            shared: self,
-            local: &self.local_ccxs[index],
-            index: index,
-        }
-    }
-
-    fn get_smallest_ccx<'a>(&'a self) -> CrateContext<'a, 'tcx> {
-        let (local_ccx, index) =
-            self.local_ccxs
-                .iter()
-                .zip(0..self.local_ccxs.len())
-                .min_by_key(|&(local_ccx, _idx)| local_ccx.n_llvm_insns.get())
-                .unwrap();
-        CrateContext {
-            shared: self,
-            local: local_ccx,
-            index: index,
-        }
-    }
-
-
     pub fn metadata_llmod(&self) -> ModuleRef {
         self.metadata_llmod
     }
@@ -447,6 +442,10 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
         &self.item_symbols
     }
 
+    pub fn trait_cache(&self) -> &RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>> {
+        &self.trait_cache
+    }
+
     pub fn link_meta<'a>(&'a self) -> &'a LinkMeta {
         &self.link_meta
     }
@@ -466,14 +465,47 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> {
     pub fn use_dll_storage_attrs(&self) -> bool {
         self.use_dll_storage_attrs
     }
+
+    pub fn get_mir(&self, def_id: DefId) -> Option<CachedMir<'b, 'tcx>> {
+        if def_id.is_local() {
+            let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
+            self.mir_map.map.get(&node_id).map(CachedMir::Ref)
+        } else {
+            if let Some(mir) = self.mir_cache.borrow().get(&def_id).cloned() {
+                return Some(CachedMir::Owned(mir));
+            }
+
+            let mir = self.sess().cstore.maybe_get_item_mir(self.tcx, def_id);
+            let cached = mir.map(Rc::new);
+            if let Some(ref mir) = cached {
+                self.mir_cache.borrow_mut().insert(def_id, mir.clone());
+            }
+            cached.map(CachedMir::Owned)
+        }
+    }
+
+    pub fn translation_items(&self) -> &RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>> {
+        &self.translation_items
+    }
 }
 
 impl<'tcx> LocalCrateContext<'tcx> {
     fn new<'a>(shared: &SharedCrateContext<'a, 'tcx>,
-           name: &str)
+               codegen_unit: CodegenUnit<'tcx>)
            -> LocalCrateContext<'tcx> {
         unsafe {
-            let (llcx, llmod) = create_context_and_module(&shared.tcx.sess, name);
+            // Append ".rs" to LLVM module identifier.
+            //
+            // LLVM code generator emits a ".file filename" directive
+            // for ELF backends. Value of the "filename" is set as the
+            // LLVM module identifier.  Due to a LLVM MC bug[1], LLVM
+            // crashes if the module identifier is same as other symbols
+            // such as a function name in the module.
+            // 1. http://llvm.org/bugs/show_bug.cgi?id=11479
+            let llmod_id = format!("{}.rs", codegen_unit.name);
+
+            let (llcx, llmod) = create_context_and_module(&shared.tcx.sess,
+                                                          &llmod_id[..]);
 
             let dbg_cx = if shared.tcx.sess.opts.debuginfo != NoDebugInfo {
                 Some(debuginfo::CrateDebugContext::new(llmod))
@@ -481,9 +513,10 @@ impl<'tcx> LocalCrateContext<'tcx> {
                 None
             };
 
-            let mut local_ccx = LocalCrateContext {
+            let local_ccx = LocalCrateContext {
                 llmod: llmod,
                 llcx: llcx,
+                codegen_unit: codegen_unit,
                 tn: TypeNames::new(),
                 needs_unwind_cleanup_cache: RefCell::new(FnvHashMap()),
                 fn_pointer_shims: RefCell::new(FnvHashMap()),
@@ -517,26 +550,30 @@ impl<'tcx> LocalCrateContext<'tcx> {
                 intrinsics: RefCell::new(FnvHashMap()),
                 n_llvm_insns: Cell::new(0),
                 type_of_depth: Cell::new(0),
-                trait_cache: RefCell::new(DepTrackingMap::new(shared.tcx
-                                                                    .dep_graph
-                                                                    .clone())),
             };
 
-            local_ccx.int_type = Type::int(&local_ccx.dummy_ccx(shared));
-            local_ccx.opaque_vec_type = Type::opaque_vec(&local_ccx.dummy_ccx(shared));
-
-            // Done mutating local_ccx directly.  (The rest of the
-            // initialization goes through RefCell.)
-            {
-                let ccx = local_ccx.dummy_ccx(shared);
+            let (int_type, opaque_vec_type, str_slice_ty, mut local_ccx) = {
+                // Do a little dance to create a dummy CrateContext, so we can
+                // create some things in the LLVM module of this codegen unit
+                let mut local_ccxs = vec![local_ccx];
+                let (int_type, opaque_vec_type, str_slice_ty) = {
+                    let dummy_ccx = LocalCrateContext::dummy_ccx(shared,
+                                                                 local_ccxs.as_mut_slice());
+                    let mut str_slice_ty = Type::named_struct(&dummy_ccx, "str_slice");
+                    str_slice_ty.set_struct_body(&[Type::i8p(&dummy_ccx),
+                                                   Type::int(&dummy_ccx)],
+                                                 false);
+                    (Type::int(&dummy_ccx), Type::opaque_vec(&dummy_ccx), str_slice_ty)
+                };
+                (int_type, opaque_vec_type, str_slice_ty, local_ccxs.pop().unwrap())
+            };
 
-                let mut str_slice_ty = Type::named_struct(&ccx, "str_slice");
-                str_slice_ty.set_struct_body(&[Type::i8p(&ccx), ccx.int_type()], false);
-                ccx.tn().associate_type("str_slice", &str_slice_ty);
+            local_ccx.int_type = int_type;
+            local_ccx.opaque_vec_type = opaque_vec_type;
+            local_ccx.tn.associate_type("str_slice", &str_slice_ty);
 
-                if ccx.sess().count_llvm_insns() {
-                    base::init_insn_ctxt()
-                }
+            if shared.tcx.sess.count_llvm_insns() {
+                base::init_insn_ctxt()
             }
 
             local_ccx
@@ -545,18 +582,19 @@ impl<'tcx> LocalCrateContext<'tcx> {
 
     /// Create a dummy `CrateContext` from `self` and  the provided
     /// `SharedCrateContext`.  This is somewhat dangerous because `self` may
-    /// not actually be an element of `shared.local_ccxs`, which can cause some
-    /// operations to panic unexpectedly.
+    /// not be fully initialized.
     ///
     /// This is used in the `LocalCrateContext` constructor to allow calling
     /// functions that expect a complete `CrateContext`, even before the local
     /// portion is fully initialized and attached to the `SharedCrateContext`.
-    fn dummy_ccx<'a>(&'a self, shared: &'a SharedCrateContext<'a, 'tcx>)
+    fn dummy_ccx<'a>(shared: &'a SharedCrateContext<'a, 'tcx>,
+                     local_ccxs: &'a [LocalCrateContext<'tcx>])
                      -> CrateContext<'a, 'tcx> {
+        assert!(local_ccxs.len() == 1);
         CrateContext {
             shared: shared,
-            local: self,
-            index: !0 as usize,
+            index: 0,
+            local_ccxs: local_ccxs
         }
     }
 }
@@ -567,13 +605,23 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     }
 
     pub fn local(&self) -> &'b LocalCrateContext<'tcx> {
-        self.local
+        &self.local_ccxs[self.index]
     }
 
     /// Get a (possibly) different `CrateContext` from the same
     /// `SharedCrateContext`.
-    pub fn rotate(&self) -> CrateContext<'b, 'tcx> {
-        self.shared.get_smallest_ccx()
+    pub fn rotate(&'b self) -> CrateContext<'b, 'tcx> {
+        let (_, index) =
+            self.local_ccxs
+                .iter()
+                .zip(0..self.local_ccxs.len())
+                .min_by_key(|&(local_ccx, _idx)| local_ccx.n_llvm_insns.get())
+                .unwrap();
+        CrateContext {
+            shared: self.shared,
+            index: index,
+            local_ccxs: &self.local_ccxs[..],
+        }
     }
 
     /// Either iterate over only `self`, or iterate over all `CrateContext`s in
@@ -588,10 +636,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
             index: if iter_all { 0 } else { self.index },
             single: !iter_all,
             origin: self.index,
+            local_ccxs: self.local_ccxs,
         }
     }
 
-
     pub fn tcx<'a>(&'a self) -> &'a TyCtxt<'tcx> {
         self.shared.tcx
     }
@@ -605,7 +653,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     }
 
     pub fn raw_builder<'a>(&'a self) -> BuilderRef {
-        self.local.builder.b
+        self.local().builder.b
     }
 
     pub fn get_intrinsic(&self, key: &str) -> ValueRef {
@@ -619,11 +667,15 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     }
 
     pub fn llmod(&self) -> ModuleRef {
-        self.local.llmod
+        self.local().llmod
     }
 
     pub fn llcx(&self) -> ContextRef {
-        self.local.llcx
+        self.local().llcx
+    }
+
+    pub fn codegen_unit(&self) -> &CodegenUnit<'tcx> {
+        &self.local().codegen_unit
     }
 
     pub fn td(&self) -> llvm::TargetDataRef {
@@ -631,7 +683,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     }
 
     pub fn tn<'a>(&'a self) -> &'a TypeNames {
-        &self.local.tn
+        &self.local().tn
     }
 
     pub fn export_map<'a>(&'a self) -> &'a ExportMap {
@@ -651,85 +703,85 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     }
 
     pub fn needs_unwind_cleanup_cache(&self) -> &RefCell<FnvHashMap<Ty<'tcx>, bool>> {
-        &self.local.needs_unwind_cleanup_cache
+        &self.local().needs_unwind_cleanup_cache
     }
 
     pub fn fn_pointer_shims(&self) -> &RefCell<FnvHashMap<Ty<'tcx>, ValueRef>> {
-        &self.local.fn_pointer_shims
+        &self.local().fn_pointer_shims
     }
 
     pub fn drop_glues<'a>(&'a self) -> &'a RefCell<FnvHashMap<DropGlueKind<'tcx>, ValueRef>> {
-        &self.local.drop_glues
+        &self.local().drop_glues
     }
 
     pub fn external<'a>(&'a self) -> &'a RefCell<DefIdMap<Option<ast::NodeId>>> {
-        &self.local.external
+        &self.local().external
     }
 
     pub fn external_srcs<'a>(&'a self) -> &'a RefCell<NodeMap<DefId>> {
-        &self.local.external_srcs
+        &self.local().external_srcs
     }
 
     pub fn instances<'a>(&'a self) -> &'a RefCell<FnvHashMap<Instance<'tcx>, ValueRef>> {
-        &self.local.instances
+        &self.local().instances
     }
 
     pub fn monomorphizing<'a>(&'a self) -> &'a RefCell<DefIdMap<usize>> {
-        &self.local.monomorphizing
+        &self.local().monomorphizing
     }
 
     pub fn vtables<'a>(&'a self) -> &'a RefCell<FnvHashMap<ty::PolyTraitRef<'tcx>, ValueRef>> {
-        &self.local.vtables
+        &self.local().vtables
     }
 
     pub fn const_cstr_cache<'a>(&'a self) -> &'a RefCell<FnvHashMap<InternedString, ValueRef>> {
-        &self.local.const_cstr_cache
+        &self.local().const_cstr_cache
     }
 
     pub fn const_unsized<'a>(&'a self) -> &'a RefCell<FnvHashMap<ValueRef, ValueRef>> {
-        &self.local.const_unsized
+        &self.local().const_unsized
     }
 
     pub fn const_globals<'a>(&'a self) -> &'a RefCell<FnvHashMap<ValueRef, ValueRef>> {
-        &self.local.const_globals
+        &self.local().const_globals
     }
 
     pub fn const_values<'a>(&'a self) -> &'a RefCell<FnvHashMap<(ast::NodeId, &'tcx Substs<'tcx>),
                                                                 ValueRef>> {
-        &self.local.const_values
+        &self.local().const_values
     }
 
     pub fn extern_const_values<'a>(&'a self) -> &'a RefCell<DefIdMap<ValueRef>> {
-        &self.local.extern_const_values
+        &self.local().extern_const_values
     }
 
     pub fn statics<'a>(&'a self) -> &'a RefCell<FnvHashMap<ValueRef, DefId>> {
-        &self.local.statics
+        &self.local().statics
     }
 
     pub fn impl_method_cache<'a>(&'a self)
             -> &'a RefCell<FnvHashMap<(DefId, ast::Name), DefId>> {
-        &self.local.impl_method_cache
+        &self.local().impl_method_cache
     }
 
     pub fn closure_bare_wrapper_cache<'a>(&'a self) -> &'a RefCell<FnvHashMap<ValueRef, ValueRef>> {
-        &self.local.closure_bare_wrapper_cache
+        &self.local().closure_bare_wrapper_cache
     }
 
     pub fn statics_to_rauw<'a>(&'a self) -> &'a RefCell<Vec<(ValueRef, ValueRef)>> {
-        &self.local.statics_to_rauw
+        &self.local().statics_to_rauw
     }
 
     pub fn lltypes<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, Type>> {
-        &self.local.lltypes
+        &self.local().lltypes
     }
 
     pub fn llsizingtypes<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, Type>> {
-        &self.local.llsizingtypes
+        &self.local().llsizingtypes
     }
 
     pub fn adt_reprs<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, Rc<adt::Repr<'tcx>>>> {
-        &self.local.adt_reprs
+        &self.local().adt_reprs
     }
 
     pub fn symbol_hasher<'a>(&'a self) -> &'a RefCell<Sha256> {
@@ -737,7 +789,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     }
 
     pub fn type_hashcodes<'a>(&'a self) -> &'a RefCell<FnvHashMap<Ty<'tcx>, String>> {
-        &self.local.type_hashcodes
+        &self.local().type_hashcodes
     }
 
     pub fn stats<'a>(&'a self) -> &'a Stats {
@@ -753,43 +805,39 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     }
 
     pub fn int_type(&self) -> Type {
-        self.local.int_type
+        self.local().int_type
     }
 
     pub fn opaque_vec_type(&self) -> Type {
-        self.local.opaque_vec_type
+        self.local().opaque_vec_type
     }
 
     pub fn closure_vals<'a>(&'a self) -> &'a RefCell<FnvHashMap<Instance<'tcx>, ValueRef>> {
-        &self.local.closure_vals
+        &self.local().closure_vals
     }
 
     pub fn dbg_cx<'a>(&'a self) -> &'a Option<debuginfo::CrateDebugContext<'tcx>> {
-        &self.local.dbg_cx
+        &self.local().dbg_cx
     }
 
     pub fn eh_personality<'a>(&'a self) -> &'a Cell<Option<ValueRef>> {
-        &self.local.eh_personality
+        &self.local().eh_personality
     }
 
     pub fn eh_unwind_resume<'a>(&'a self) -> &'a Cell<Option<ValueRef>> {
-        &self.local.eh_unwind_resume
+        &self.local().eh_unwind_resume
     }
 
     pub fn rust_try_fn<'a>(&'a self) -> &'a Cell<Option<ValueRef>> {
-        &self.local.rust_try_fn
+        &self.local().rust_try_fn
     }
 
     fn intrinsics<'a>(&'a self) -> &'a RefCell<FnvHashMap<&'static str, ValueRef>> {
-        &self.local.intrinsics
+        &self.local().intrinsics
     }
 
     pub fn count_llvm_insn(&self) {
-        self.local.n_llvm_insns.set(self.local.n_llvm_insns.get() + 1);
-    }
-
-    pub fn trait_cache(&self) -> &RefCell<DepTrackingMap<TraitSelectionCache<'tcx>>> {
-        &self.local.trait_cache
+        self.local().n_llvm_insns.set(self.local().n_llvm_insns.get() + 1);
     }
 
     pub fn obj_size_bound(&self) -> u64 {
@@ -803,14 +851,14 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     }
 
     pub fn enter_type_of(&self, ty: Ty<'tcx>) -> TypeOfDepthLock<'b, 'tcx> {
-        let current_depth = self.local.type_of_depth.get();
+        let current_depth = self.local().type_of_depth.get();
         debug!("enter_type_of({:?}) at depth {:?}", ty, current_depth);
         if current_depth > self.sess().recursion_limit.get() {
             self.sess().fatal(
                 &format!("overflow representing the type `{}`", ty))
         }
-        self.local.type_of_depth.set(current_depth + 1);
-        TypeOfDepthLock(self.local)
+        self.local().type_of_depth.set(current_depth + 1);
+        TypeOfDepthLock(self.local())
     }
 
     pub fn check_overflow(&self) -> bool {
@@ -829,21 +877,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
     }
 
     pub fn get_mir(&self, def_id: DefId) -> Option<CachedMir<'b, 'tcx>> {
-        if def_id.is_local() {
-            let node_id = self.tcx().map.as_local_node_id(def_id).unwrap();
-            self.shared.mir_map.map.get(&node_id).map(CachedMir::Ref)
-        } else {
-            if let Some(mir) = self.shared.mir_cache.borrow().get(&def_id).cloned() {
-                return Some(CachedMir::Owned(mir));
-            }
-
-            let mir = self.sess().cstore.maybe_get_item_mir(self.tcx(), def_id);
-            let cached = mir.map(Rc::new);
-            if let Some(ref mir) = cached {
-                self.shared.mir_cache.borrow_mut().insert(def_id, mir.clone());
-            }
-            cached.map(CachedMir::Owned)
-        }
+        self.shared.get_mir(def_id)
     }
 
     pub fn translation_items(&self) -> &RefCell<FnvHashMap<TransItem<'tcx>, TransItemState>> {
diff --git a/src/librustc_trans/expr.rs b/src/librustc_trans/expr.rs
index cd11ca58689..edb3d167dde 100644
--- a/src/librustc_trans/expr.rs
+++ b/src/librustc_trans/expr.rs
@@ -510,7 +510,9 @@ fn coerce_unsized<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             let source = unpack_datum!(bcx, source.to_ref_datum(bcx));
             assert!(target.kind.is_by_ref());
 
-            let kind = custom_coerce_unsize_info(bcx.ccx(), source.ty, target.ty);
+            let kind = custom_coerce_unsize_info(bcx.ccx().shared(),
+                                                 source.ty,
+                                                 target.ty);
 
             let repr_source = adt::represent_type(bcx.ccx(), source.ty);
             let src_fields = match &*repr_source {
diff --git a/src/librustc_trans/glue.rs b/src/librustc_trans/glue.rs
index 06761a7016a..898ac636c1d 100644
--- a/src/librustc_trans/glue.rs
+++ b/src/librustc_trans/glue.rs
@@ -19,7 +19,7 @@ use llvm;
 use llvm::{ValueRef, get_param};
 use middle::lang_items::ExchangeFreeFnLangItem;
 use rustc::ty::subst::{Substs};
-use rustc::traits;
+use rustc::{infer, traits};
 use rustc::ty::{self, Ty, TyCtxt};
 use abi::{Abi, FnType};
 use adt;
@@ -92,13 +92,12 @@ pub fn type_needs_drop<'tcx>(tcx: &TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
     tcx.type_needs_drop_given_env(ty, &tcx.empty_parameter_environment())
 }
 
-pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                    t: Ty<'tcx>) -> Ty<'tcx> {
-    let tcx = ccx.tcx();
+pub fn get_drop_glue_type<'tcx>(tcx: &TyCtxt<'tcx>,
+                                t: Ty<'tcx>) -> Ty<'tcx> {
     // Even if there is no dtor for t, there might be one deeper down and we
     // might need to pass in the vtable ptr.
     if !type_is_sized(tcx, t) {
-        return ccx.tcx().erase_regions(&t);
+        return tcx.erase_regions(&t);
     }
 
     // FIXME (#22815): note that type_needs_drop conservatively
@@ -116,15 +115,18 @@ pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     match t.sty {
         ty::TyBox(typ) if !type_needs_drop(&tcx, typ)
                          && type_is_sized(tcx, typ) => {
-            let llty = sizing_type_of(ccx, typ);
-            // `Box<ZeroSizeType>` does not allocate.
-            if llsize_of_alloc(ccx, llty) == 0 {
+            let infcx = infer::normalizing_infer_ctxt(tcx,
+                                                      &tcx.tables,
+                                                      traits::ProjectionMode::Any);
+            let layout = t.layout(&infcx).unwrap();
+            if layout.size(&tcx.data_layout).bytes() == 0 {
+                // `Box<ZeroSizeType>` does not allocate.
                 tcx.types.i8
             } else {
-                ccx.tcx().erase_regions(&t)
+                tcx.erase_regions(&t)
             }
         }
-        _ => ccx.tcx().erase_regions(&t)
+        _ => tcx.erase_regions(&t)
     }
 }
 
@@ -154,7 +156,7 @@ pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
             DropGlueKind::Ty(t)
         };
         let glue = get_drop_glue_core(ccx, g);
-        let glue_type = get_drop_glue_type(ccx, t);
+        let glue_type = get_drop_glue_type(ccx.tcx(), t);
         let ptr = if glue_type != t {
             PointerCast(bcx, v, type_of(ccx, glue_type).ptr_to())
         } else {
@@ -231,7 +233,7 @@ impl<'tcx> DropGlueKind<'tcx> {
 fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                 g: DropGlueKind<'tcx>) -> ValueRef {
     debug!("make drop glue for {:?}", g);
-    let g = g.map_ty(|t| get_drop_glue_type(ccx, t));
+    let g = g.map_ty(|t| get_drop_glue_type(ccx.tcx(), t));
     debug!("drop glue type {:?}", g);
     match ccx.drop_glues().borrow().get(&g) {
         Some(&glue) => return glue,
@@ -364,7 +366,7 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         def_id: tcx.lang_items.drop_trait().unwrap(),
         substs: tcx.mk_substs(Substs::empty().with_self_ty(t))
     });
-    let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) {
+    let vtbl = match fulfill_obligation(bcx.ccx().shared(), DUMMY_SP, trait_ref) {
         traits::VtableImpl(data) => data,
         _ => bug!("dtor for {:?} is not an impl???", t)
     };
@@ -487,7 +489,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
 
 fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueKind<'tcx>)
                               -> Block<'blk, 'tcx> {
-    if collector::collecting_debug_information(bcx.ccx()) {
+    if collector::collecting_debug_information(bcx.ccx().shared()) {
         bcx.ccx()
            .record_translation_item_as_generated(TransItem::DropGlue(g));
     }
diff --git a/src/librustc_trans/meth.rs b/src/librustc_trans/meth.rs
index 9e5476ae80d..648a232ef69 100644
--- a/src/librustc_trans/meth.rs
+++ b/src/librustc_trans/meth.rs
@@ -144,7 +144,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
     // Not in the cache. Build it.
     let methods = traits::supertraits(tcx, trait_ref.clone()).flat_map(|trait_ref| {
-        let vtable = fulfill_obligation(ccx, DUMMY_SP, trait_ref.clone());
+        let vtable = fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref.clone());
         match vtable {
             // Should default trait error here?
             traits::VtableDefaultImpl(_) |
@@ -157,7 +157,7 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                     substs,
                     nested: _ }) => {
                 let nullptr = C_null(Type::nil(ccx).ptr_to());
-                get_vtable_methods(ccx, id, substs)
+                get_vtable_methods(tcx, id, substs)
                     .into_iter()
                     .map(|opt_mth| opt_mth.map_or(nullptr, |mth| {
                         Callee::def(ccx, mth.method.def_id, &mth.substs).reify(ccx).val
@@ -215,13 +215,11 @@ pub fn get_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     vtable
 }
 
-pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                                    impl_id: DefId,
-                                    substs: &'tcx subst::Substs<'tcx>)
-                                    -> Vec<Option<ImplMethod<'tcx>>>
+pub fn get_vtable_methods<'tcx>(tcx: &TyCtxt<'tcx>,
+                                impl_id: DefId,
+                                substs: &'tcx subst::Substs<'tcx>)
+                                -> Vec<Option<ImplMethod<'tcx>>>
 {
-    let tcx = ccx.tcx();
-
     debug!("get_vtable_methods(impl_id={:?}, substs={:?}", impl_id, substs);
 
     let trt_id = match tcx.impl_trait_ref(impl_id) {
@@ -287,7 +285,7 @@ pub fn get_vtable_methods<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             // try and trans it, in that case. Issue #23435.
             if mth.is_provided {
                 let predicates = mth.method.predicates.predicates.subst(tcx, &mth.substs);
-                if !normalize_and_test_predicates(ccx, predicates.into_vec()) {
+                if !normalize_and_test_predicates(tcx, predicates.into_vec()) {
                     debug!("get_vtable_methods: predicates do not hold");
                     return None;
                 }
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index e605ef81c58..39bf0da5cf9 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -136,7 +136,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     return;
                 }
                 let drop_fn = glue::get_drop_glue(bcx.ccx(), ty);
-                let drop_ty = glue::get_drop_glue_type(bcx.ccx(), ty);
+                let drop_ty = glue::get_drop_glue_type(bcx.tcx(), ty);
                 let llvalue = if drop_ty != ty {
                     bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx(), drop_ty).ptr_to())
                 } else {
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 93206179837..267d9e9a23a 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -233,7 +233,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
             let trait_id = trait_item.container().id();
             let substs = instance.substs;
             let trait_ref = ty::Binder(substs.to_trait_ref(ccx.tcx(), trait_id));
-            let vtable = common::fulfill_obligation(ccx, DUMMY_SP, trait_ref);
+            let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref);
             if let traits::VtableImpl(vtable_impl) = vtable {
                 let name = ccx.tcx().item_name(instance.def);
                 for ac in ccx.tcx().associated_consts(vtable_impl.impl_def_id) {
diff --git a/src/librustc_trans/partitioning.rs b/src/librustc_trans/partitioning.rs
index 250292ee684..7b21b612097 100644
--- a/src/librustc_trans/partitioning.rs
+++ b/src/librustc_trans/partitioning.rs
@@ -256,10 +256,6 @@ fn place_root_translation_items<'tcx, I>(tcx: &TyCtxt<'tcx>,
 fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<'tcx>,
                              target_cgu_count: usize,
                              crate_name: &str) {
-    if target_cgu_count >= initial_partitioning.codegen_units.len() {
-        return;
-    }
-
     assert!(target_cgu_count >= 1);
     let codegen_units = &mut initial_partitioning.codegen_units;
 
@@ -278,7 +274,22 @@ fn merge_codegen_units<'tcx>(initial_partitioning: &mut PreInliningPartitioning<
     }
 
     for (index, cgu) in codegen_units.iter_mut().enumerate() {
-        cgu.name = token::intern_and_get_ident(&format!("{}.{}", crate_name, index)[..]);
+        cgu.name = numbered_codegen_unit_name(crate_name, index);
+    }
+
+    // If the initial partitioning contained less than target_cgu_count to begin
+    // with, we won't have enough codegen units here, so add a empty units until
+    // we reach the target count
+    while codegen_units.len() < target_cgu_count {
+        let index = codegen_units.len();
+        codegen_units.push(CodegenUnit {
+            name: numbered_codegen_unit_name(crate_name, index),
+            items: FnvHashMap()
+        });
+    }
+
+    fn numbered_codegen_unit_name(crate_name: &str, index: usize) -> InternedString {
+        token::intern_and_get_ident(&format!("{}.{}", crate_name, index)[..])
     }
 }