about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorJames Miller <james@aatch.net>2016-05-14 05:41:42 +1200
committerMichael Woerister <michaelwoerister@posteo.net>2016-07-08 10:42:38 -0400
commit67171069472f57875ac8cf4c94e1a56fa635582a (patch)
tree7d27fc98d1a84e78074f846215760140a6995f11 /src
parent891c2a082fd562744b4495ed7bd0602414e93f2b (diff)
Drive function item translation from collector
Functions and method are declared ahead-of-time, including generic ones.

Closures are not considered trans items anymore, instead they are
translated on demands.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trans/base.rs173
-rw-r--r--src/librustc_trans/closure.rs7
-rw-r--r--src/librustc_trans/collector.rs41
-rw-r--r--src/librustc_trans/inline.rs64
-rw-r--r--src/librustc_trans/monomorphize.rs11
-rw-r--r--src/librustc_trans/trans_item.rs90
6 files changed, 211 insertions, 175 deletions
diff --git a/src/librustc_trans/base.rs b/src/librustc_trans/base.rs
index 40ae5025180..05ae347b534 100644
--- a/src/librustc_trans/base.rs
+++ b/src/librustc_trans/base.rs
@@ -75,6 +75,7 @@ use debuginfo::{self, DebugLoc, ToDebugLoc};
 use declare;
 use expr;
 use glue;
+use inline;
 use machine;
 use machine::{llalign_of_min, llsize_of, llsize_of_real};
 use meth;
@@ -1948,6 +1949,49 @@ pub fn trans_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                   closure::ClosureEnv::NotClosure);
 }
 
+pub fn trans_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, instance: Instance<'tcx>) {
+    let instance = inline::maybe_inline_instance(ccx, instance);
+
+    let fn_node_id = ccx.tcx().map.as_local_node_id(instance.def).unwrap();
+
+    let _s = StatRecorder::new(ccx, ccx.tcx().node_path_str(fn_node_id));
+    debug!("trans_instance(instance={:?})", instance);
+    let _icx = push_ctxt("trans_instance");
+
+    let item = ccx.tcx().map.find(fn_node_id).unwrap();
+
+    let fn_ty = ccx.tcx().lookup_item_type(instance.def).ty;
+    let fn_ty = ccx.tcx().erase_regions(&fn_ty);
+    let fn_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &fn_ty);
+
+    let sig = ccx.tcx().erase_late_bound_regions(fn_ty.fn_sig());
+    let sig = ccx.tcx().normalize_associated_type(&sig);
+    let abi = fn_ty.fn_abi();
+
+    let lldecl = match ccx.instances().borrow().get(&instance) {
+        Some(&val) => val,
+        None => bug!("Instance `{:?}` not already declared", instance)
+    };
+
+    match item {
+        hir_map::NodeItem(&hir::Item {
+            node: hir::ItemFn(ref decl, _, _, _, _, ref body), ..
+        }) |
+        hir_map::NodeTraitItem(&hir::TraitItem {
+            node: hir::MethodTraitItem(
+                hir::MethodSig { ref decl, .. }, Some(ref body)), ..
+        }) |
+        hir_map::NodeImplItem(&hir::ImplItem {
+            node: hir::ImplItemKind::Method(
+                hir::MethodSig { ref decl, .. }, ref body), ..
+        }) => {
+            trans_closure(ccx, decl, body, lldecl, instance,
+                          fn_node_id, &sig, abi, closure::ClosureEnv::NotClosure);
+        }
+        _ => bug!("Instance is a {:?}?", item)
+    }
+}
+
 pub fn trans_named_tuple_constructor<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                                  ctor_ty: Ty<'tcx>,
                                                  disr: Disr,
@@ -2267,70 +2311,23 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
     let _icx = push_ctxt("trans_item");
 
     let tcx = ccx.tcx();
-    let from_external = ccx.external_srcs().borrow().contains_key(&item.id);
-
     match item.node {
-        hir::ItemFn(ref decl, _, _, _, ref generics, ref body) => {
-            if !generics.is_type_parameterized() {
-                let trans_everywhere = attr::requests_inline(&item.attrs);
-                // Ignore `trans_everywhere` for cross-crate inlined items
-                // (`from_external`).  `trans_item` will be called once for each
-                // compilation unit that references the item, so it will still get
-                // translated everywhere it's needed.
-                for (ref ccx, is_origin) in ccx.maybe_iter(!from_external && trans_everywhere) {
-                    let def_id = tcx.map.local_def_id(item.id);
-                    let empty_substs = ccx.empty_substs_for_def_id(def_id);
-                    let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
-                    trans_fn(ccx, &decl, &body, llfn, empty_substs, item.id);
-                    set_link_section(ccx, llfn, &item.attrs);
-                    update_linkage(ccx,
-                                   llfn,
-                                   Some(item.id),
-                                   if is_origin {
-                                       OriginalTranslation
-                                   } else {
-                                       InlinedCopy
-                                   });
-
-                    if is_entry_fn(ccx.sess(), item.id) {
-                        create_entry_wrapper(ccx, item.span, llfn);
-                        // check for the #[rustc_error] annotation, which forces an
-                        // error in trans. This is used to write compile-fail tests
-                        // that actually test that compilation succeeds without
-                        // reporting an error.
-                        if tcx.has_attr(def_id, "rustc_error") {
-                            tcx.sess.span_fatal(item.span, "compilation successful");
-                        }
-                    }
+        hir::ItemFn(_, _, _, _, _, _) => {
+            let def_id = tcx.map.local_def_id(item.id);
+            // check for the #[rustc_error] annotation, which forces an
+            // error in trans. This is used to write compile-fail tests
+            // that actually test that compilation succeeds without
+            // reporting an error.
+            if is_entry_fn(ccx.sess(), item.id) {
+                let empty_substs = ccx.empty_substs_for_def_id(def_id);
+                let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
+                create_entry_wrapper(ccx, item.span, llfn);
+                if tcx.has_attr(def_id, "rustc_error") {
+                    tcx.sess.span_fatal(item.span, "compilation successful");
                 }
             }
-        }
-        hir::ItemImpl(_, _, ref generics, _, _, ref impl_items) => {
-            // Both here and below with generic methods, be sure to recurse and look for
-            // items that we need to translate.
-            if !generics.ty_params.is_empty() {
-                return;
-            }
 
-            for impl_item in impl_items {
-                if let hir::ImplItemKind::Method(ref sig, ref body) = impl_item.node {
-                    if sig.generics.ty_params.is_empty() {
-                        let trans_everywhere = attr::requests_inline(&impl_item.attrs);
-                        for (ref ccx, is_origin) in ccx.maybe_iter(trans_everywhere) {
-                            let def_id = tcx.map.local_def_id(impl_item.id);
-                            let empty_substs = ccx.empty_substs_for_def_id(def_id);
-                            let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
-                            trans_fn(ccx, &sig.decl, body, llfn, empty_substs, impl_item.id);
-                            update_linkage(ccx, llfn, Some(impl_item.id),
-                                if is_origin {
-                                    OriginalTranslation
-                                } else {
-                                    InlinedCopy
-                                });
-                        }
-                    }
-                }
-            }
+            // Function is actually translated in trans_instance
         }
         hir::ItemEnum(ref enum_definition, ref gens) => {
             if gens.ty_params.is_empty() {
@@ -2338,8 +2335,9 @@ pub fn trans_item(ccx: &CrateContext, item: &hir::Item) {
                 enum_variant_size_lint(ccx, enum_definition, item.span, item.id);
             }
         }
+        hir::ItemImpl(..) |
         hir::ItemStatic(..) => {
-            // Don't do anything here. Translation of statics has been moved to
+            // Don't do anything here. Translation has been moved to
             // being "collector-driven".
         }
         _ => {}
@@ -2482,16 +2480,16 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) {
                 let linkage = llvm::LLVMGetLinkage(val);
                 // We only care about external declarations (not definitions)
                 // and available_externally definitions.
-                if !(linkage == llvm::ExternalLinkage as c_uint &&
-                     llvm::LLVMIsDeclaration(val) != 0) &&
-                   !(linkage == llvm::AvailableExternallyLinkage as c_uint) {
-                    continue;
+                let is_available_externally = linkage == llvm::AvailableExternallyLinkage as c_uint;
+                let is_decl = llvm::LLVMIsDeclaration(val) != 0;
+
+                if is_decl || is_available_externally {
+                    let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
+                        .to_bytes()
+                        .to_vec();
+                    declared.insert(name);
                 }
 
-                let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
-                               .to_bytes()
-                               .to_vec();
-                declared.insert(name);
             }
         }
 
@@ -2501,21 +2499,27 @@ fn internalize_symbols(cx: &CrateContextList, reachable: &HashSet<&str>) {
         for ccx in cx.iter() {
             for val in iter_globals(ccx.llmod()).chain(iter_functions(ccx.llmod())) {
                 let linkage = llvm::LLVMGetLinkage(val);
+
+                let is_external = linkage == llvm::ExternalLinkage as c_uint;
+                let is_weak_odr = linkage == llvm::WeakODRLinkage as c_uint;
+                let is_decl = llvm::LLVMIsDeclaration(val) != 0;
+
                 // We only care about external definitions.
-                if !((linkage == llvm::ExternalLinkage as c_uint ||
-                      linkage == llvm::WeakODRLinkage as c_uint) &&
-                     llvm::LLVMIsDeclaration(val) == 0) {
-                    continue;
-                }
+                if (is_external || is_weak_odr) && !is_decl {
+
+                    let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
+                                .to_bytes()
+                                .to_vec();
+
+                    let is_declared = declared.contains(&name);
+                    let reachable = reachable.contains(str::from_utf8(&name).unwrap());
+
+                    if !is_declared && !reachable {
+                        llvm::SetLinkage(val, llvm::InternalLinkage);
+                        llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
+                        llvm::UnsetComdat(val);
+                    }
 
-                let name = CStr::from_ptr(llvm::LLVMGetValueName(val))
-                               .to_bytes()
-                               .to_vec();
-                if !declared.contains(&name) &&
-                   !reachable.contains(str::from_utf8(&name).unwrap()) {
-                    llvm::SetLinkage(val, llvm::InternalLinkage);
-                    llvm::SetDLLStorageClass(val, llvm::DefaultStorageClass);
-                    llvm::UnsetComdat(val);
                 }
             }
         }
@@ -2744,6 +2748,9 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         span_bug!(item.span, "Mismatch between hir::Item type and TransItem type")
                     }
                 }
+                TransItem::Fn(instance) => {
+                    trans_instance(&ccx, instance);
+                }
                 _ => { }
             }
         }
@@ -2980,7 +2987,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>(scx: &SharedCrateContext<'a
         let mut item_keys: Vec<_> = items
             .iter()
             .map(|i| {
-                let mut output = i.to_string(scx.tcx());
+                let mut output = i.to_string(scx);
                 output.push_str(" @@");
                 let mut empty = Vec::new();
                 let mut cgus = item_to_cgus.get_mut(i).unwrap_or(&mut empty);
diff --git a/src/librustc_trans/closure.rs b/src/librustc_trans/closure.rs
index 9196cfce16f..bf9cde9a441 100644
--- a/src/librustc_trans/closure.rs
+++ b/src/librustc_trans/closure.rs
@@ -10,7 +10,7 @@
 
 use arena::TypedArena;
 use back::symbol_names;
-use llvm::{ValueRef, get_param, get_params};
+use llvm::{self, ValueRef, get_param, get_params};
 use rustc::hir::def_id::DefId;
 use abi::{Abi, FnType};
 use adt;
@@ -167,7 +167,7 @@ fn get_or_create_closure_declaration<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             variadic: false
         })
     }));
-    let llfn = declare::define_internal_fn(ccx, &symbol, function_type);
+    let llfn = declare::declare_fn(ccx, &symbol, function_type);
 
     // set an inline hint for all closures
     attributes::inline(llfn, attributes::InlineAttr::Hint);
@@ -211,6 +211,7 @@ pub fn trans_closure_expr<'a, 'tcx>(dest: Dest<'a, 'tcx>,
            id, closure_def_id, closure_substs);
 
     let llfn = get_or_create_closure_declaration(ccx, closure_def_id, closure_substs);
+    llvm::SetLinkage(llfn, llvm::WeakODRLinkage);
 
     // Get the type of this closure. Use the current `param_substs` as
     // the closure substitutions. This makes sense because the closure
@@ -377,7 +378,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
     // Create the by-value helper.
     let function_name =
         symbol_names::internal_name_from_type_and_suffix(ccx, llonce_fn_ty, "once_shim");
-    let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
+    let lloncefn = declare::declare_fn(ccx, &function_name, llonce_fn_ty);
     attributes::set_frame_pointer_elimination(ccx, lloncefn);
 
     let (block_arena, fcx): (TypedArena<_>, FunctionContext);
diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs
index eea6aec3726..8cb9fd23e49 100644
--- a/src/librustc_trans/collector.rs
+++ b/src/librustc_trans/collector.rs
@@ -325,7 +325,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
         // We've been here already, no need to search again.
         return;
     }
-    debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx.tcx()));
+    debug!("BEGIN collect_items_rec({})", starting_point.to_string(scx));
 
     let mut neighbors = Vec::new();
     let recursion_depth_reset;
@@ -396,7 +396,7 @@ fn collect_items_rec<'a, 'tcx: 'a>(scx: &SharedCrateContext<'a, 'tcx>,
         recursion_depths.insert(def_id, depth);
     }
 
-    debug!("END collect_items_rec({})", starting_point.to_string(scx.tcx()));
+    debug!("END collect_items_rec({})", starting_point.to_string(scx));
 }
 
 fn record_inlining_canditates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -456,12 +456,25 @@ 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.scx.tcx(), def_id));
-                let trans_item = create_fn_trans_item(self.scx.tcx(),
-                                                      def_id,
-                                                      substs.func_substs,
-                                                      self.param_substs);
-                self.output.push(trans_item);
+                let mir = errors::expect(self.scx.sess().diagnostic(), self.scx.get_mir(def_id),
+                                         || format!("Could not find MIR for closure: {:?}", def_id));
+
+                let concrete_substs = monomorphize::apply_param_substs(self.scx.tcx(),
+                                                                       self.param_substs,
+                                                                       &substs.func_substs);
+                let concrete_substs = self.scx.tcx().erase_regions(&concrete_substs);
+
+                let mut visitor = MirNeighborCollector {
+                    scx: self.scx,
+                    mir: &mir,
+                    output: self.output,
+                    param_substs: concrete_substs
+                };
+
+                visitor.visit_mir(&mir);
+                for promoted in &mir.promoted {
+                    visitor.visit_mir(promoted);
+                }
             }
             // When doing an cast from a regular pointer to a fat pointer, we
             // have to instantiate all methods of the trait being cast to, so we
@@ -1107,9 +1120,8 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
                                         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 {
+            hir::ItemFn(_, _, _, _, ref generics, _) => {
+                if !generics.is_type_parameterized() {
                     let def_id = self.scx.tcx().map.local_def_id(item.id);
 
                     debug!("RootCollector: ItemFn({})",
@@ -1129,9 +1141,8 @@ impl<'b, 'a, 'v> hir_visit::Visitor<'v> for RootCollector<'b, 'a, 'v> {
         match ii.node {
             hir::ImplItemKind::Method(hir::MethodSig {
                 ref generics,
-                constness,
                 ..
-            }, _) if constness == hir::Constness::NotConst => {
+            }, _) => {
                 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) {
@@ -1260,7 +1271,7 @@ pub fn print_collection_results<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) {
         let mut item_keys = FnvHashMap();
 
         for (item, item_state) in trans_items.iter() {
-            let k = item.to_string(scx.tcx());
+            let k = item.to_string(scx);
 
             if item_keys.contains_key(&k) {
                 let prev: (TransItem, TransItemState) = item_keys[&k];
@@ -1288,7 +1299,7 @@ pub fn print_collection_results<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>) {
     let mut generated = FnvHashSet();
 
     for (item, item_state) in trans_items.iter() {
-        let item_key = item.to_string(scx.tcx());
+        let item_key = item.to_string(scx);
 
         match *item_state {
             TransItemState::PredictedAndGenerated => {
diff --git a/src/librustc_trans/inline.rs b/src/librustc_trans/inline.rs
index af175fbf882..4077b894d62 100644
--- a/src/librustc_trans/inline.rs
+++ b/src/librustc_trans/inline.rs
@@ -8,13 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{AvailableExternallyLinkage, InternalLinkage, SetLinkage};
 use middle::cstore::{FoundAst, InlinedItem};
 use rustc::hir::def_id::DefId;
-use rustc::ty::subst::Substs;
-use base::{push_ctxt, trans_item, trans_fn};
-use callee::Callee;
+use base::push_ctxt;
 use common::*;
+use monomorphize::Instance;
 
 use rustc::dep_graph::DepNode;
 use rustc::hir;
@@ -52,30 +50,6 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option<DefId> {
             ccx.external_srcs().borrow_mut().insert(item.id, fn_id);
 
             ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1);
-            trans_item(ccx, item);
-
-            if let hir::ItemFn(_, _, _, _, ref generics, _) = item.node {
-                // Generics have no symbol, so they can't be given any linkage.
-                if !generics.is_type_parameterized() {
-                    let linkage = if ccx.sess().opts.cg.codegen_units == 1 {
-                        // We could use AvailableExternallyLinkage here,
-                        // but InternalLinkage allows LLVM to optimize more
-                        // aggressively (at the cost of sometimes
-                        // duplicating code).
-                        InternalLinkage
-                    } else {
-                        // With multiple compilation units, duplicated code
-                        // is more of a problem.  Also, `codegen_units > 1`
-                        // means the user is okay with losing some
-                        // performance.
-                        AvailableExternallyLinkage
-                    };
-                    let empty_substs = tcx.mk_substs(Substs::empty());
-                    let def_id = tcx.map.local_def_id(item.id);
-                    let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
-                    SetLinkage(llfn, linkage);
-                }
-            }
 
             item.id
         }
@@ -135,35 +109,12 @@ fn instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> Option<DefId> {
             // don't.
             trait_item.id
         }
-        FoundAst::Found(&InlinedItem::ImplItem(impl_did, ref impl_item)) => {
+        FoundAst::Found(&InlinedItem::ImplItem(_, ref impl_item)) => {
             ccx.external().borrow_mut().insert(fn_id, Some(impl_item.id));
             ccx.external_srcs().borrow_mut().insert(impl_item.id, fn_id);
 
             ccx.stats().n_inlines.set(ccx.stats().n_inlines.get() + 1);
 
-            // Translate monomorphic impl methods immediately.
-            if let hir::ImplItemKind::Method(ref sig, ref body) = impl_item.node {
-                let impl_tpt = tcx.lookup_item_type(impl_did);
-                if impl_tpt.generics.types.is_empty() &&
-                        sig.generics.ty_params.is_empty() {
-                    let def_id = tcx.map.local_def_id(impl_item.id);
-                    let empty_substs = ccx.empty_substs_for_def_id(def_id);
-                    let llfn = Callee::def(ccx, def_id, empty_substs).reify(ccx).val;
-                    trans_fn(ccx,
-                             &sig.decl,
-                             body,
-                             llfn,
-                             empty_substs,
-                             impl_item.id);
-                    // See linkage comments on items.
-                    if ccx.sess().opts.cg.codegen_units == 1 {
-                        SetLinkage(llfn, InternalLinkage);
-                    } else {
-                        SetLinkage(llfn, AvailableExternallyLinkage);
-                    }
-                }
-            }
-
             impl_item.id
         }
     };
@@ -184,3 +135,12 @@ pub fn get_local_instance(ccx: &CrateContext, fn_id: DefId)
 pub fn maybe_instantiate_inline(ccx: &CrateContext, fn_id: DefId) -> DefId {
     get_local_instance(ccx, fn_id).unwrap_or(fn_id)
 }
+
+pub fn maybe_inline_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                                       instance: Instance<'tcx>) -> Instance<'tcx> {
+    let def_id = maybe_instantiate_inline(ccx, instance.def);
+    Instance {
+        def: def_id,
+        substs: instance.substs
+    }
+}
diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs
index ab859b88a85..13d6d432422 100644
--- a/src/librustc_trans/monomorphize.rs
+++ b/src/librustc_trans/monomorphize.rs
@@ -109,15 +109,16 @@ pub fn monomorphic_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
         });
     match map_node {
         hir_map::NodeItem(&hir::Item {
-            ref attrs, node: hir::ItemFn(ref decl, _, _, _, _, ref body), ..
-        }) |
-        hir_map::NodeTraitItem(&hir::TraitItem {
-            ref attrs, node: hir::MethodTraitItem(
-                hir::MethodSig { ref decl, .. }, Some(ref body)), ..
+            ref attrs,
+            node: hir::ItemFn(ref decl, _, _, _, _, ref body), ..
         }) |
         hir_map::NodeImplItem(&hir::ImplItem {
             ref attrs, node: hir::ImplItemKind::Method(
                 hir::MethodSig { ref decl, .. }, ref body), ..
+        }) |
+        hir_map::NodeTraitItem(&hir::TraitItem {
+            ref attrs, node: hir::MethodTraitItem(
+                hir::MethodSig { ref decl, .. }, Some(ref body)), ..
         }) => {
             attributes::from_fn_attrs(ccx, attrs, lldecl);
 
diff --git a/src/librustc_trans/trans_item.rs b/src/librustc_trans/trans_item.rs
index 92fddd7d77d..f3c0ddfaf73 100644
--- a/src/librustc_trans/trans_item.rs
+++ b/src/librustc_trans/trans_item.rs
@@ -14,19 +14,22 @@
 //! item-path. This is used for unit testing the code that generates
 //! paths etc in all kinds of annoying scenarios.
 
+use attributes;
 use base;
-use context::CrateContext;
+use context::{SharedCrateContext, CrateContext};
 use declare;
 use glue::DropGlueKind;
 use llvm;
-use monomorphize::Instance;
+use monomorphize::{self, Instance};
+use inline;
 use rustc::hir;
+use rustc::hir::map as hir_map;
 use rustc::hir::def_id::DefId;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc::ty::subst;
 use std::hash::{Hash, Hasher};
 use syntax::ast::{self, NodeId};
-use syntax::attr;
+use syntax::{attr,errors};
 use syntax::parse::token;
 use type_of;
 
@@ -59,24 +62,27 @@ impl<'tcx> Hash for TransItem<'tcx> {
 }
 
 
-impl<'tcx> TransItem<'tcx> {
+impl<'a, 'tcx> TransItem<'tcx> {
 
-    pub fn predefine<'ccx>(&self,
-                           ccx: &CrateContext<'ccx, 'tcx>,
-                           linkage: llvm::Linkage) {
+    pub fn predefine(&self,
+                     ccx: &CrateContext<'a, 'tcx>,
+                     linkage: llvm::Linkage) {
         match *self {
             TransItem::Static(node_id) => {
                 TransItem::predefine_static(ccx, node_id, linkage);
             }
+            TransItem::Fn(instance) => {
+                TransItem::predefine_fn(ccx, instance, linkage);
+            }
             _ => {
                 // Not yet implemented
             }
         }
     }
 
-    fn predefine_static<'a>(ccx: &CrateContext<'a, 'tcx>,
-                            node_id: ast::NodeId,
-                            linkage: llvm::Linkage) {
+    fn predefine_static(ccx: &CrateContext<'a, 'tcx>,
+                        node_id: ast::NodeId,
+                        linkage: llvm::Linkage) {
         let def_id = ccx.tcx().map.local_def_id(node_id);
         let ty = ccx.tcx().lookup_item_type(def_id).ty;
         let llty = type_of::type_of(ccx, ty);
@@ -101,7 +107,57 @@ impl<'tcx> TransItem<'tcx> {
         }
     }
 
-    pub fn requests_inline<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
+    fn predefine_fn(ccx: &CrateContext<'a, 'tcx>,
+                    instance: Instance<'tcx>,
+                    linkage: llvm::Linkage) {
+        let unit = ccx.codegen_unit();
+        debug!("predefine_fn[cg={}](instance={:?})", &unit.name[..], instance);
+        assert!(!instance.substs.types.needs_infer() &&
+                !instance.substs.types.has_param_types());
+
+        let instance = inline::maybe_inline_instance(ccx, instance);
+
+        let item_ty = ccx.tcx().lookup_item_type(instance.def).ty;
+        let item_ty = ccx.tcx().erase_regions(&item_ty);
+        let mono_ty = monomorphize::apply_param_substs(ccx.tcx(), instance.substs, &item_ty);
+
+        let fn_node_id = ccx.tcx().map.as_local_node_id(instance.def).unwrap();
+        let map_node = errors::expect(
+            ccx.sess().diagnostic(),
+            ccx.tcx().map.find(fn_node_id),
+            || {
+                format!("while instantiating `{}`, couldn't find it in \
+                     the item map (may have attempted to monomorphize \
+                     an item defined in a different crate?)",
+                    instance)
+            });
+
+        match map_node {
+            hir_map::NodeItem(&hir::Item {
+                ref attrs, node: hir::ItemFn(..), ..
+            }) |
+            hir_map::NodeTraitItem(&hir::TraitItem {
+                ref attrs, node: hir::MethodTraitItem(..), ..
+            }) |
+            hir_map::NodeImplItem(&hir::ImplItem {
+                ref attrs, node: hir::ImplItemKind::Method(..), ..
+            }) => {
+                let symbol = instance.symbol_name(ccx.shared());
+                let lldecl = declare::declare_fn(ccx, &symbol, mono_ty);
+
+                attributes::from_fn_attrs(ccx, attrs, lldecl);
+                llvm::SetLinkage(lldecl, linkage);
+                base::set_link_section(ccx, lldecl, attrs);
+
+                ccx.instances().borrow_mut().insert(instance, lldecl);
+            }
+            _ => bug!("Invalid item for TransItem::Fn: `{:?}`", map_node)
+        };
+
+    }
+
+
+    pub fn requests_inline(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> bool {
         match *self {
             TransItem::Fn(ref instance) => {
                 let attributes = tcx.get_attrs(instance.def);
@@ -128,7 +184,7 @@ impl<'tcx> TransItem<'tcx> {
         }
     }
 
-    pub fn explicit_linkage<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<llvm::Linkage> {
+    pub fn explicit_linkage(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Option<llvm::Linkage> {
         let def_id = match *self {
             TransItem::Fn(ref instance) => instance.def,
             TransItem::Static(node_id) => tcx.map.local_def_id(node_id),
@@ -152,7 +208,8 @@ impl<'tcx> TransItem<'tcx> {
         }
     }
 
-    pub fn to_string<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> String {
+    pub fn to_string(&self, scx: &SharedCrateContext<'a, 'tcx>) -> String {
+        let tcx = scx.tcx();
         let hir_map = &tcx.map;
 
         return match *self {
@@ -170,13 +227,12 @@ impl<'tcx> TransItem<'tcx> {
             },
             TransItem::Static(node_id) => {
                 let def_id = hir_map.local_def_id(node_id);
-                let instance = Instance::new(def_id,
-                                             tcx.mk_substs(subst::Substs::empty()));
+                let instance = Instance::mono(scx, def_id);
                 to_string_internal(tcx, "static ", instance)
             },
         };
 
-        fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx,'tcx>,
+        fn to_string_internal<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                                         prefix: &str,
                                         instance: Instance<'tcx>)
                                         -> String {