about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/trans/base.rs171
-rw-r--r--src/librustc/middle/trans/build.rs13
-rw-r--r--src/librustc/middle/trans/builder.rs31
-rw-r--r--src/librustc/middle/trans/callee.rs22
-rw-r--r--src/librustc/middle/trans/closure.rs8
-rw-r--r--src/librustc/middle/trans/foreign.rs22
-rw-r--r--src/librustc/middle/trans/monomorphize.rs14
-rw-r--r--src/librustc/middle/trans/reflect.rs3
8 files changed, 172 insertions, 112 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index f0238e8f5c5..e8c2388a383 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -174,6 +174,7 @@ impl<'self> Drop for StatRecorder<'self> {
     }
 }
 
+// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
 pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
     let llfn: ValueRef = do name.with_c_str |buf| {
         unsafe {
@@ -185,18 +186,12 @@ pub fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv, ty: Type)
     return llfn;
 }
 
+// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
 pub fn decl_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
     return decl_fn(llmod, name, lib::llvm::CCallConv, ty);
 }
 
-// Only use this if you are going to actually define the function. It's
-// not valid to simply declare a function as internal.
-pub fn decl_internal_cdecl_fn(llmod: ModuleRef, name: &str, ty: Type) -> ValueRef {
-    let llfn = decl_cdecl_fn(llmod, name, ty);
-    lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
-    return llfn;
-}
-
+// 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, name: &str,
                      cc: lib::llvm::CallConv, ty: Type) -> ValueRef {
     match externs.find_equiv(&name) {
@@ -205,7 +200,73 @@ pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef, name: &str,
     }
     let f = decl_fn(llmod, name, cc, ty);
     externs.insert(name.to_owned(), f);
-    return f;
+    f
+}
+
+pub fn get_extern_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+                          name: &str) -> ValueRef {
+    match ccx.externs.find_equiv(&name) {
+        Some(n) => return *n,
+        None => ()
+    }
+    let f = decl_rust_fn(ccx, inputs, output, name);
+    ccx.externs.insert(name.to_owned(), f);
+    f
+}
+
+pub fn decl_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+                    name: &str) -> ValueRef {
+    let llfty = type_of_rust_fn(ccx, inputs, output);
+    let llfn = decl_cdecl_fn(ccx.llmod, name, llfty);
+
+    match ty::get(output).sty {
+        // `~` pointer return values never alias because ownership is transferred
+        ty::ty_uniq(*) |
+        ty::ty_evec(_, ty::vstore_uniq) => {
+            unsafe {
+                llvm::LLVMAddReturnAttribute(llfn, lib::llvm::NoAliasAttribute as c_uint);
+            }
+        }
+        _ => ()
+    }
+
+    let uses_outptr = type_of::return_uses_outptr(ccx.tcx, output);
+    let offset = if uses_outptr { 2 } else { 1 };
+
+    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(*) |
+            ty::ty_evec(_, ty::vstore_uniq) |
+            ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
+                unsafe {
+                    llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
+                }
+            }
+            _ => ()
+        }
+    }
+
+    // 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.
+    if uses_outptr {
+        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);
+        }
+    }
+
+    llfn
+}
+
+pub fn decl_internal_rust_fn(ccx: &mut CrateContext, inputs: &[ty::t], output: ty::t,
+                             name: &str) -> ValueRef {
+    let llfn = decl_rust_fn(ccx, inputs, output, name);
+    lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
+    llfn
 }
 
 pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
@@ -809,33 +870,30 @@ pub fn null_env_ptr(ccx: &CrateContext) -> ValueRef {
     C_null(Type::opaque_box(ccx).ptr_to())
 }
 
-pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t)
-    -> ValueRef {
+pub fn trans_external_path(ccx: &mut CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
     let name = csearch::get_symbol(ccx.sess.cstore, did);
     match ty::get(t).sty {
         ty::ty_bare_fn(ref fn_ty) => {
-            // Currently llvm_calling_convention triggers unimpl/bug on
-            // Rust/RustIntrinsic, so those two are handled specially here.
-            let cconv = match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
-                Some(Rust) | Some(RustIntrinsic) => lib::llvm::CCallConv,
+            match fn_ty.abis.for_arch(ccx.sess.targ_cfg.arch) {
+                Some(Rust) | Some(RustIntrinsic) => {
+                    get_extern_rust_fn(ccx, fn_ty.sig.inputs, fn_ty.sig.output, name)
+                }
                 Some(*) | None => {
                     let c = foreign::llvm_calling_convention(ccx, fn_ty.abis);
-                    c.unwrap_or(lib::llvm::CCallConv)
+                    let cconv = c.unwrap_or(lib::llvm::CCallConv);
+                    let llty = type_of_fn_from_ty(ccx, t);
+                    get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty)
                 }
-            };
-            let llty = type_of_fn_from_ty(ccx, t);
-            return get_extern_fn(&mut ccx.externs, ccx.llmod, name, cconv, llty);
+            }
         }
-        ty::ty_closure(_) => {
-            let llty = type_of_fn_from_ty(ccx, t);
-            return get_extern_fn(&mut ccx.externs, ccx.llmod, name,
-            lib::llvm::CCallConv, llty);
+        ty::ty_closure(ref f) => {
+            get_extern_rust_fn(ccx, f.sig.inputs, f.sig.output, name)
         }
         _ => {
             let llty = type_of(ccx, t);
-            return get_extern_const(&mut ccx.externs, ccx.llmod, name, llty);
+            get_extern_const(&mut ccx.externs, ccx.llmod, name, llty)
         }
-    };
+    }
 }
 
 pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
@@ -868,7 +926,8 @@ pub fn invoke(bcx: @mut Block, llfn: ValueRef, llargs: ~[ValueRef],
                               llfn,
                               llargs,
                               normal_bcx.llbb,
-                              get_landing_pad(bcx));
+                              get_landing_pad(bcx),
+                              attributes);
         return (llresult, normal_bcx);
     } else {
         unsafe {
@@ -1707,8 +1766,7 @@ pub fn new_fn_ctxt(ccx: @mut CrateContext,
 // field of the fn_ctxt with
 pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
                                  self_arg: self_arg,
-                                 args: &[ast::arg],
-                                 arg_tys: &[ty::t])
+                                 args: &[ast::arg])
                               -> ~[ValueRef] {
     let _icx = push_ctxt("create_llargs_for_fn_args");
 
@@ -1726,23 +1784,7 @@ pub fn create_llargs_for_fn_args(cx: @mut FunctionContext,
     // Return an array containing the ValueRefs that we get from
     // llvm::LLVMGetParam for each argument.
     do vec::from_fn(args.len()) |i| {
-        let arg_n = cx.arg_pos(i);
-        let arg_ty = arg_tys[i];
-        let llarg = unsafe {llvm::LLVMGetParam(cx.llfn, arg_n as c_uint) };
-
-        match ty::get(arg_ty).sty {
-            // `~` pointer parameters never alias because ownership is transferred
-            ty::ty_uniq(*) |
-            ty::ty_evec(_, ty::vstore_uniq) |
-            ty::ty_closure(ty::ClosureTy {sigil: ast::OwnedSigil, _}) => {
-                unsafe {
-                    llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
-                }
-            }
-            _ => ()
-        }
-
-        llarg
+        unsafe { llvm::LLVMGetParam(cx.llfn, cx.arg_pos(i) as c_uint) }
     }
 }
 
@@ -1896,8 +1938,7 @@ pub fn trans_closure(ccx: @mut CrateContext,
 
     // Set up arguments to the function.
     let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
-    let raw_llargs = create_llargs_for_fn_args(fcx, self_arg,
-                                               decl.inputs, arg_tys);
+    let raw_llargs = create_llargs_for_fn_args(fcx, self_arg, decl.inputs);
 
     // Set the fixed stack segment flag if necessary.
     if attr::contains_name(attributes, "fixed_stack_segment") {
@@ -1961,18 +2002,6 @@ pub fn trans_fn(ccx: @mut CrateContext,
            param_substs.repr(ccx.tcx));
     let _icx = push_ctxt("trans_fn");
     let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx, id));
-
-    match ty::get(output_type).sty {
-        // `~` pointer return values never alias because ownership is transferred
-        ty::ty_uniq(*) |
-        ty::ty_evec(_, ty::vstore_uniq) => {
-            unsafe {
-                llvm::LLVMAddReturnAttribute(llfndecl, lib::llvm::NoAliasAttribute as c_uint);
-            }
-        }
-        _ => ()
-    }
-
     trans_closure(ccx,
                   path.clone(),
                   decl,
@@ -2120,7 +2149,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
 
     let arg_tys = ty::ty_fn_args(ctor_ty);
 
-    let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args, arg_tys);
+    let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
 
     let bcx = fcx.entry_bcx.unwrap();
 
@@ -2298,10 +2327,28 @@ pub fn register_fn(ccx: @mut CrateContext,
                    node_id: ast::NodeId,
                    node_type: ty::t)
                    -> ValueRef {
-    let llfty = type_of_fn_from_ty(ccx, node_type);
-    register_fn_llvmty(ccx, sp, sym, node_id, lib::llvm::CCallConv, llfty)
+    let f = match ty::get(node_type).sty {
+        ty::ty_bare_fn(ref f) => {
+            assert!(f.abis.is_rust() || f.abis.is_intrinsic());
+            f
+        }
+        _ => fail!("expected bare rust fn or an intrinsic")
+    };
+
+    let llfn = decl_rust_fn(ccx, f.sig.inputs, f.sig.output, sym);
+    ccx.item_symbols.insert(node_id, sym);
+
+    // FIXME #4404 android JNI hacks
+    let is_entry = is_entry_fn(&ccx.sess, node_id) && (!*ccx.sess.building_library ||
+                      (*ccx.sess.building_library &&
+                       ccx.sess.targ_cfg.os == session::OsAndroid));
+    if is_entry {
+        create_entry_wrapper(ccx, sp, llfn);
+    }
+    llfn
 }
 
+// only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
 pub fn register_fn_llvmty(ccx: @mut CrateContext,
                           sp: Span,
                           sym: ~str,
diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs
index aabb389dde1..4b03a2cac4b 100644
--- a/src/librustc/middle/trans/build.rs
+++ b/src/librustc/middle/trans/build.rs
@@ -109,7 +109,8 @@ pub fn Invoke(cx: @mut Block,
               Fn: ValueRef,
               Args: &[ValueRef],
               Then: BasicBlockRef,
-              Catch: BasicBlockRef)
+              Catch: BasicBlockRef,
+              attributes: &[(uint, lib::llvm::Attribute)])
            -> ValueRef {
     if cx.unreachable {
         return C_null(Type::i8());
@@ -119,15 +120,7 @@ pub fn Invoke(cx: @mut Block,
     debug!("Invoke(%s with arguments (%s))",
            cx.val_to_str(Fn),
            Args.map(|a| cx.val_to_str(*a)).connect(", "));
-    B(cx).invoke(Fn, Args, Then, Catch)
-}
-
-pub fn FastInvoke(cx: @mut Block, Fn: ValueRef, Args: &[ValueRef],
-                  Then: BasicBlockRef, Catch: BasicBlockRef) {
-    if cx.unreachable { return; }
-    check_not_terminated(cx);
-    terminate(cx, "FastInvoke");
-    B(cx).fast_invoke(Fn, Args, Then, Catch);
+    B(cx).invoke(Fn, Args, Then, Catch, attributes)
 }
 
 pub fn Unreachable(cx: @mut Block) {
diff --git a/src/librustc/middle/trans/builder.rs b/src/librustc/middle/trans/builder.rs
index 85e45942b79..d7a4dbb3510 100644
--- a/src/librustc/middle/trans/builder.rs
+++ b/src/librustc/middle/trans/builder.rs
@@ -154,30 +154,25 @@ impl Builder {
                   llfn: ValueRef,
                   args: &[ValueRef],
                   then: BasicBlockRef,
-                  catch: BasicBlockRef)
+                  catch: BasicBlockRef,
+                  attributes: &[(uint, lib::llvm::Attribute)])
                   -> ValueRef {
         self.count_insn("invoke");
         unsafe {
-            llvm::LLVMBuildInvoke(self.llbuilder,
-                                  llfn,
-                                  vec::raw::to_ptr(args),
-                                  args.len() as c_uint,
-                                  then,
-                                  catch,
-                                  noname())
+            let v = llvm::LLVMBuildInvoke(self.llbuilder,
+                                          llfn,
+                                          vec::raw::to_ptr(args),
+                                          args.len() as c_uint,
+                                          then,
+                                          catch,
+                                          noname());
+            for &(idx, attr) in attributes.iter() {
+                llvm::LLVMAddInstrAttribute(v, idx as c_uint, attr as c_uint);
+            }
+            v
         }
     }
 
-    pub fn fast_invoke(&self,
-                       llfn: ValueRef,
-                       args: &[ValueRef],
-                       then: BasicBlockRef,
-                       catch: BasicBlockRef) {
-        self.count_insn("fastinvoke");
-        let v = self.invoke(llfn, args, then, catch);
-        lib::llvm::SetInstructionCallConv(v, lib::llvm::FastCallConv);
-    }
-
     pub fn unreachable(&self) {
         self.count_insn("unreachable");
         unsafe {
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index 45da026afd0..54c905a4c16 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -20,7 +20,7 @@ use std::vec;
 
 use back::abi;
 use driver::session;
-use lib::llvm::ValueRef;
+use lib::llvm::{ValueRef, NoAliasAttribute, StructRetAttribute};
 use lib::llvm::llvm;
 use metadata::csearch;
 use middle::trans::base;
@@ -706,8 +706,26 @@ pub fn trans_call_inner(in_cx: @mut Block,
                 _ => {}
             }
 
+            // 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 = ~[];
+            if type_of::return_uses_outptr(in_cx.tcx(), ret_ty) {
+                attrs.push((1, StructRetAttribute));
+            }
+
+            // 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::ty_evec(_, ty::vstore_uniq) => {
+                    attrs.push((0, NoAliasAttribute));
+                }
+                _ => ()
+            }
+
             // Invoke the actual rust fn and update bcx/llresult.
-            let (llret, b) = base::invoke(bcx, llfn, llargs, []);
+            let (llret, b) = base::invoke(bcx, llfn, llargs, attrs);
             bcx = b;
             llresult = llret;
 
diff --git a/src/librustc/middle/trans/closure.rs b/src/librustc/middle/trans/closure.rs
index 690d7343489..605032dc20c 100644
--- a/src/librustc/middle/trans/closure.rs
+++ b/src/librustc/middle/trans/closure.rs
@@ -381,8 +381,10 @@ pub fn trans_expr_fn(bcx: @mut Block,
 
     let ccx = bcx.ccx();
     let fty = node_id_type(bcx, outer_id);
-
-    let llfnty = type_of_fn_from_ty(ccx, fty);
+    let f = match ty::get(fty).sty {
+        ty::ty_closure(ref f) => f,
+        _ => fail!("expected closure")
+    };
 
     let sub_path = vec::append_one(bcx.fcx.path.clone(),
                                    path_name(special_idents::anon));
@@ -390,7 +392,7 @@ pub fn trans_expr_fn(bcx: @mut Block,
     let s = mangle_internal_name_by_path_and_seq(ccx,
                                                  sub_path.clone(),
                                                  "expr_fn");
-    let llfn = decl_internal_cdecl_fn(ccx.llmod, s, llfnty);
+    let llfn = decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, s);
 
     // set an inline hint for all closures
     set_inline_hint(llfn);
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 1ebe402bbb9..b00d77d72dd 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -21,7 +21,6 @@ use middle::trans::cabi;
 use middle::trans::build::*;
 use middle::trans::builder::noname;
 use middle::trans::common::*;
-use middle::trans::llrepr::LlvmRepr;
 use middle::trans::type_of::*;
 use middle::trans::type_of;
 use middle::ty;
@@ -265,6 +264,9 @@ pub fn trans_native_call(bcx: @mut Block,
         }
     };
 
+    // 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 attrs;
     if fn_type.sret {
         attrs = &[(1, StructRetAttribute)];
@@ -406,13 +408,12 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
                 special_idents::clownshoe_abi
             )));
 
-        // Compute the LLVM type that the function would have if it
-        // were just a normal Rust function. This will be the type of
-        // the wrappee fn.
-        let llty = match ty::get(t).sty {
+        // 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 {
             ty::ty_bare_fn(ref f) => {
                 assert!(!f.abis.is_rust() && !f.abis.is_intrinsic());
-                type_of_rust_fn(ccx, f.sig.inputs, f.sig.output)
+                f
             }
             _ => {
                 ccx.sess.bug(fmt!("build_rust_fn: extern fn %s has ty %s, \
@@ -422,13 +423,12 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
             }
         };
 
-        debug!("build_rust_fn: path=%s id=%? t=%s llty=%s",
+        debug!("build_rust_fn: path=%s id=%? t=%s",
                path.repr(tcx),
                id,
-               t.repr(tcx),
-               llty.llrepr(ccx));
+               t.repr(tcx));
 
-        let llfndecl = base::decl_internal_cdecl_fn(ccx.llmod, ps, llty);
+        let llfndecl = base::decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, ps);
         base::trans_fn(ccx,
                        (*path).clone(),
                        decl,
@@ -500,7 +500,7 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
             // Rust expects to use an outpointer. If the foreign fn
             // also uses an outpointer, we can reuse it, but the types
             // may vary, so cast first to the Rust type. If the
-            // foriegn fn does NOT use an outpointer, we will have to
+            // foreign fn does NOT use an outpointer, we will have to
             // alloca some scratch space on the stack.
             match foreign_outptr {
                 Some(llforeign_outptr) => {
diff --git a/src/librustc/middle/trans/monomorphize.rs b/src/librustc/middle/trans/monomorphize.rs
index 2bdff6c8567..ef055a52468 100644
--- a/src/librustc/middle/trans/monomorphize.rs
+++ b/src/librustc/middle/trans/monomorphize.rs
@@ -14,14 +14,13 @@ use driver::session;
 use lib::llvm::ValueRef;
 use middle::trans::base::{set_llvm_fn_attrs, set_inline_hint};
 use middle::trans::base::{trans_enum_variant,push_ctxt};
-use middle::trans::base::{trans_fn, decl_internal_cdecl_fn};
+use middle::trans::base::{trans_fn, decl_internal_rust_fn};
 use middle::trans::base::{get_item_val, no_self};
 use middle::trans::base;
 use middle::trans::common::*;
 use middle::trans::datum;
 use middle::trans::machine;
 use middle::trans::meth;
-use middle::trans::type_of::type_of_fn_from_ty;
 use middle::trans::type_of;
 use middle::trans::type_use;
 use middle::trans::intrinsic;
@@ -177,7 +176,14 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
             ty::subst_tps(ccx.tcx, substs, None, llitem_ty)
         }
     };
-    let llfty = type_of_fn_from_ty(ccx, mono_ty);
+
+    let f = match ty::get(mono_ty).sty {
+        ty::ty_bare_fn(ref f) => {
+            assert!(f.abis.is_rust() || f.abis.is_intrinsic());
+            f
+        }
+        _ => fail!("expected bare rust fn or an intrinsic")
+    };
 
     ccx.stats.n_monos += 1;
 
@@ -200,7 +206,7 @@ pub fn monomorphic_fn(ccx: @mut CrateContext,
     debug!("monomorphize_fn mangled to %s", s);
 
     let mk_lldecl = || {
-        let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, llfty);
+        let lldecl = decl_internal_rust_fn(ccx, f.sig.inputs, f.sig.output, s);
         ccx.monomorphized.insert(hash_id, lldecl);
         lldecl
     };
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index 300fb64863c..23b87c63d6a 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -293,8 +293,7 @@ impl Reflector {
                                                                sub_path,
                                                                "get_disr");
 
-                let llfty = type_of_rust_fn(ccx, [opaqueptrty], ty::mk_int());
-                let llfdecl = decl_internal_cdecl_fn(ccx.llmod, sym, llfty);
+                let llfdecl = decl_internal_rust_fn(ccx, [opaqueptrty], ty::mk_int(), sym);
                 let fcx = new_fn_ctxt(ccx,
                                       ~[],
                                       llfdecl,