about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEduard Burtescu <edy.burt@gmail.com>2016-02-25 12:11:02 +0200
committerEduard Burtescu <edy.burt@gmail.com>2016-03-17 21:51:51 +0200
commitd492d09f31699ff2ef1cda9da71ab3f1910a649f (patch)
treea245b6f3581e83e2482c306316164fab51ca6aa1 /src
parentac60318cf52946027050c18ad68ec85e52555853 (diff)
downloadrust-d492d09f31699ff2ef1cda9da71ab3f1910a649f.tar.gz
rust-d492d09f31699ff2ef1cda9da71ab3f1910a649f.zip
trans: Apply ZExt and StructRet attributes uniformly.
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trans/trans/abi.rs42
-rw-r--r--src/librustc_trans/trans/cabi_aarch64.rs9
-rw-r--r--src/librustc_trans/trans/cabi_arm.rs9
-rw-r--r--src/librustc_trans/trans/cabi_asmjs.rs22
-rw-r--r--src/librustc_trans/trans/cabi_mips.rs23
-rw-r--r--src/librustc_trans/trans/cabi_powerpc.rs23
-rw-r--r--src/librustc_trans/trans/cabi_powerpc64.rs10
-rw-r--r--src/librustc_trans/trans/cabi_x86.rs10
-rw-r--r--src/librustc_trans/trans/cabi_x86_64.rs12
-rw-r--r--src/librustc_trans/trans/cabi_x86_win64.rs13
-rw-r--r--src/librustc_trans/trans/declare.rs13
-rw-r--r--src/librustc_trans/trans/foreign.rs36
-rw-r--r--src/librustc_trans/trans/type_of.rs2
13 files changed, 67 insertions, 157 deletions
diff --git a/src/librustc_trans/trans/abi.rs b/src/librustc_trans/trans/abi.rs
index d802a41ed69..a0351e32259 100644
--- a/src/librustc_trans/trans/abi.rs
+++ b/src/librustc_trans/trans/abi.rs
@@ -10,8 +10,7 @@
 
 pub use self::ArgKind::*;
 
-use llvm::{self, AttrHelper, ValueRef};
-use trans::attributes;
+use llvm;
 use trans::common::{return_type_is_void, type_is_fat_ptr};
 use trans::context::CrateContext;
 use trans::cabi_x86;
@@ -23,7 +22,7 @@ use trans::cabi_powerpc;
 use trans::cabi_powerpc64;
 use trans::cabi_mips;
 use trans::cabi_asmjs;
-use trans::machine::llsize_of_alloc;
+use trans::machine::{llsize_of_alloc, llsize_of_real};
 use trans::type_::Type;
 use trans::type_of;
 
@@ -191,6 +190,13 @@ impl FnType {
             cconv: cconv
         };
 
+        // Add ZExt attributes to i1 arguments and returns.
+        for arg in Some(&mut fty.ret).into_iter().chain(&mut fty.args) {
+            if arg.ty == Type::i1(ccx) {
+                arg.attr = Some(llvm::Attribute::ZExt);
+            }
+        }
+
         if abi == Rust || abi == RustCall {
             let fixup = |arg: &mut ArgType| {
                 if !arg.ty.is_aggregate() {
@@ -246,7 +252,7 @@ impl FnType {
         fty
     }
 
-    pub fn to_llvm(&self, ccx: &CrateContext) -> Type {
+    pub fn llvm_type(&self, ccx: &CrateContext) -> Type {
         let mut llargument_tys = Vec::new();
 
         let llreturn_ty = if self.ret.is_indirect() {
@@ -281,19 +287,29 @@ impl FnType {
         }
     }
 
-    pub fn add_attributes(&self, llfn: ValueRef) {
-        let mut i = if self.ret.is_indirect() {
-            1
-        } else {
-            0
+    pub fn llvm_attrs(&self, ccx: &CrateContext) -> llvm::AttrBuilder {
+        let mut attrs = llvm::AttrBuilder::new();
+        let mut i = if self.ret.is_indirect() { 1 } else { 0 };
+
+        // Add attributes that are always applicable, independent of the concrete foreign ABI
+        if self.ret.is_indirect() {
+            let llret_sz = llsize_of_real(ccx, self.ret.ty);
+
+            // The outptr can be noalias and nocapture because it's entirely
+            // invisible to the program. We also know it's nonnull as well
+            // as how many bytes we can dereference
+            attrs.arg(i, llvm::Attribute::StructRet)
+                 .arg(i, llvm::Attribute::NoAlias)
+                 .arg(i, llvm::Attribute::NoCapture)
+                 .arg(i, llvm::DereferenceableAttribute(llret_sz));
         };
 
+        // Add attributes that depend on the concrete foreign ABI
         if let Some(attr) = self.ret.attr {
-            attr.apply_llfn(i, llfn);
+            attrs.arg(i, attr);
         }
 
         i += 1;
-
         for arg in &self.args {
             if arg.is_ignore() {
                 continue;
@@ -302,12 +318,12 @@ impl FnType {
             if arg.pad.is_some() { i += 1; }
 
             if let Some(attr) = arg.attr {
-                attr.apply_llfn(i, llfn);
+                attrs.arg(i, attr);
             }
 
             i += 1;
         }
 
-        attributes::unwind(llfn, false);
+        attrs
     }
 }
diff --git a/src/librustc_trans/trans/cabi_aarch64.rs b/src/librustc_trans/trans/cabi_aarch64.rs
index c98c53894ca..65d2ad9c4fa 100644
--- a/src/librustc_trans/trans/cabi_aarch64.rs
+++ b/src/librustc_trans/trans/cabi_aarch64.rs
@@ -10,7 +10,7 @@
 
 #![allow(non_upper_case_globals)]
 
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector, Attribute};
+use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
 use trans::abi::{FnType, ArgType, Indirect};
 use trans::context::CrateContext;
 use trans::type_::Type;
@@ -163,9 +163,6 @@ fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
 
 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
     if is_reg_ty(ret.ty) {
-        if ret.ty == Type::i1(ccx) {
-            ret.attr = Some(Attribute::ZExt)
-        }
         return;
     }
     if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
@@ -189,14 +186,10 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
         return;
     }
     ret.kind = Indirect;
-    ret.attr = Some(Attribute::StructRet);
 }
 
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
     if is_reg_ty(arg.ty) {
-        if arg.ty == Type::i1(ccx) {
-            arg.attr = Some(Attribute::ZExt);
-        }
         return;
     }
     if let Some((base_ty, members)) = is_homogenous_aggregate_ty(arg.ty) {
diff --git a/src/librustc_trans/trans/cabi_arm.rs b/src/librustc_trans/trans/cabi_arm.rs
index abdc5bbd79f..77941a853e6 100644
--- a/src/librustc_trans/trans/cabi_arm.rs
+++ b/src/librustc_trans/trans/cabi_arm.rs
@@ -10,7 +10,7 @@
 
 #![allow(non_upper_case_globals)]
 
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector, Attribute};
+use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
 use trans::abi::{FnType, ArgType, Indirect};
 use trans::context::CrateContext;
 use trans::type_::Type;
@@ -131,9 +131,6 @@ fn ty_size(ty: Type, align_fn: TyAlignFn) -> usize {
 
 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
     if is_reg_ty(ret.ty) {
-        if ret.ty == Type::i1(ccx) {
-            ret.attr = Some(Attribute::ZExt);
-        }
         return;
     }
     let size = ty_size(ret.ty, align_fn);
@@ -149,14 +146,10 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType, align_fn: TyAlignFn) {
         return;
     }
     ret.kind = Indirect;
-    ret.attr = Some(Attribute::StructRet);
 }
 
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, align_fn: TyAlignFn) {
     if is_reg_ty(arg.ty) {
-        if arg.ty == Type::i1(ccx) {
-            arg.attr = Some(Attribute::ZExt);
-        }
         return;
     }
     let align = align_fn(arg.ty);
diff --git a/src/librustc_trans/trans/cabi_asmjs.rs b/src/librustc_trans/trans/cabi_asmjs.rs
index fd831f0e253..5c9bf28e4e0 100644
--- a/src/librustc_trans/trans/cabi_asmjs.rs
+++ b/src/librustc_trans/trans/cabi_asmjs.rs
@@ -20,7 +20,7 @@ use trans::type_::Type;
 // See the https://github.com/kripken/emscripten-fastcomp-clang repository.
 // The class `EmscriptenABIInfo` in `/lib/CodeGen/TargetInfo.cpp` contains the ABI definitions.
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+fn classify_ret_ty(ret: &mut ArgType) {
     match ret.ty.kind() {
         Struct => {
             let field_types = ret.ty.field_types();
@@ -28,38 +28,28 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
                 ret.cast = Some(field_types[0]);
             } else {
                 ret.kind = Indirect;
-                ret.attr = Some(Attribute::StructRet);
             }
-        },
+        }
         Array => {
             ret.kind = Indirect;
-            ret.attr = Some(Attribute::StructRet);
-        },
-        _ => {
-            if ret.ty == Type::i1(ccx) {
-                ret.attr = Some(Attribute::ZExt);
-            }
         }
+        _ => {}
     }
 }
 
-fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
+fn classify_arg_ty(arg: &mut ArgType) {
     if arg.ty.is_aggregate() {
         arg.kind = Indirect;
         arg.attr = Some(Attribute::ByVal);
-    } else {
-        if arg.ty == Type::i1(ccx) {
-            arg.attr = Some(Attribute::ZExt);
-        }
     }
 }
 
 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
     if fty.ret.ty != Type::void(ccx) {
-        classify_ret_ty(ccx, &mut fty.ret);
+        classify_ret_ty(&mut fty.ret);
     }
 
     for arg in &mut fty.args {
-        classify_arg_ty(ccx, arg);
+        classify_arg_ty(arg);
     }
 }
diff --git a/src/librustc_trans/trans/cabi_mips.rs b/src/librustc_trans/trans/cabi_mips.rs
index a07f897c122..419c56072b4 100644
--- a/src/librustc_trans/trans/cabi_mips.rs
+++ b/src/librustc_trans/trans/cabi_mips.rs
@@ -13,7 +13,7 @@
 use libc::c_uint;
 use std::cmp;
 use llvm;
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector, Attribute};
+use llvm::{Integer, Pointer, Float, Double, Struct, Array, Vector};
 use trans::abi::{ArgType, FnType, Indirect};
 use trans::context::CrateContext;
 use trans::type_::Type;
@@ -86,17 +86,6 @@ fn ty_size(ty: Type) -> usize {
     }
 }
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
-        if ret.ty == Type::i1(ccx) {
-            ret.attr = Some(Attribute::ZExt);
-        }
-    } else {
-        ret.kind = Indirect;
-        ret.attr = Some(Attribute::StructRet);
-    }
-}
-
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     let orig_offset = *offset;
     let size = ty_size(arg.ty) * 8;
@@ -106,11 +95,7 @@ fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     *offset = align_up_to(*offset, align);
     *offset += align_up_to(size, align * 8) / 8;
 
-    if is_reg_ty(arg.ty) {
-        if arg.ty == Type::i1(ccx) {
-            arg.attr = Some(Attribute::ZExt);
-        }
-    } else {
+    if !is_reg_ty(arg.ty) {
         arg.cast = Some(struct_ty(ccx, arg.ty));
         arg.pad = padding_ty(ccx, align, orig_offset);
     }
@@ -162,7 +147,9 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
 
 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
     if fty.ret.ty != Type::void(ccx) {
-        classify_ret_ty(ccx, &mut fty.ret);
+        if !is_reg_ty(fty.ret.ty) {
+            fty.ret.kind = Indirect;
+        }
     }
 
     let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
diff --git a/src/librustc_trans/trans/cabi_powerpc.rs b/src/librustc_trans/trans/cabi_powerpc.rs
index 19307cc230f..ecd5b71ada9 100644
--- a/src/librustc_trans/trans/cabi_powerpc.rs
+++ b/src/librustc_trans/trans/cabi_powerpc.rs
@@ -10,7 +10,7 @@
 
 use libc::c_uint;
 use llvm;
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Attribute};
+use llvm::{Integer, Pointer, Float, Double, Struct, Array};
 use trans::abi::{FnType, ArgType, Indirect};
 use trans::context::CrateContext;
 use trans::type_::Type;
@@ -82,17 +82,6 @@ fn ty_size(ty: Type) -> usize {
     }
 }
 
-fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
-    if is_reg_ty(ret.ty) {
-        if ret.ty == Type::i1(ccx) {
-            ret.attr = Some(Attribute::ZExt);
-        }
-    } else {
-        ret.kind = Indirect;
-        ret.attr = Some(Attribute::StructRet);
-    }
-}
-
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     let orig_offset = *offset;
     let size = ty_size(arg.ty) * 8;
@@ -102,11 +91,7 @@ fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
     *offset = align_up_to(*offset, align);
     *offset += align_up_to(size, align * 8) / 8;
 
-    if is_reg_ty(arg.ty) {
-        if arg.ty == Type::i1(ccx) {
-            arg.attr = Some(Attribute::ZExt);
-        }
-    } else {
+    if !is_reg_ty(arg.ty) {
         arg.cast = Some(struct_ty(ccx, arg.ty));
         arg.pad = padding_ty(ccx, align, orig_offset);
     }
@@ -157,7 +142,9 @@ fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
 
 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
     if fty.ret.ty != Type::void(ccx) {
-        classify_ret_ty(ccx, &mut fty.ret);
+        if !is_reg_ty(fty.ret.ty) {
+            fty.ret.kind = Indirect;
+        }
     }
 
     let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
diff --git a/src/librustc_trans/trans/cabi_powerpc64.rs b/src/librustc_trans/trans/cabi_powerpc64.rs
index ee1e5a39b61..b28ec618650 100644
--- a/src/librustc_trans/trans/cabi_powerpc64.rs
+++ b/src/librustc_trans/trans/cabi_powerpc64.rs
@@ -15,7 +15,7 @@
 // Alignment of 128 bit types is not currently handled, this will
 // need to be fixed when PowerPC vector support is added.
 
-use llvm::{Integer, Pointer, Float, Double, Struct, Array, Attribute};
+use llvm::{Integer, Pointer, Float, Double, Struct, Array};
 use trans::abi::{FnType, ArgType, Indirect};
 use trans::context::CrateContext;
 use trans::type_::Type;
@@ -153,16 +153,12 @@ fn is_homogenous_aggregate_ty(ty: Type) -> Option<(Type, u64)> {
 
 fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
     if is_reg_ty(ret.ty) {
-        if ret.ty == Type::i1(ccx) {
-            ret.attr = Some(Attribute::ZExt);
-        }
         return;
     }
 
     // The PowerPC64 big endian ABI doesn't return aggregates in registers
     if ccx.sess().target.target.target_endian == "big" {
         ret.kind = Indirect;
-        ret.attr = Some(Attribute::StructRet);
     }
 
     if let Some((base_ty, members)) = is_homogenous_aggregate_ty(ret.ty) {
@@ -187,14 +183,10 @@ fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
     }
 
     ret.kind = Indirect;
-    ret.attr = Some(Attribute::StructRet);
 }
 
 fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
     if is_reg_ty(arg.ty) {
-        if arg.ty == Type::i1(ccx) {
-            arg.attr = Some(Attribute::ZExt);
-        }
         return;
     }
 
diff --git a/src/librustc_trans/trans/cabi_x86.rs b/src/librustc_trans/trans/cabi_x86.rs
index b5dd3393ba9..fd1b8b21401 100644
--- a/src/librustc_trans/trans/cabi_x86.rs
+++ b/src/librustc_trans/trans/cabi_x86.rs
@@ -30,17 +30,11 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
                 2 => fty.ret.cast = Some(Type::i16(ccx)),
                 4 => fty.ret.cast = Some(Type::i32(ccx)),
                 8 => fty.ret.cast = Some(Type::i64(ccx)),
-                _ => {
-                    fty.ret.kind = Indirect;
-                    fty.ret.attr = Some(Attribute::StructRet);
-                }
+                _ => fty.ret.kind = Indirect
             }
         } else {
             fty.ret.kind = Indirect;
-            fty.ret.attr = Some(Attribute::StructRet);
         }
-    } else if fty.ret.ty == Type::i1(ccx) {
-        fty.ret.attr = Some(Attribute::ZExt);
     }
 
     for arg in &mut fty.args {
@@ -51,8 +45,6 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
                 arg.kind = Indirect;
                 arg.attr = Some(Attribute::ByVal);
             }
-        } else if arg.ty == Type::i1(ccx) {
-            arg.attr = Some(Attribute::ZExt);
         }
     }
 }
diff --git a/src/librustc_trans/trans/cabi_x86_64.rs b/src/librustc_trans/trans/cabi_x86_64.rs
index 4c6ff6ff955..ab32ca206fc 100644
--- a/src/librustc_trans/trans/cabi_x86_64.rs
+++ b/src/librustc_trans/trans/cabi_x86_64.rs
@@ -387,21 +387,17 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
     fn x86_64_ty<F>(ccx: &CrateContext,
                     arg: &mut ArgType,
                     is_mem_cls: F,
-                    ind_attr: Attribute)
+                    ind_attr: Option<Attribute>)
         where F: FnOnce(&[RegClass]) -> bool
     {
         if !arg.ty.is_reg_ty() {
             let cls = classify_ty(arg.ty);
             if is_mem_cls(&cls) {
                 arg.kind = Indirect;
-                arg.attr = Some(ind_attr);
+                arg.attr = ind_attr;
             } else {
                 arg.cast = Some(llreg_ty(ccx, &cls));
             }
-        } else {
-            if arg.ty == Type::i1(ccx) {
-                arg.attr = Some(Attribute::ZExt);
-            }
         }
     }
 
@@ -417,7 +413,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
             } else {
                 false
             }
-        }, Attribute::StructRet);
+        }, None);
     }
 
     for arg in &mut fty.args {
@@ -436,7 +432,7 @@ pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
                 sse_regs -= needed_sse;
             }
             in_mem
-        }, Attribute::ByVal);
+        }, Some(Attribute::ByVal));
 
         // An integer, pointer, double or float parameter
         // thus the above closure passed to `x86_64_ty` won't
diff --git a/src/librustc_trans/trans/cabi_x86_win64.rs b/src/librustc_trans/trans/cabi_x86_win64.rs
index ab9323dda7b..e9a06fd8d6b 100644
--- a/src/librustc_trans/trans/cabi_x86_win64.rs
+++ b/src/librustc_trans/trans/cabi_x86_win64.rs
@@ -17,27 +17,22 @@ use trans::type_::Type;
 // Win64 ABI: http://msdn.microsoft.com/en-us/library/zthk2dkh.aspx
 
 pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
-    let fixup = |a: &mut ArgType, indirect_attr| {
+    let fixup = |a: &mut ArgType| {
         if a.ty.kind() == Struct {
             match llsize_of_alloc(ccx, a.ty) {
                 1 => a.cast = Some(Type::i8(ccx)),
                 2 => a.cast = Some(Type::i16(ccx)),
                 4 => a.cast = Some(Type::i32(ccx)),
                 8 => a.cast = Some(Type::i64(ccx)),
-                _ => {
-                    a.kind = Indirect;
-                    a.attr = indirect_attr;
-                }
+                _ => a.kind = Indirect
             }
-        } else if a.ty == Type::i1(ccx) {
-            a.attr = Some(Attribute::ZExt);
         }
     };
 
     if fty.ret.ty != Type::void(ccx) {
-        fixup(&mut fty.ret, Some(Attribute::StructRet));
+        fixup(&mut fty.ret);
     }
     for arg in &mut fty.args {
-        fixup(arg, None);
+        fixup(arg);
     }
 }
diff --git a/src/librustc_trans/trans/declare.rs b/src/librustc_trans/trans/declare.rs
index 76195f19e9f..f7bc22a4482 100644
--- a/src/librustc_trans/trans/declare.rs
+++ b/src/librustc_trans/trans/declare.rs
@@ -103,17 +103,20 @@ pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
     debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
 
     let fty = FnType::new(ccx, f.abi, &sig, &[]);
-    let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.to_llvm(ccx));
+    let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx));
 
     if sig.output == ty::FnDiverging {
         llvm::SetFunctionAttribute(llfn, llvm::Attribute::NoReturn);
     }
 
-    if f.abi == Abi::Rust || f.abi == Abi::RustCall {
-        attributes::from_fn_type(ccx, fn_type).apply_llfn(llfn);
+    let attrs = if f.abi == Abi::Rust || f.abi == Abi::RustCall {
+        attributes::from_fn_type(ccx, fn_type)
     } else {
-        fty.add_attributes(llfn);
-    }
+        attributes::unwind(llfn, false);
+        fty.llvm_attrs(ccx)
+    };
+
+    attrs.apply_llfn(llfn);
 
     llfn
 }
diff --git a/src/librustc_trans/trans/foreign.rs b/src/librustc_trans/trans/foreign.rs
index 46eb8006272..870853af1ee 100644
--- a/src/librustc_trans/trans/foreign.rs
+++ b/src/librustc_trans/trans/foreign.rs
@@ -247,47 +247,13 @@ pub fn trans_native_call<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
 
     // A function pointer is called without the declaration available, so we have to apply
     // any attributes with ABI implications directly to the call instruction.
-    let mut attrs = llvm::AttrBuilder::new();
 
-    // Add attributes that are always applicable, independent of the concrete foreign ABI
-    if fn_type.ret.is_indirect() {
-        let llret_sz = machine::llsize_of_real(ccx, fn_type.ret.ty);
-
-        // The outptr can be noalias and nocapture because it's entirely
-        // invisible to the program. We also know it's nonnull as well
-        // as how many bytes we can dereference
-        attrs.arg(1, llvm::Attribute::NoAlias)
-             .arg(1, llvm::Attribute::NoCapture)
-             .arg(1, llvm::DereferenceableAttribute(llret_sz));
-    };
-
-    // Add attributes that depend on the concrete foreign ABI
-    let mut arg_idx = if fn_type.ret.is_indirect() { 1 } else { 0 };
-    match fn_type.ret.attr {
-        Some(attr) => { attrs.arg(arg_idx, attr); },
-        _ => ()
-    }
-
-    arg_idx += 1;
-    for arg_ty in &fn_type.args {
-        if arg_ty.is_ignore() {
-            continue;
-        }
-        // skip padding
-        if arg_ty.pad.is_some() { arg_idx += 1; }
-
-        if let Some(attr) = arg_ty.attr {
-            attrs.arg(arg_idx, attr);
-        }
-
-        arg_idx += 1;
-    }
 
     let llforeign_retval = CallWithConv(bcx,
                                         llfn,
                                         &llargs_foreign[..],
                                         fn_type.cconv,
-                                        Some(attrs),
+                                        Some(fn_type.llvm_attrs(ccx)),
                                         call_debug_loc);
 
     // If the function we just called does not use an outpointer,
diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs
index 662471241d5..634d33d445e 100644
--- a/src/librustc_trans/trans/type_of.rs
+++ b/src/librustc_trans/trans/type_of.rs
@@ -322,7 +322,7 @@ pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) ->
       ty::TyFnPtr(f) => {
         let sig = cx.tcx().erase_late_bound_regions(&f.sig);
         let sig = infer::normalize_associated_type(cx.tcx(), &sig);
-        FnType::new(cx, f.abi, &sig, &[]).to_llvm(cx).ptr_to()
+        FnType::new(cx, f.abi, &sig, &[]).llvm_type(cx).ptr_to()
       }
       ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
       ty::TyTuple(..) => {