summary refs log tree commit diff
path: root/src/librustc_codegen_llvm
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-04 08:22:05 +0000
committerbors <bors@rust-lang.org>2019-12-04 08:22:05 +0000
commit5f1d6c44034ac143f7a3e56ae7ea8858dcbb61ca (patch)
tree8ce8e889e897fa1514cece0e96b6f632de2411d5 /src/librustc_codegen_llvm
parenta7fc0939ca4f8f951ce39e85ec5d149c7bb1501c (diff)
parentc2f4c57296f0d929618baed0b0d6eb594abf01eb (diff)
downloadrust-5f1d6c44034ac143f7a3e56ae7ea8858dcbb61ca.tar.gz
rust-5f1d6c44034ac143f7a3e56ae7ea8858dcbb61ca.zip
Auto merge of #65947 - eddyb:fn-abi, r=oli-obk,nagisa
rustc: split FnAbi's into definitions/direct calls ("of_instance") and indirect calls ("of_fn_ptr").

After this PR:
* `InstanceDef::Virtual` is only used for "direct" virtual calls, and shims around those calls use `InstanceDef::ReifyShim` (i.e. for `<dyn Trait as Trait>::f as fn(_)`)
  * this could easily be done for intrinsics as well, to allow their reification, but I didn't do it
* `FnAbi::of_instance` is **always** used for declaring/defining an `fn`, and for direct calls to an `fn`
  * this is great for e.g. https://github.com/rust-lang/rust/pull/65881 (`#[track_caller]`), which can introduce the "caller location" argument into "codegen signatures" by only changing `FnAbi::of_instance`, after this PR
* `FnAbi::of_fn_ptr` is used primarily for indirect calls, i.e. to `fn` pointers
  * *not* virtual calls (which use `FnAbi::of_instance` with `InstanceDef::Virtual`)
  * there's also a couple uses where the `rustc_codegen_llvm` needs to declare (i.e. FFI-import) an LLVM function that has no Rust declaration available at all
    * at least one of them could probably be a "weak lang item" instead

As there are many steps, this PR is best reviewed commit by commit - some of which arguably should be in their own PRs, I may have gotten carried away a bit.

cc @nagisa @rkruppe @oli-obk @anp
Diffstat (limited to 'src/librustc_codegen_llvm')
-rw-r--r--src/librustc_codegen_llvm/abi.rs7
-rw-r--r--src/librustc_codegen_llvm/attributes.rs48
-rw-r--r--src/librustc_codegen_llvm/callee.rs21
-rw-r--r--src/librustc_codegen_llvm/context.rs6
-rw-r--r--src/librustc_codegen_llvm/debuginfo/mod.rs42
-rw-r--r--src/librustc_codegen_llvm/declare.rs38
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs9
-rw-r--r--src/librustc_codegen_llvm/mono_item.rs22
-rw-r--r--src/librustc_codegen_llvm/type_of.rs6
9 files changed, 75 insertions, 124 deletions
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 804a7af41f3..1f3c8e1953e 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -372,7 +372,7 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
 
     fn llvm_cconv(&self) -> llvm::CallConv {
         match self.conv {
-            Conv::C => llvm::CCallConv,
+            Conv::C | Conv::Rust => llvm::CCallConv,
             Conv::AmdGpuKernel => llvm::AmdGpuKernel,
             Conv::ArmAapcs => llvm::ArmAapcsCallConv,
             Conv::Msp430Intr => llvm::Msp430Intr,
@@ -388,6 +388,11 @@ impl<'tcx> FnAbiLlvmExt<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
     }
 
     fn apply_attrs_llfn(&self, cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value) {
+        // FIXME(eddyb) can this also be applied to callsites?
+        if self.ret.layout.abi.is_uninhabited() {
+            llvm::Attribute::NoReturn.apply_llfn(llvm::AttributePlace::Function, llfn);
+        }
+
         let mut i = 0;
         let mut apply = |attrs: &ArgAttributes, ty: Option<&Type>| {
             attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn, ty);
diff --git a/src/librustc_codegen_llvm/attributes.rs b/src/librustc_codegen_llvm/attributes.rs
index 6f4e7d0f0ca..33dc2513de5 100644
--- a/src/librustc_codegen_llvm/attributes.rs
+++ b/src/librustc_codegen_llvm/attributes.rs
@@ -2,19 +2,20 @@
 
 use std::ffi::CString;
 
-use rustc::hir::{CodegenFnAttrFlags, CodegenFnAttrs};
+use rustc::hir::CodegenFnAttrFlags;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::session::Session;
 use rustc::session::config::{Sanitizer, OptLevel};
-use rustc::ty::{self, TyCtxt, PolyFnSig};
+use rustc::ty::{self, TyCtxt, Ty};
 use rustc::ty::layout::HasTyCtxt;
 use rustc::ty::query::Providers;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_target::abi::call::Conv;
 use rustc_target::spec::PanicStrategy;
 use rustc_codegen_ssa::traits::*;
 
-use crate::abi::Abi;
+use crate::abi::FnAbi;
 use crate::attributes;
 use crate::llvm::{self, Attribute};
 use crate::llvm::AttributePlace::Function;
@@ -26,7 +27,7 @@ use crate::value::Value;
 
 /// Mark LLVM function to use provided inline heuristic.
 #[inline]
-pub fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
+fn inline(cx: &CodegenCx<'ll, '_>, val: &'ll Value, inline: InlineAttr) {
     use self::InlineAttr::*;
     match inline {
         Hint   => Attribute::InlineHint.apply_llfn(Function, val),
@@ -58,7 +59,7 @@ fn unwind(val: &'ll Value, can_unwind: bool) {
 
 /// Tell LLVM if this function should be 'naked', i.e., skip the epilogue and prologue.
 #[inline]
-pub fn naked(val: &'ll Value, is_naked: bool) {
+fn naked(val: &'ll Value, is_naked: bool) {
     Attribute::Naked.toggle_llfn(Function, val, is_naked);
 }
 
@@ -72,7 +73,7 @@ pub fn set_frame_pointer_elimination(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value)
 
 /// Tell LLVM what instrument function to insert.
 #[inline]
-pub fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     if cx.sess().instrument_mcount() {
         // Similar to `clang -pg` behavior. Handled by the
         // `post-inline-ee-instrument` LLVM pass.
@@ -88,7 +89,7 @@ pub fn set_instrument_function(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     }
 }
 
-pub fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
+fn set_probestack(cx: &CodegenCx<'ll, '_>, llfn: &'ll Value) {
     // Only use stack probes if the target specification indicates that we
     // should be using stack probes
     if !cx.sess().target.target.options.stack_probes {
@@ -202,11 +203,10 @@ pub(crate) fn default_optimisation_attrs(sess: &Session, llfn: &'ll Value) {
 pub fn from_fn_attrs(
     cx: &CodegenCx<'ll, 'tcx>,
     llfn: &'ll Value,
-    id: Option<DefId>,
-    sig: PolyFnSig<'tcx>,
+    instance: ty::Instance<'tcx>,
+    fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
 ) {
-    let codegen_fn_attrs = id.map(|id| cx.tcx.codegen_fn_attrs(id))
-        .unwrap_or_else(|| CodegenFnAttrs::new());
+    let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
 
     match codegen_fn_attrs.optimize {
         OptimizeAttr::None => {
@@ -224,6 +224,11 @@ pub fn from_fn_attrs(
         }
     }
 
+    // FIXME(eddyb) consolidate these two `inline` calls (and avoid overwrites).
+    if instance.def.is_inline(cx.tcx) {
+        inline(cx, llfn, attributes::InlineAttr::Hint);
+    }
+
     inline(cx, llfn, codegen_fn_attrs.inline);
 
     // The `uwtable` attribute according to LLVM is:
@@ -276,8 +281,7 @@ pub fn from_fn_attrs(
         // Special attribute for allocator functions, which can't unwind.
         false
     } else {
-        let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
-        if sig.abi == Abi::Rust || sig.abi == Abi::RustCall {
+        if fn_abi.conv == Conv::Rust {
             // Any Rust method (or `extern "Rust" fn` or `extern
             // "rust-call" fn`) is explicitly allowed to unwind
             // (unless it has no-unwind attribute, handled above).
@@ -331,16 +335,14 @@ pub fn from_fn_attrs(
     // Note that currently the `wasm-import-module` doesn't do anything, but
     // eventually LLVM 7 should read this and ferry the appropriate import
     // module to the output file.
-    if let Some(id) = id {
-        if cx.tcx.sess.target.target.arch == "wasm32" {
-            if let Some(module) = wasm_import_module(cx.tcx, id) {
-                llvm::AddFunctionAttrStringValue(
-                    llfn,
-                    llvm::AttributePlace::Function,
-                    const_cstr!("wasm-import-module"),
-                    &module,
-                );
-            }
+    if cx.tcx.sess.target.target.arch == "wasm32" {
+        if let Some(module) = wasm_import_module(cx.tcx, instance.def_id()) {
+            llvm::AddFunctionAttrStringValue(
+                llfn,
+                llvm::AttributePlace::Function,
+                const_cstr!("wasm-import-module"),
+                &module,
+            );
         }
     }
 }
diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs
index 08fa23f2a7c..e0db7cae99e 100644
--- a/src/librustc_codegen_llvm/callee.rs
+++ b/src/librustc_codegen_llvm/callee.rs
@@ -4,6 +4,7 @@
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
+use crate::abi::{FnAbi, FnAbiLlvmExt};
 use crate::attributes;
 use crate::llvm;
 use crate::context::CodegenCx;
@@ -11,7 +12,7 @@ use crate::value::Value;
 use rustc_codegen_ssa::traits::*;
 
 use rustc::ty::{TypeFoldable, Instance};
-use rustc::ty::layout::{LayoutOf, HasTyCtxt};
+use rustc::ty::layout::{FnAbiExt, HasTyCtxt};
 
 /// Codegens a reference to a fn/method item, monomorphizing and
 /// inlining as it goes.
@@ -32,19 +33,19 @@ pub fn get_fn(
     assert!(!instance.substs.has_escaping_bound_vars());
     assert!(!instance.substs.has_param_types());
 
-    let sig = instance.fn_sig(cx.tcx());
     if let Some(&llfn) = cx.instances.borrow().get(&instance) {
         return llfn;
     }
 
     let sym = tcx.symbol_name(instance).name.as_str();
-    debug!("get_fn({:?}: {:?}) => {}", instance, sig, sym);
+    debug!("get_fn({:?}: {:?}) => {}", instance, instance.ty(cx.tcx()), sym);
 
-    // Create a fn pointer with the substituted signature.
-    let fn_ptr_ty = tcx.mk_fn_ptr(sig);
-    let llptrty = cx.backend_type(cx.layout_of(fn_ptr_ty));
+    let fn_abi = FnAbi::of_instance(cx, instance, &[]);
 
     let llfn = if let Some(llfn) = cx.get_declared_value(&sym) {
+        // Create a fn pointer with the new signature.
+        let llptrty = fn_abi.ptr_to_llvm_type(cx);
+
         // This is subtle and surprising, but sometimes we have to bitcast
         // the resulting fn pointer.  The reason has to do with external
         // functions.  If you have two crates that both bind the same C
@@ -76,14 +77,10 @@ pub fn get_fn(
             llfn
         }
     } else {
-        let llfn = cx.declare_fn(&sym, sig);
-        assert_eq!(cx.val_ty(llfn), llptrty);
+        let llfn = cx.declare_fn(&sym, &fn_abi);
         debug!("get_fn: not casting pointer!");
 
-        if instance.def.is_inline(tcx) {
-            attributes::inline(cx, llfn, attributes::InlineAttr::Hint);
-        }
-        attributes::from_fn_attrs(cx, llfn, Some(instance.def.def_id()), sig);
+        attributes::from_fn_attrs(cx, llfn, instance, &fn_abi);
 
         let instance_def_id = instance.def_id();
 
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 4a40349cb73..39ea1f6f5dc 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -1,3 +1,4 @@
+use crate::abi::FnAbi;
 use crate::attributes;
 use crate::llvm;
 use crate::llvm_util;
@@ -15,7 +16,7 @@ use rustc::mir::mono::CodegenUnit;
 use rustc::session::config::{self, DebugInfo};
 use rustc::session::Session;
 use rustc::ty::layout::{
-    LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx, HasParamEnv
+    FnAbiExt, LayoutError, LayoutOf, PointeeInfo, Size, TyLayout, VariantIdx, HasParamEnv
 };
 use rustc::ty::{self, Ty, TyCtxt, Instance};
 use rustc::util::nodemap::FxHashMap;
@@ -420,7 +421,8 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             Abi::C
         ));
 
-        let llfn = self.declare_fn("rust_eh_unwind_resume", sig);
+        let fn_abi = FnAbi::of_fn_ptr(self, sig, &[]);
+        let llfn = self.declare_fn("rust_eh_unwind_resume", &fn_abi);
         attributes::apply_target_cpu_attr(self, llfn);
         unwresume.set(Some(llfn));
         llfn
diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs
index 7713fe47004..c2359a2fe6d 100644
--- a/src/librustc_codegen_llvm/debuginfo/mod.rs
+++ b/src/librustc_codegen_llvm/debuginfo/mod.rs
@@ -16,7 +16,7 @@ use rustc::hir::CodegenFnAttrFlags;
 use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE};
 use rustc::ty::subst::{SubstsRef, GenericArgKind};
 
-use crate::abi::Abi;
+use crate::abi::FnAbi;
 use crate::common::CodegenCx;
 use crate::builder::Builder;
 use crate::value::Value;
@@ -280,7 +280,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     fn create_function_debug_context(
         &self,
         instance: Instance<'tcx>,
-        sig: ty::FnSig<'tcx>,
+        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
         llfn: &'ll Value,
         mir: &mir::Body<'_>,
     ) -> Option<FunctionDebugContext<&'ll DIScope>> {
@@ -308,7 +308,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         let file_metadata = file_metadata(self, &loc.file.name, def_id.krate);
 
         let function_type_metadata = unsafe {
-            let fn_signature = get_function_signature(self, sig);
+            let fn_signature = get_function_signature(self, fn_abi);
             llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(self), file_metadata, fn_signature)
         };
 
@@ -338,7 +338,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 
         let mut flags = DIFlags::FlagPrototyped;
 
-        if self.layout_of(sig.output()).abi.is_uninhabited() {
+        if fn_abi.ret.layout.abi.is_uninhabited() {
             flags |= DIFlags::FlagNoReturn;
         }
 
@@ -392,25 +392,20 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 
         fn get_function_signature<'ll, 'tcx>(
             cx: &CodegenCx<'ll, 'tcx>,
-            sig: ty::FnSig<'tcx>,
+            fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
         ) -> &'ll DIArray {
             if cx.sess().opts.debuginfo == DebugInfo::Limited {
                 return create_DIArray(DIB(cx), &[]);
             }
 
-            let mut signature = Vec::with_capacity(sig.inputs().len() + 1);
+            let mut signature = Vec::with_capacity(fn_abi.args.len() + 1);
 
             // Return type -- llvm::DIBuilder wants this at index 0
-            signature.push(match sig.output().kind {
-                ty::Tuple(ref tys) if tys.is_empty() => None,
-                _ => Some(type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP))
-            });
-
-            let inputs = if sig.abi == Abi::RustCall {
-                &sig.inputs()[..sig.inputs().len() - 1]
+            signature.push(if fn_abi.ret.is_ignore() {
+                None
             } else {
-                sig.inputs()
-            };
+                Some(type_metadata(cx, fn_abi.ret.layout.ty, syntax_pos::DUMMY_SP))
+            });
 
             // Arguments types
             if cx.sess().target.target.options.is_like_msvc {
@@ -424,7 +419,8 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                 // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`.
                 // This transformed type is wrong, but these function types are
                 // already inaccurate due to ABI adjustments (see #42800).
-                signature.extend(inputs.iter().map(|&t| {
+                signature.extend(fn_abi.args.iter().map(|arg| {
+                    let t = arg.layout.ty;
                     let t = match t.kind {
                         ty::Array(ct, _)
                             if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => {
@@ -435,21 +431,11 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
                     Some(type_metadata(cx, t, syntax_pos::DUMMY_SP))
                 }));
             } else {
-                signature.extend(inputs.iter().map(|t| {
-                    Some(type_metadata(cx, t, syntax_pos::DUMMY_SP))
+                signature.extend(fn_abi.args.iter().map(|arg| {
+                    Some(type_metadata(cx, arg.layout.ty, syntax_pos::DUMMY_SP))
                 }));
             }
 
-            if sig.abi == Abi::RustCall && !sig.inputs().is_empty() {
-                if let ty::Tuple(args) = sig.inputs()[sig.inputs().len() - 1].kind {
-                    signature.extend(
-                        args.iter().map(|argument_type| {
-                            Some(type_metadata(cx, argument_type.expect_ty(), syntax_pos::DUMMY_SP))
-                        })
-                    );
-                }
-            }
-
             create_DIArray(DIB(cx), &signature[..])
         }
 
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 46cdd2aaa96..8b6fedc87db 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -18,8 +18,7 @@ use crate::attributes;
 use crate::context::CodegenCx;
 use crate::type_::Type;
 use crate::value::Value;
-use rustc::ty::{self, PolyFnSig};
-use rustc::ty::layout::{FnAbiExt, LayoutOf};
+use rustc::ty::Ty;
 use rustc::session::config::Sanitizer;
 use rustc_data_structures::small_c_str::SmallCStr;
 use rustc_codegen_ssa::traits::*;
@@ -94,21 +93,12 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     fn declare_fn(
         &self,
         name: &str,
-        sig: PolyFnSig<'tcx>,
+        fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
     ) -> &'ll Value {
-        debug!("declare_rust_fn(name={:?}, sig={:?})", name, sig);
-        let sig = self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
-        debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
+        debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
 
-        let fn_abi = FnAbi::new(self, sig, &[]);
         let llfn = declare_raw_fn(self, name, fn_abi.llvm_cconv(), fn_abi.llvm_type(self));
-
-        if self.layout_of(sig.output()).abi.is_uninhabited() {
-            llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
-        }
-
         fn_abi.apply_attrs_llfn(self, llfn);
-
         llfn
     }
 
@@ -130,28 +120,6 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         }
     }
 
-    fn define_fn(
-        &self,
-        name: &str,
-        fn_sig: PolyFnSig<'tcx>,
-    ) -> &'ll Value {
-        if self.get_defined_value(name).is_some() {
-            self.sess().fatal(&format!("symbol `{}` already defined", name))
-        } else {
-            self.declare_fn(name, fn_sig)
-        }
-    }
-
-    fn define_internal_fn(
-        &self,
-        name: &str,
-        fn_sig: PolyFnSig<'tcx>,
-    ) -> &'ll Value {
-        let llfn = self.define_fn(name, fn_sig);
-        unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
-        llfn
-    }
-
     fn get_declared_value(&self, name: &str) -> Option<&'ll Value> {
         debug!("get_declared_value(name={:?})", name);
         let namebuf = SmallCStr::new(name);
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index c34bee802f7..9df75a800f1 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -1,4 +1,3 @@
-use crate::attributes;
 use crate::llvm;
 use crate::llvm_util;
 use crate::abi::{Abi, FnAbi, LlvmType, PassMode};
@@ -14,7 +13,7 @@ use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
 use rustc_codegen_ssa::glue;
 use rustc_codegen_ssa::base::{to_immediate, wants_msvc_seh, compare_simd_types};
 use rustc::ty::{self, Ty};
-use rustc::ty::layout::{self, LayoutOf, HasTyCtxt, Primitive};
+use rustc::ty::layout::{self, FnAbiExt, LayoutOf, HasTyCtxt, Primitive};
 use rustc::mir::interpret::GlobalId;
 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
 use rustc::hir;
@@ -992,8 +991,10 @@ fn gen_fn<'ll, 'tcx>(
         hir::Unsafety::Unsafe,
         Abi::Rust
     ));
-    let llfn = cx.define_internal_fn(name, rust_fn_sig);
-    attributes::from_fn_attrs(cx, llfn, None, rust_fn_sig);
+    let fn_abi = FnAbi::of_fn_ptr(cx, rust_fn_sig, &[]);
+    let llfn = cx.declare_fn(name, &fn_abi);
+    // FIXME(eddyb) find a nicer way to do this.
+    unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
     let bx = Builder::new_block(cx, llfn, "entry-block");
     codegen(bx);
     llfn
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index c1703ffd0c7..cbc8af4fd27 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -1,3 +1,4 @@
+use crate::abi::FnAbi;
 use crate::attributes;
 use crate::base;
 use crate::context::CodegenCx;
@@ -6,7 +7,7 @@ use crate::type_of::LayoutLlvmExt;
 use rustc::hir::def_id::{DefId, LOCAL_CRATE};
 use rustc::mir::mono::{Linkage, Visibility};
 use rustc::ty::{TypeFoldable, Instance};
-use rustc::ty::layout::{LayoutOf, HasTyCtxt};
+use rustc::ty::layout::{FnAbiExt, LayoutOf};
 use rustc_codegen_ssa::traits::*;
 
 pub use rustc::mir::mono::MonoItem;
@@ -42,10 +43,10 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
         assert!(!instance.substs.needs_infer() &&
                 !instance.substs.has_param_types());
 
-        let mono_sig = instance.fn_sig(self.tcx());
-        let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
-        let lldecl = self.declare_fn(symbol_name, mono_sig);
+        let fn_abi = FnAbi::of_instance(self, instance, &[]);
+        let lldecl = self.declare_fn(symbol_name, &fn_abi);
         unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
+        let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
         base::set_link_section(lldecl, &attrs);
         if linkage == Linkage::LinkOnceODR ||
             linkage == Linkage::WeakODR {
@@ -67,16 +68,9 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
             }
         }
 
-        debug!("predefine_fn: mono_sig = {:?} instance = {:?}", mono_sig, instance);
-        if instance.def.is_inline(self.tcx) {
-            attributes::inline(self, lldecl, attributes::InlineAttr::Hint);
-        }
-        attributes::from_fn_attrs(
-            self,
-            lldecl,
-            Some(instance.def.def_id()),
-            mono_sig,
-        );
+        debug!("predefine_fn: instance = {:?}", instance);
+
+        attributes::from_fn_attrs(self, lldecl, instance, &fn_abi);
 
         self.instances.borrow_mut().insert(instance, lldecl);
     }
diff --git a/src/librustc_codegen_llvm/type_of.rs b/src/librustc_codegen_llvm/type_of.rs
index c21e62e7562..d77bbb27921 100644
--- a/src/librustc_codegen_llvm/type_of.rs
+++ b/src/librustc_codegen_llvm/type_of.rs
@@ -235,11 +235,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
                     cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx))
                 }
                 ty::FnPtr(sig) => {
-                    let sig = cx.tcx.normalize_erasing_late_bound_regions(
-                        ty::ParamEnv::reveal_all(),
-                        &sig,
-                    );
-                    cx.fn_ptr_backend_type(&FnAbi::new(cx, sig, &[]))
+                    cx.fn_ptr_backend_type(&FnAbi::of_fn_ptr(cx, sig, &[]))
                 }
                 _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO)
             };