about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/lib/llvm.rs54
-rw-r--r--src/librustc/middle/trans/base.rs277
-rw-r--r--src/librustc/middle/trans/build.rs6
-rw-r--r--src/librustc/middle/trans/builder.rs10
-rw-r--r--src/librustc/middle/trans/callee.rs58
-rw-r--r--src/librustc/middle/trans/closure.rs25
-rw-r--r--src/librustc/middle/trans/foreign.rs56
-rw-r--r--src/librustc/middle/trans/glue.rs13
-rw-r--r--src/librustc/middle/trans/monomorphize.rs14
-rw-r--r--src/librustc/middle/trans/reflect.rs6
-rw-r--r--src/rustllvm/RustWrapper.cpp71
11 files changed, 276 insertions, 314 deletions
diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs
index 0e7a904c967..dacda4e2a0b 100644
--- a/src/librustc/lib/llvm.rs
+++ b/src/librustc/lib/llvm.rs
@@ -15,7 +15,7 @@
 use std::c_str::ToCStr;
 use std::cell::RefCell;
 use collections::HashMap;
-use libc::{c_uint, c_ushort, c_void, free};
+use libc::{c_uint, c_ushort, c_void, free, uint64_t};
 use std::str::raw::from_c_str;
 
 use middle::trans::type_::Type;
@@ -92,6 +92,33 @@ pub enum Attribute {
     NonLazyBindAttribute = 1 << 31,
 }
 
+#[repr(u64)]
+pub enum OtherAttribute {
+    // The following are not really exposed in
+    // the LLVM c api so instead to add these
+    // we call a wrapper function in RustWrapper
+    // that uses the C++ api.
+    SanitizeAddressAttribute = 1 << 32,
+    MinSizeAttribute = 1 << 33,
+    NoDuplicateAttribute = 1 << 34,
+    StackProtectStrongAttribute = 1 << 35,
+    SanitizeThreadAttribute = 1 << 36,
+    SanitizeMemoryAttribute = 1 << 37,
+    NoBuiltinAttribute = 1 << 38,
+    ReturnedAttribute = 1 << 39,
+    ColdAttribute = 1 << 40,
+    BuiltinAttribute = 1 << 41,
+    OptimizeNoneAttribute = 1 << 42,
+    InAllocaAttribute = 1 << 43,
+    NonNullAttribute = 1 << 44,
+}
+
+#[repr(C)]
+pub enum AttributeSet {
+    ReturnIndex = 0,
+    FunctionIndex = !0
+}
+
 // enum for the LLVM IntPredicate type
 pub enum IntPredicate {
     IntEQ = 32,
@@ -308,7 +335,7 @@ pub mod llvm {
     use super::{CodeGenModel, RelocMode, CodeGenOptLevel};
     use super::debuginfo::*;
     use libc::{c_char, c_int, c_longlong, c_ushort, c_uint, c_ulonglong,
-                    size_t};
+               size_t, uint64_t};
 
     // Link to our native llvm bindings (things that we need to use the C++ api
     // for) and because llvm is written in C++ we need to link against libstdc++
@@ -706,23 +733,11 @@ pub mod llvm {
         pub fn LLVMSetFunctionCallConv(Fn: ValueRef, CC: c_uint);
         pub fn LLVMGetGC(Fn: ValueRef) -> *c_char;
         pub fn LLVMSetGC(Fn: ValueRef, Name: *c_char);
-        pub fn LLVMAddFunctionAttr(Fn: ValueRef, PA: c_uint);
-        pub fn LLVMAddFunctionAttrString(Fn: ValueRef, Name: *c_char);
-        pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, Name: *c_char);
+        pub fn LLVMAddFunctionAttribute(Fn: ValueRef, index: c_uint, PA: uint64_t);
+        pub fn LLVMAddFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *c_char);
+        pub fn LLVMRemoveFunctionAttrString(Fn: ValueRef, index: c_uint, Name: *c_char);
         pub fn LLVMGetFunctionAttr(Fn: ValueRef) -> c_ulonglong;
 
-        pub fn LLVMAddReturnAttribute(Fn: ValueRef, PA: c_uint);
-        pub fn LLVMRemoveReturnAttribute(Fn: ValueRef, PA: c_uint);
-
-        pub fn LLVMAddColdAttribute(Fn: ValueRef);
-
-        pub fn LLVMAddNonNullAttribute(Arg: ValueRef);
-        pub fn LLVMAddNonNullReturnAttribute(Fn: ValueRef);
-
-        pub fn LLVMRemoveFunctionAttr(Fn: ValueRef,
-                                      PA: c_ulonglong,
-                                      HighPA: c_ulonglong);
-
         /* Operations on parameters */
         pub fn LLVMCountParams(Fn: ValueRef) -> c_uint;
         pub fn LLVMGetParams(Fn: ValueRef, Params: *ValueRef);
@@ -786,6 +801,9 @@ pub mod llvm {
         pub fn LLVMSetInstrParamAlignment(Instr: ValueRef,
                                           index: c_uint,
                                           align: c_uint);
+        pub fn LLVMAddCallSiteAttribute(Instr: ValueRef,
+                                        index: c_uint,
+                                        Val: uint64_t);
 
         /* Operations on call instructions (only) */
         pub fn LLVMIsTailCall(CallInst: ValueRef) -> Bool;
@@ -1838,7 +1856,7 @@ pub fn ConstFCmp(pred: RealPredicate, v1: ValueRef, v2: ValueRef) -> ValueRef {
 
 pub fn SetFunctionAttribute(fn_: ValueRef, attr: Attribute) {
     unsafe {
-        llvm::LLVMAddFunctionAttr(fn_, attr as c_uint)
+        llvm::LLVMAddFunctionAttribute(fn_, FunctionIndex as c_uint, attr as uint64_t)
     }
 }
 /* Memory-managed object interface to type handles. */
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index 6413d798e0e..43f3442ec47 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -73,7 +73,7 @@ use util::sha2::Sha256;
 use util::nodemap::NodeMap;
 
 use arena::TypedArena;
-use libc::c_uint;
+use libc::{c_uint, uint64_t};
 use std::c_str::ToCStr;
 use std::cell::{Cell, RefCell};
 use std::rc::Rc;
@@ -167,6 +167,7 @@ impl<'a> Drop for StatRecorder<'a> {
 // only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
 fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv,
            ty: Type, output: ty::t) -> ValueRef {
+
     let llfn: ValueRef = name.with_c_str(|buf| {
         unsafe {
             llvm::LLVMGetOrInsertFunction(llmod, buf, ty.to_ref())
@@ -177,14 +178,9 @@ fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv,
         // functions returning bottom may unwind, but can never return normally
         ty::ty_bot => {
             unsafe {
-                llvm::LLVMAddFunctionAttr(llfn, lib::llvm::NoReturnAttribute as c_uint)
-            }
-        }
-        // `~` pointer return values never alias because ownership is transferred
-        ty::ty_uniq(..) // | ty::ty_trait(_, _, ty::UniqTraitStore, _, _)
-         => {
-            unsafe {
-                llvm::LLVMAddReturnAttribute(llfn, lib::llvm::NoAliasAttribute as c_uint);
+                llvm::LLVMAddFunctionAttribute(llfn,
+                                               lib::llvm::FunctionIndex as c_uint,
+                                               lib::llvm::NoReturnAttribute as uint64_t)
             }
         }
         _ => {}
@@ -207,8 +203,8 @@ pub fn decl_cdecl_fn(llmod: ModuleRef,
 }
 
 // only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
-pub fn get_extern_fn(externs: &mut ExternMap,
-                     llmod: ModuleRef,
+pub fn get_extern_fn(ccx: &CrateContext,
+                     externs: &mut ExternMap,
                      name: &str,
                      cc: lib::llvm::CallConv,
                      ty: Type,
@@ -218,19 +214,19 @@ pub fn get_extern_fn(externs: &mut ExternMap,
         Some(n) => return *n,
         None => {}
     }
-    let f = decl_fn(llmod, name, cc, ty, output);
+    let f = decl_fn(ccx.llmod, name, cc, ty, output);
     externs.insert(name.to_strbuf(), f);
     f
 }
 
-fn get_extern_rust_fn(ccx: &CrateContext, inputs: &[ty::t], output: ty::t,
-                      name: &str, did: ast::DefId) -> ValueRef {
+fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::DefId) -> ValueRef {
     match ccx.externs.borrow().find_equiv(&name) {
         Some(n) => return *n,
         None => ()
     }
 
-    let f = decl_rust_fn(ccx, false, inputs, output, name);
+    let f = decl_rust_fn(ccx, fn_ty, name);
+
     csearch::get_item_attrs(&ccx.sess().cstore, did, |meta_items| {
         set_llvm_fn_attrs(meta_items.iter().map(|&x| attr::mk_attr_outer(x))
                                     .collect::<Vec<_>>().as_slice(), f)
@@ -240,92 +236,27 @@ fn get_extern_rust_fn(ccx: &CrateContext, inputs: &[ty::t], output: ty::t,
     f
 }
 
-pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
-                    inputs: &[ty::t], output: ty::t,
-                    name: &str) -> ValueRef {
-    use middle::ty::{BrAnon, ReLateBound};
-
-    let llfty = type_of_rust_fn(ccx, has_env, inputs, output);
-    let llfn = decl_cdecl_fn(ccx.llmod, name, llfty, output);
-
-    let uses_outptr = type_of::return_uses_outptr(ccx, output);
-    let offset = if uses_outptr { 1 } else { 0 };
-    let offset = if has_env { offset + 1 } else { offset };
-
-    for (i, &arg_ty) in inputs.iter().enumerate() {
-        let llarg = unsafe { llvm::LLVMGetParam(llfn, (offset + i) as c_uint) };
-        match ty::get(arg_ty).sty {
-            // `~` pointer parameters never alias because ownership is transferred
-            ty::ty_uniq(..) => {
-                unsafe {
-                    llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
-                    llvm::LLVMAddNonNullAttribute(llarg);
-                }
-            }
-            // `&mut` pointer parameters never alias other parameters, or mutable global data
-            ty::ty_rptr(_, mt) if mt.mutbl == ast::MutMutable => {
-                unsafe {
-                    llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
-                    llvm::LLVMAddNonNullAttribute(llarg);
-                }
-            }
-            // When a reference in an argument has no named lifetime, it's impossible for that
-            // reference to escape this function (returned or stored beyond the call by a closure).
-            ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
-                debug!("marking argument of {} as nocapture because of anonymous lifetime", name);
-                unsafe {
-                    llvm::LLVMAddAttribute(llarg, lib::llvm::NoCaptureAttribute as c_uint);
-                    llvm::LLVMAddNonNullAttribute(llarg);
-                }
-            }
-            // `&` pointer parameters are never null
-            ty::ty_rptr(..) => {
-                unsafe {
-                    llvm::LLVMAddNonNullAttribute(llarg);
-                }
-            }
-            _ => {
-                // For non-immediate arguments the callee gets its own copy of
-                // the value on the stack, so there are no aliases
-                if !type_is_immediate(ccx, arg_ty) {
-                    unsafe {
-                        llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
-                        llvm::LLVMAddAttribute(llarg, lib::llvm::NoCaptureAttribute as c_uint);
-                    }
-                }
-            }
-        }
-    }
+pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
+    let (inputs, output, has_env) = match ty::get(fn_ty).sty {
+        ty::ty_bare_fn(ref f) => (f.sig.inputs.clone(), f.sig.output, false),
+        ty::ty_closure(ref f) => (f.sig.inputs.clone(), f.sig.output, true),
+        _ => fail!("expected closure or fn")
+    };
 
-    // The out pointer will never alias with any other pointers, as the object only exists at a
-    // language level after the call. It can also be tagged with SRet to indicate that it is
-    // guaranteed to point to a usable block of memory for the type. We also know that it's
-    // never null
-    if uses_outptr {
+    let llfty = type_of_rust_fn(ccx, has_env, inputs.as_slice(), output);
+    let llfn = decl_fn(ccx.llmod, name, lib::llvm::CCallConv, llfty, output);
+    let attrs = get_fn_llvm_attributes(ccx, fn_ty);
+    for &(idx, attr) in attrs.iter() {
         unsafe {
-            let outptr = llvm::LLVMGetParam(llfn, 0);
-            llvm::LLVMAddAttribute(outptr, lib::llvm::StructRetAttribute as c_uint);
-            llvm::LLVMAddAttribute(outptr, lib::llvm::NoAliasAttribute as c_uint);
-            llvm::LLVMAddNonNullAttribute(outptr);
-        }
-    } else {
-        match ty::get(output).sty {
-            ty::ty_uniq(..) | ty::ty_rptr(..) => {
-                unsafe {
-                    llvm::LLVMAddNonNullReturnAttribute(llfn);
-                }
-            }
-            _ => {}
+            llvm::LLVMAddFunctionAttribute(llfn, idx as c_uint, attr);
         }
     }
 
     llfn
 }
 
-pub fn decl_internal_rust_fn(ccx: &CrateContext, has_env: bool,
-                             inputs: &[ty::t], output: ty::t,
-                             name: &str) -> ValueRef {
-    let llfn = decl_rust_fn(ccx, has_env, inputs, output, name);
+pub fn decl_internal_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
+    let llfn = decl_rust_fn(ccx, fn_ty, name);
     lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
     llfn
 }
@@ -473,7 +404,11 @@ pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) {
     }
 
     if contains_name(attrs, "cold") {
-        unsafe { llvm::LLVMAddColdAttribute(llfn) }
+        unsafe {
+            llvm::LLVMAddFunctionAttribute(llfn,
+                                           lib::llvm::FunctionIndex as c_uint,
+                                           lib::llvm::ColdAttribute as uint64_t)
+        }
     }
 }
 
@@ -483,13 +418,13 @@ pub fn set_always_inline(f: ValueRef) {
 
 pub fn set_split_stack(f: ValueRef) {
     "split-stack".with_c_str(|buf| {
-        unsafe { llvm::LLVMAddFunctionAttrString(f, buf); }
+        unsafe { llvm::LLVMAddFunctionAttrString(f, lib::llvm::FunctionIndex as c_uint, buf); }
     })
 }
 
 pub fn unset_split_stack(f: ValueRef) {
     "split-stack".with_c_str(|buf| {
-        unsafe { llvm::LLVMRemoveFunctionAttrString(f, buf); }
+        unsafe { llvm::LLVMRemoveFunctionAttrString(f, lib::llvm::FunctionIndex as c_uint, buf); }
     })
 }
 
@@ -505,6 +440,7 @@ pub fn note_unique_llvm_symbol(ccx: &CrateContext, sym: StrBuf) {
 
 pub fn get_res_dtor(ccx: &CrateContext,
                     did: ast::DefId,
+                    t: ty::t,
                     parent_id: ast::DefId,
                     substs: &ty::substs)
                  -> ValueRef {
@@ -530,13 +466,14 @@ pub fn get_res_dtor(ccx: &CrateContext,
         let class_ty = ty::subst(tcx, substs,
                                  ty::lookup_item_type(tcx, parent_id).ty);
         let llty = type_of_dtor(ccx, class_ty);
-
-        get_extern_fn(&mut *ccx.externs.borrow_mut(),
-                      ccx.llmod,
+        let dtor_ty = ty::mk_ctor_fn(ccx.tcx(), ast::DUMMY_NODE_ID,
+                                     [glue::get_drop_glue_type(ccx, t)], ty::mk_nil());
+        get_extern_fn(ccx,
+                      &mut *ccx.externs.borrow_mut(),
                       name.as_slice(),
                       lib::llvm::CCallConv,
                       llty,
-                      ty::mk_nil())
+                      dtor_ty)
     }
 }
 
@@ -878,11 +815,7 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val
             match fn_ty.abi.for_target(ccx.sess().targ_cfg.os,
                                        ccx.sess().targ_cfg.arch) {
                 Some(Rust) | Some(RustIntrinsic) => {
-                    get_extern_rust_fn(ccx,
-                                       fn_ty.sig.inputs.as_slice(),
-                                       fn_ty.sig.output,
-                                       name.as_slice(),
-                                       did)
+                    get_extern_rust_fn(ccx, t, name.as_slice(), did)
                 }
                 Some(..) | None => {
                     foreign::register_foreign_item_fn(ccx, fn_ty.abi, t,
@@ -890,12 +823,8 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val
                 }
             }
         }
-        ty::ty_closure(ref f) => {
-            get_extern_rust_fn(ccx,
-                               f.sig.inputs.as_slice(),
-                               f.sig.output,
-                               name.as_slice(),
-                               did)
+        ty::ty_closure(_) => {
+            get_extern_rust_fn(ccx, t, name.as_slice(), did)
         }
         _ => {
             let llty = type_of(ccx, t);
@@ -911,7 +840,7 @@ pub fn invoke<'a>(
               bcx: &'a Block<'a>,
               llfn: ValueRef,
               llargs: Vec<ValueRef> ,
-              attributes: &[(uint, lib::llvm::Attribute)],
+              fn_ty: ty::t,
               call_info: Option<NodeInfo>)
               -> (ValueRef, &'a Block<'a>) {
     let _icx = push_ctxt("invoke_");
@@ -919,6 +848,8 @@ pub fn invoke<'a>(
         return (C_null(Type::i8(bcx.ccx())), bcx);
     }
 
+    let attributes = get_fn_llvm_attributes(bcx.ccx(), fn_ty);
+
     match bcx.opt_node_id {
         None => {
             debug!("invoke at ???");
@@ -946,7 +877,7 @@ pub fn invoke<'a>(
                               llargs.as_slice(),
                               normal_bcx.llbb,
                               landing_pad,
-                              attributes);
+                              attributes.as_slice());
         return (llresult, normal_bcx);
     } else {
         debug!("calling {} at {}", llfn, bcx.llbb);
@@ -959,7 +890,7 @@ pub fn invoke<'a>(
             None => debuginfo::clear_source_location(bcx.fcx)
         };
 
-        let llresult = Call(bcx, llfn, llargs.as_slice(), attributes);
+        let llresult = Call(bcx, llfn, llargs.as_slice(), attributes.as_slice());
         return (llresult, bcx);
     }
 }
@@ -1728,34 +1659,132 @@ fn register_fn(ccx: &CrateContext,
                node_id: ast::NodeId,
                node_type: ty::t)
                -> ValueRef {
-    let f = match ty::get(node_type).sty {
+    match ty::get(node_type).sty {
         ty::ty_bare_fn(ref f) => {
             assert!(f.abi == Rust || f.abi == RustIntrinsic);
-            f
         }
         _ => fail!("expected bare rust fn or an intrinsic")
     };
 
-    let llfn = decl_rust_fn(ccx,
-                            false,
-                            f.sig.inputs.as_slice(),
-                            f.sig.output,
-                            sym.as_slice());
+    let llfn = decl_rust_fn(ccx, node_type, sym.as_slice());
     finish_register_fn(ccx, sp, sym, node_id, llfn);
     llfn
 }
 
+pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t) -> Vec<(uint, u64)> {
+    use middle::ty::{BrAnon, ReLateBound};
+
+    let (fn_sig, has_env) = match ty::get(fn_ty).sty {
+        ty::ty_closure(ref f) => (f.sig.clone(), true),
+        ty::ty_bare_fn(ref f) => (f.sig.clone(), false),
+        _ => fail!("expected closure or function.")
+    };
+
+    // Since index 0 is the return value of the llvm func, we start
+    // at either 1 or 2 depending on whether there's an env slot or not
+    let mut first_arg_offset = if has_env { 2 } else { 1 };
+    let mut attrs = Vec::new();
+    let ret_ty = fn_sig.output;
+
+    // A function pointer is called without the declaration
+    // available, so we have to apply any attributes with ABI
+    // implications directly to the call instruction. Right now,
+    // the only attribute we need to worry about is `sret`.
+    if type_of::return_uses_outptr(ccx, ret_ty) {
+        attrs.push((1, lib::llvm::StructRetAttribute as u64));
+
+        // The outptr can be noalias and nocapture because it's entirely
+        // invisible to the program. We can also mark it as nonnull
+        attrs.push((1, lib::llvm::NoAliasAttribute as u64));
+        attrs.push((1, lib::llvm::NoCaptureAttribute as u64));
+        attrs.push((1, lib::llvm::NonNullAttribute as u64));
+
+        // Add one more since there's an outptr
+        first_arg_offset += 1;
+    } else {
+        // The `noalias` attribute on the return value is useful to a
+        // function ptr caller.
+        match ty::get(ret_ty).sty {
+            // `~` pointer return values never alias because ownership
+            // is transferred
+            ty::ty_uniq(_) => {
+                attrs.push((lib::llvm::ReturnIndex as uint, lib::llvm::NoAliasAttribute as u64));
+            }
+            _ => {}
+        }
+
+        // We can also mark the return value as `nonnull` in certain cases
+        match ty::get(ret_ty).sty {
+            // These are not really pointers but pairs, (pointer, len)
+            ty::ty_rptr(_, ty::mt { ty: it, .. }) |
+            ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty {
+                ty::ty_str | ty::ty_vec(..) => true, _ => false
+            } => {}
+            ty::ty_uniq(_) | ty::ty_rptr(_, _) => {
+                attrs.push((lib::llvm::ReturnIndex as uint, lib::llvm::NonNullAttribute as u64));
+            }
+            _ => {}
+        }
+    }
+
+    for (idx, &t) in fn_sig.inputs.iter().enumerate().map(|(i, v)| (i + first_arg_offset, v)) {
+        match ty::get(t).sty {
+            // `~` pointer parameters never alias because ownership is transferred
+            ty::ty_uniq(_) => {
+                attrs.push((idx, lib::llvm::NoAliasAttribute as u64));
+                attrs.push((idx, lib::llvm::NonNullAttribute as u64));
+            }
+            // These are not really pointers but pairs, (pointer, len)
+            ty::ty_rptr(_, ty::mt { ty: it, .. }) |
+            ty::ty_rptr(_, ty::mt { ty: it, .. }) if match ty::get(it).sty {
+                ty::ty_str | ty::ty_vec(..) => true, _ => false
+            } => {}
+            // `&mut` pointer parameters never alias other parameters, or mutable global data
+            ty::ty_rptr(b, mt) if mt.mutbl == ast::MutMutable => {
+                attrs.push((idx, lib::llvm::NoAliasAttribute as u64));
+                attrs.push((idx, lib::llvm::NonNullAttribute as u64));
+                match b {
+                    ReLateBound(_, BrAnon(_)) => {
+                        attrs.push((idx, lib::llvm::NoCaptureAttribute as u64));
+                    }
+                    _ => {}
+                }
+            }
+            // When a reference in an argument has no named lifetime, it's impossible for that
+            // reference to escape this function (returned or stored beyond the call by a closure).
+            ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
+                attrs.push((idx, lib::llvm::NoCaptureAttribute as u64));
+                attrs.push((idx, lib::llvm::NonNullAttribute as u64));
+            }
+            // & pointer parameters are never null
+            ty::ty_rptr(_, _) => {
+                attrs.push((idx, lib::llvm::NonNullAttribute as u64));
+            }
+            _ => {
+                // For non-immediate arguments the callee gets its own copy of
+                // the value on the stack, so there are no aliases. It's also
+                // program-invisible so can't possibly capture
+                if !type_is_immediate(ccx, t) {
+                    attrs.push((idx, lib::llvm::NoAliasAttribute as u64));
+                    attrs.push((idx, lib::llvm::NoCaptureAttribute as u64));
+                }
+            }
+        }
+    }
+
+    attrs
+}
+
 // only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
 pub fn register_fn_llvmty(ccx: &CrateContext,
                           sp: Span,
                           sym: StrBuf,
                           node_id: ast::NodeId,
                           cc: lib::llvm::CallConv,
-                          fn_ty: Type,
-                          output: ty::t) -> ValueRef {
+                          llfty: Type) -> ValueRef {
     debug!("register_fn_llvmty id={} sym={}", node_id, sym);
 
-    let llfn = decl_fn(ccx.llmod, sym.as_slice(), cc, fn_ty, output);
+    let llfn = decl_fn(ccx.llmod, sym.as_slice(), cc, llfty, ty::mk_nil());
     finish_register_fn(ccx, sp, sym, node_id, llfn);
     llfn
 }
diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs
index bc4a2d9f96f..b0a73c4e6f7 100644
--- a/src/librustc/middle/trans/build.rs
+++ b/src/librustc/middle/trans/build.rs
@@ -113,7 +113,7 @@ pub fn Invoke(cx: &Block,
               args: &[ValueRef],
               then: BasicBlockRef,
               catch: BasicBlockRef,
-              attributes: &[(uint, lib::llvm::Attribute)])
+              attributes: &[(uint, u64)])
               -> ValueRef {
     if cx.unreachable.get() {
         return C_null(Type::i8(cx.ccx()));
@@ -679,13 +679,13 @@ pub fn InlineAsmCall(cx: &Block, asm: *c_char, cons: *c_char,
 }
 
 pub fn Call(cx: &Block, fn_: ValueRef, args: &[ValueRef],
-            attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
+            attributes: &[(uint, u64)]) -> ValueRef {
     if cx.unreachable.get() { return _UndefReturn(cx, fn_); }
     B(cx).call(fn_, args, attributes)
 }
 
 pub fn CallWithConv(cx: &Block, fn_: ValueRef, args: &[ValueRef], conv: CallConv,
-                    attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
+                    attributes: &[(uint, u64)]) -> ValueRef {
     if cx.unreachable.get() { return _UndefReturn(cx, fn_); }
     B(cx).call_with_conv(fn_, args, conv, attributes)
 }
diff --git a/src/librustc/middle/trans/builder.rs b/src/librustc/middle/trans/builder.rs
index f82a609d695..278e586c6ac 100644
--- a/src/librustc/middle/trans/builder.rs
+++ b/src/librustc/middle/trans/builder.rs
@@ -156,7 +156,7 @@ impl<'a> Builder<'a> {
                   args: &[ValueRef],
                   then: BasicBlockRef,
                   catch: BasicBlockRef,
-                  attributes: &[(uint, lib::llvm::Attribute)])
+                  attributes: &[(uint, u64)])
                   -> ValueRef {
         self.count_insn("invoke");
         unsafe {
@@ -168,7 +168,7 @@ impl<'a> Builder<'a> {
                                           catch,
                                           noname());
             for &(idx, attr) in attributes.iter() {
-                llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint);
+                llvm::LLVMAddCallSiteAttribute(v, idx as c_uint, attr);
             }
             v
         }
@@ -799,7 +799,7 @@ impl<'a> Builder<'a> {
     }
 
     pub fn call(&self, llfn: ValueRef, args: &[ValueRef],
-                attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
+                attributes: &[(uint, u64)]) -> ValueRef {
         self.count_insn("call");
 
         debug!("Call {} with args ({})",
@@ -813,14 +813,14 @@ impl<'a> Builder<'a> {
             let v = llvm::LLVMBuildCall(self.llbuilder, llfn, args.as_ptr(),
                                         args.len() as c_uint, noname());
             for &(idx, attr) in attributes.iter() {
-                llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint);
+                llvm::LLVMAddCallSiteAttribute(v, idx as c_uint, attr);
             }
             v
         }
     }
 
     pub fn call_with_conv(&self, llfn: ValueRef, args: &[ValueRef],
-                          conv: CallConv, attributes: &[(uint, lib::llvm::Attribute)]) -> ValueRef {
+                          conv: CallConv, attributes: &[(uint, u64)]) -> ValueRef {
         self.count_insn("callwithconv");
         let v = self.call(llfn, args, attributes);
         lib::llvm::SetInstructionCallConv(v, conv);
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index fe9581c638e..90600ea2d3b 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -18,7 +18,7 @@
 
 use back::abi;
 use driver::session;
-use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute, NoCaptureAttribute};
+use lib::llvm::ValueRef;
 use lib::llvm::llvm;
 use metadata::csearch;
 use middle::trans::base;
@@ -614,13 +614,9 @@ pub fn trans_call_inner<'a>(
             llargs.push(opt_llretslot.unwrap());
         }
 
-        // start at 1, because index 0 is the return value of the llvm func
-        let mut first_arg_offset = 1;
-
         // Push the environment (or a trait object's self).
         match (llenv, llself) {
             (Some(llenv), None) => {
-                first_arg_offset += 1;
                 llargs.push(llenv)
             },
             (None, Some(llself)) => llargs.push(llself),
@@ -634,61 +630,11 @@ pub fn trans_call_inner<'a>(
 
         fcx.pop_custom_cleanup_scope(arg_cleanup_scope);
 
-        // A function pointer is called without the declaration
-        // available, so we have to apply any attributes with ABI
-        // implications directly to the call instruction. Right now,
-        // the only attribute we need to worry about is `sret`.
-        let mut attrs = Vec::new();
-        if type_of::return_uses_outptr(ccx, ret_ty) {
-            attrs.push((1, StructRetAttribute));
-            // The outptr can be noalias and nocapture because it's entirely
-            // invisible to the program.
-            attrs.push((1, NoAliasAttribute));
-            attrs.push((1, NoCaptureAttribute));
-            first_arg_offset += 1;
-        }
-
-        // The `noalias` attribute on the return value is useful to a
-        // function ptr caller.
-        match ty::get(ret_ty).sty {
-            // `~` pointer return values never alias because ownership
-            // is transferred
-            ty::ty_uniq(ty) => match ty::get(ty).sty {
-                ty::ty_str => {}
-                _ => attrs.push((0, NoAliasAttribute)),
-            },
-            _ => {}
-        }
-
-        debug!("trans_callee_inner: first_arg_offset={}", first_arg_offset);
-
-        for (idx, &t) in ty::ty_fn_args(callee_ty).iter().enumerate()
-                                                  .map(|(i, v)| (i+first_arg_offset, v)) {
-            use middle::ty::{BrAnon, ReLateBound};
-            if !type_is_immediate(ccx, t) {
-                // if it's not immediate, we have a program-invisible pointer,
-                // which it can't possibly capture
-                attrs.push((idx, NoCaptureAttribute));
-                debug!("trans_callee_inner: argument {} nocapture because it's non-immediate", idx);
-                continue;
-            }
-
-            let t_ = ty::get(t);
-            match t_.sty {
-                ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
-                    debug!("trans_callee_inner: argument {} nocapture because \
-                           of anonymous lifetime", idx);
-                    attrs.push((idx, NoCaptureAttribute));
-                },
-                _ => { }
-            }
-        }
-
         // Invoke the actual rust fn and update bcx/llresult.
         let (llret, b) = base::invoke(bcx,
                                       llfn,
                                       llargs,
-                                      attrs.as_slice(),
+                                      callee_ty,
                                       call_info);
         bcx = b;
         llresult = llret;
diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs
index c804cb77fb2..5fe6c234579 100644
--- a/src/librustc/middle/trans/closure.rs
+++ b/src/librustc/middle/trans/closure.rs
@@ -340,21 +340,12 @@ pub fn trans_expr_fn<'a>(
     };
 
     let ccx = bcx.ccx();
-    let fty = node_id_type(bcx, id);
-    let f = match ty::get(fty).sty {
-        ty::ty_closure(ref f) => f,
-        _ => fail!("expected closure")
-    };
-
     let tcx = bcx.tcx();
+    let fty = node_id_type(bcx, id);
     let s = tcx.map.with_path(id, |path| {
         mangle_internal_name_by_path_and_seq(path, "closure")
     });
-    let llfn = decl_internal_rust_fn(ccx,
-                                     true,
-                                     f.sig.inputs.as_slice(),
-                                     f.sig.output,
-                                     s.as_slice());
+    let llfn = decl_internal_rust_fn(ccx, fty, s.as_slice());
 
     // set an inline hint for all closures
     set_inline_hint(llfn);
@@ -414,17 +405,9 @@ pub fn get_wrapper_for_bare_fn(ccx: &CrateContext,
         mangle_internal_name_by_path_and_seq(path, "as_closure")
     });
     let llfn = if is_local {
-        decl_internal_rust_fn(ccx,
-                              true,
-                              f.sig.inputs.as_slice(),
-                              f.sig.output,
-                              name.as_slice())
+        decl_internal_rust_fn(ccx, closure_ty, name.as_slice())
     } else {
-        decl_rust_fn(ccx,
-                     true,
-                     f.sig.inputs.as_slice(),
-                     f.sig.output,
-                     name.as_slice())
+        decl_rust_fn(ccx, closure_ty, name.as_slice())
     };
 
     ccx.closure_bare_wrapper_cache.borrow_mut().insert(fn_ptr, llfn);
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index e08ab33808a..f723a4556b9 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -227,12 +227,12 @@ pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi, fty: ty::t,
     // Create the LLVM value for the C extern fn
     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
 
-    let llfn = base::get_extern_fn(&mut *ccx.externs.borrow_mut(),
-                                   ccx.llmod,
+    let llfn = base::get_extern_fn(ccx,
+                                   &mut *ccx.externs.borrow_mut(),
                                    name,
                                    cc,
                                    llfn_ty,
-                                   tys.fn_sig.output);
+                                   fty);
     add_argument_attributes(&tys, llfn);
 
     llfn
@@ -378,17 +378,21 @@ pub fn trans_native_call<'a>(
     // A function pointer is called without the declaration available, so we have to apply
     // any attributes with ABI implications directly to the call instruction. Right now, the
     // only attribute we need to worry about is `sret`.
-    let sret_attr = if fn_type.ret_ty.is_indirect() {
-        Some((1, StructRetAttribute))
-    } else {
-        None
+    let mut attrs = Vec::new();
+    if fn_type.ret_ty.is_indirect() {
+        attrs.push((1, lib::llvm::StructRetAttribute as u64));
+
+        // The outptr can be noalias and nocapture because it's entirely
+        // invisible to the program. We can also mark it as nonnull
+        attrs.push((1, lib::llvm::NoAliasAttribute as u64));
+        attrs.push((1, lib::llvm::NoCaptureAttribute as u64));
+        attrs.push((1, lib::llvm::NonNullAttribute as u64));
     };
-    let attrs = sret_attr.as_slice();
     let llforeign_retval = CallWithConv(bcx,
                                         llfn,
                                         llargs_foreign.as_slice(),
                                         cc,
-                                        attrs);
+                                        attrs.as_slice());
 
     // If the function we just called does not use an outpointer,
     // store the result into the rust outpointer. Cast the outpointer
@@ -500,14 +504,14 @@ pub fn register_rust_fn_with_foreign_abi(ccx: &CrateContext,
     let tys = foreign_types_for_id(ccx, node_id);
     let llfn_ty = lltype_for_fn_from_foreign_types(ccx, &tys);
     let t = ty::node_id_to_type(ccx.tcx(), node_id);
-    let (cconv, output) = match ty::get(t).sty {
+    let cconv = match ty::get(t).sty {
         ty::ty_bare_fn(ref fn_ty) => {
             let c = llvm_calling_convention(ccx, fn_ty.abi);
-            (c.unwrap_or(lib::llvm::CCallConv), fn_ty.sig.output)
+            c.unwrap_or(lib::llvm::CCallConv)
         }
         _ => fail!("expected bare fn in register_rust_fn_with_foreign_abi")
     };
-    let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty, output);
+    let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, cconv, llfn_ty);
     add_argument_attributes(&tys, llfn);
     debug!("register_rust_fn_with_foreign_abi(node_id={:?}, llfn_ty={}, llfn={})",
            node_id, ccx.tn.type_to_str(llfn_ty), ccx.tn.val_to_str(llfn));
@@ -528,7 +532,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
         let llrustfn = build_rust_fn(ccx, decl, body, attrs, id);
 
         // Build up the foreign wrapper (`foo` above).
-        return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys);
+        return build_wrap_fn(ccx, llrustfn, llwrapfn, &tys, id);
     }
 
     fn build_rust_fn(ccx: &CrateContext,
@@ -548,10 +552,9 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
 
         // Compute the type that the function would have if it were just a
         // normal Rust function. This will be the type of the wrappee fn.
-        let f = match ty::get(t).sty {
+        match ty::get(t).sty {
             ty::ty_bare_fn(ref f) => {
                 assert!(f.abi != Rust && f.abi != RustIntrinsic);
-                f
             }
             _ => {
                 ccx.sess().bug(format!("build_rust_fn: extern fn {} has ty {}, \
@@ -565,11 +568,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
                ccx.tcx.map.path_to_str(id),
                id, t.repr(tcx));
 
-        let llfn = base::decl_internal_rust_fn(ccx,
-                                               false,
-                                               f.sig.inputs.as_slice(),
-                                               f.sig.output,
-                                               ps.as_slice());
+        let llfn = base::decl_internal_rust_fn(ccx, t, ps.as_slice());
         base::set_llvm_fn_attrs(attrs, llfn);
         base::trans_fn(ccx, decl, body, llfn, None, id, []);
         llfn
@@ -578,14 +577,18 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
     unsafe fn build_wrap_fn(ccx: &CrateContext,
                             llrustfn: ValueRef,
                             llwrapfn: ValueRef,
-                            tys: &ForeignTypes) {
+                            tys: &ForeignTypes,
+                            id: ast::NodeId) {
         let _icx = push_ctxt(
             "foreign::trans_rust_fn_with_foreign_abi::build_wrap_fn");
         let tcx = ccx.tcx();
 
-        debug!("build_wrap_fn(llrustfn={}, llwrapfn={})",
+        let t = ty::node_id_to_type(tcx, id);
+
+        debug!("build_wrap_fn(llrustfn={}, llwrapfn={}, t={})",
                ccx.tn.val_to_str(llrustfn),
-               ccx.tn.val_to_str(llwrapfn));
+               ccx.tn.val_to_str(llwrapfn),
+               t.repr(ccx.tcx()));
 
         // Avoid all the Rust generation stuff and just generate raw
         // LLVM here.
@@ -731,10 +734,15 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: &CrateContext,
         }
 
         // Perform the call itself
-        debug!("calling llrustfn = {}", ccx.tn.val_to_str(llrustfn));
+        debug!("calling llrustfn = {}, t = {}", ccx.tn.val_to_str(llrustfn), t.repr(ccx.tcx()));
         let llrust_ret_val = llvm::LLVMBuildCall(builder, llrustfn, llrust_args.as_ptr(),
                                                  llrust_args.len() as c_uint, noname());
 
+        let attributes = base::get_fn_llvm_attributes(ccx, t);
+        for &(idx, attr) in attributes.iter() {
+            llvm::LLVMAddCallSiteAttribute(llrust_ret_val, idx as c_uint, attr);
+        }
+
         // Get the return value where the foreign fn expects it.
         let llforeign_ret_ty = match tys.fn_ty.ret_ty.cast {
             Some(ty) => ty,
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index c103a44aa75..6d269756931 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -88,7 +88,7 @@ pub fn take_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
     }
 }
 
-fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
+pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
     let tcx = ccx.tcx();
     if !ty::type_needs_drop(tcx, t) {
         return ty::mk_i8();
@@ -248,7 +248,7 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
     let repr = adt::represent_type(bcx.ccx(), t);
 
     // Find and call the actual destructor
-    let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did,
+    let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t,
                                  class_did, substs);
 
     // The second argument is the "self" argument for drop
@@ -279,7 +279,9 @@ fn trans_struct_drop<'a>(bcx: &'a Block<'a>,
                                   fld.mt.ty);
     }
 
-    let (_, bcx) = invoke(bcx, dtor_addr, args, [], None);
+    let dtor_ty = ty::mk_ctor_fn(bcx.tcx(), ast::DUMMY_NODE_ID,
+                                 [get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil());
+    let (_, bcx) = invoke(bcx, dtor_addr, args, dtor_ty, None);
 
     bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, field_scope)
 }
@@ -459,10 +461,7 @@ fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type,
         t,
         format!("glue_{}", name).as_slice());
     debug!("{} is for type {}", fn_nm, ppaux::ty_to_str(ccx.tcx(), t));
-    let llfn = decl_cdecl_fn(ccx.llmod,
-                             fn_nm.as_slice(),
-                             llfnty,
-                             ty::mk_nil());
+    let llfn = decl_cdecl_fn(ccx.llmod, fn_nm.as_slice(), llfnty, ty::mk_nil());
     note_unique_llvm_symbol(ccx, fn_nm);
     return llfn;
 }
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index 3076a19228c..e0fd872fb06 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -172,14 +172,6 @@ pub fn monomorphic_fn(ccx: &CrateContext,
         }
     };
 
-    let f = match ty::get(mono_ty).sty {
-        ty::ty_bare_fn(ref f) => {
-            assert!(f.abi == abi::Rust || f.abi == abi::RustIntrinsic);
-            f
-        }
-        _ => fail!("expected bare rust fn or an intrinsic")
-    };
-
     ccx.stats.n_monos.set(ccx.stats.n_monos.get() + 1);
 
     let depth;
@@ -214,11 +206,7 @@ pub fn monomorphic_fn(ccx: &CrateContext,
     // This shouldn't need to option dance.
     let mut hash_id = Some(hash_id);
     let mk_lldecl = || {
-        let lldecl = decl_internal_rust_fn(ccx,
-                                           false,
-                                           f.sig.inputs.as_slice(),
-                                           f.sig.output,
-                                           s.as_slice());
+        let lldecl = decl_internal_rust_fn(ccx, mono_ty, s.as_slice());
         ccx.monomorphized.borrow_mut().insert(hash_id.take_unwrap(), lldecl);
         lldecl
     };
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index a65802d2c36..f5f3d4366f6 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -291,10 +291,10 @@ impl<'a, 'b> Reflector<'a, 'b> {
                 let sym = mangle_internal_name_by_path_and_seq(
                     ast_map::Values([].iter()).chain(None), "get_disr");
 
+                let fn_ty = ty::mk_ctor_fn(&ccx.tcx, ast::DUMMY_NODE_ID,
+                                           [opaqueptrty], ty::mk_u64());
                 let llfdecl = decl_internal_rust_fn(ccx,
-                                                    false,
-                                                    [opaqueptrty],
-                                                    ty::mk_u64(),
+                                                    fn_ty,
                                                     sym.as_slice());
                 let arena = TypedArena::new();
                 let fcx = new_fn_ctxt(ccx, llfdecl, -1, false,
diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp
index 3661d152d59..2157aecf376 100644
--- a/src/rustllvm/RustWrapper.cpp
+++ b/src/rustllvm/RustWrapper.cpp
@@ -12,6 +12,12 @@
 #include "llvm/Object/Archive.h"
 #include "llvm/Object/ObjectFile.h"
 
+#if LLVM_VERSION_MINOR >= 5
+#include "llvm/IR/CallSite.h"
+#else
+#include "llvm/Support/CallSite.h"
+#endif
+
 //===----------------------------------------------------------------------===
 //
 // This file defines alternate interfaces to core functions that are more
@@ -83,58 +89,43 @@ extern "C" LLVMTypeRef LLVMMetadataTypeInContext(LLVMContextRef C) {
   return wrap(Type::getMetadataTy(*unwrap(C)));
 }
 
-extern "C" void LLVMAddFunctionAttrString(LLVMValueRef fn, const char *Name) {
-  unwrap<Function>(fn)->addFnAttr(Name);
+extern "C" void LLVMAddCallSiteAttribute(LLVMValueRef Instr, unsigned index, uint64_t Val) {
+  CallSite Call = CallSite(unwrap<Instruction>(Instr));
+  AttrBuilder B;
+  B.addRawValue(Val);
+  Call.setAttributes(
+    Call.getAttributes().addAttributes(Call->getContext(), index,
+                                       AttributeSet::get(Call->getContext(),
+                                                         index, B)));
 }
 
-extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, const char *Name) {
+extern "C" void LLVMAddFunctionAttribute(LLVMValueRef Fn, unsigned index, uint64_t Val) {
+  Function *A = unwrap<Function>(Fn);
+  AttrBuilder B;
+  B.addRawValue(Val);
+  A->addAttributes(index, AttributeSet::get(A->getContext(), index, B));
+}
+
+extern "C" void LLVMAddFunctionAttrString(LLVMValueRef Fn, unsigned index, const char *Name) {
+  Function *F = unwrap<Function>(Fn);
+  AttrBuilder B;
+  B.addAttribute(Name);
+  F->addAttributes(index, AttributeSet::get(F->getContext(), index, B));
+}
+
+extern "C" void LLVMRemoveFunctionAttrString(LLVMValueRef fn, unsigned index, const char *Name) {
   Function *f = unwrap<Function>(fn);
   LLVMContext &C = f->getContext();
   AttrBuilder B;
   B.addAttribute(Name);
-  AttributeSet to_remove = AttributeSet::get(C, AttributeSet::FunctionIndex, B);
+  AttributeSet to_remove = AttributeSet::get(C, index, B);
 
   AttributeSet attrs = f->getAttributes();
   f->setAttributes(attrs.removeAttributes(f->getContext(),
-                                          AttributeSet::FunctionIndex,
+                                          index,
                                           to_remove));
 }
 
-extern "C" void LLVMAddReturnAttribute(LLVMValueRef Fn, LLVMAttribute PA) {
-  Function *A = unwrap<Function>(Fn);
-  AttrBuilder B(PA);
-  A->addAttributes(AttributeSet::ReturnIndex,
-                   AttributeSet::get(A->getContext(), AttributeSet::ReturnIndex,  B));
-}
-
-extern "C" void LLVMRemoveReturnAttribute(LLVMValueRef Fn, LLVMAttribute PA) {
-  Function *A = unwrap<Function>(Fn);
-  AttrBuilder B(PA);
-  A->removeAttributes(AttributeSet::ReturnIndex,
-                      AttributeSet::get(A->getContext(), AttributeSet::ReturnIndex,  B));
-}
-
-#if LLVM_VERSION_MINOR >= 5
-extern "C" void LLVMAddColdAttribute(LLVMValueRef Fn) {
-  Function *A = unwrap<Function>(Fn);
-  A->addAttribute(AttributeSet::FunctionIndex, Attribute::Cold);
-}
-
-extern "C" void LLVMAddNonNullAttribute(LLVMValueRef Arg) {
-  Argument *A = unwrap<Argument>(Arg);
-  A->addAttr(AttributeSet::get(A->getContext(), A->getArgNo() + 1, Attribute::NonNull));
-}
-
-extern "C" void LLVMAddNonNullReturnAttribute(LLVMValueRef Fn) {
-  Function *A = unwrap<Function>(Fn);
-  A->addAttribute(AttributeSet::ReturnIndex, Attribute::NonNull);
-}
-#else
-extern "C" void LLVMAddColdAttribute(LLVMValueRef Fn) {}
-extern "C" void LLVMAddNonNullAttribute(LLVMValueRef Arg) {}
-extern "C" void LLVMAddNonNullReturnAttribute(LLVMValueRef Fn) {}
-#endif
-
 extern "C" LLVMValueRef LLVMBuildAtomicLoad(LLVMBuilderRef B,
                                             LLVMValueRef source,
                                             const char* Name,