about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2013-09-14 10:46:29 -0700
committerAlex Crichton <alex@alexcrichton.com>2013-09-15 20:42:06 -0700
commit297ac739d8e7891bfaa4d73f8126371c2c13425f (patch)
tree89642ea04fd96c89a8b98e8c1c2d8b74c3da1677
parentccadbd3b7c936dacab69856cc3963aad477c7f06 (diff)
downloadrust-297ac739d8e7891bfaa4d73f8126371c2c13425f.tar.gz
rust-297ac739d8e7891bfaa4d73f8126371c2c13425f.zip
When declaring extern fns from external crates, use the correct abi
Beforehand it was assumed that the standard cdecl abi was used for all extern
fns of extern crates, but this reads the abi of the extern fn type and declares
the function in the local crate with the appropriate type.
-rw-r--r--src/librustc/middle/trans/base.rs33
-rw-r--r--src/librustc/middle/trans/foreign.rs5
2 files changed, 25 insertions, 13 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index a79063c9c9a..f1fffa88071 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -86,7 +86,7 @@ use syntax::parse::token;
 use syntax::parse::token::{special_idents};
 use syntax::print::pprust::stmt_to_str;
 use syntax::{ast, ast_util, codemap, ast_map};
-use syntax::abi::{X86, X86_64, Arm, Mips};
+use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic};
 use syntax::visit;
 use syntax::visit::Visitor;
 
@@ -813,15 +813,28 @@ 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(_) | 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);
-      }
-      _ => {
-        let llty = type_of(ccx, t);
-        return get_extern_const(&mut ccx.externs, ccx.llmod, name, llty);
-      }
+        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,
+                Some(*) | None => {
+                    let c = foreign::llvm_calling_convention(ccx, fn_ty.abis);
+                    c.unwrap_or(lib::llvm::CCallConv)
+                }
+            };
+            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);
+        }
+        _ => {
+            let llty = type_of(ccx, t);
+            return get_extern_const(&mut ccx.externs, ccx.llmod, name, llty);
+        }
     };
 }
 
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 681852b3bf2..d5ce3516c59 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -74,9 +74,8 @@ struct LlvmSignature {
 ///////////////////////////////////////////////////////////////////////////
 // Calls to external functions
 
-fn llvm_calling_convention(ccx: @mut CrateContext,
-                           abis: AbiSet)
-                           -> Option<CallConv> {
+pub fn llvm_calling_convention(ccx: &mut CrateContext,
+                               abis: AbiSet) -> Option<CallConv> {
     let arch = ccx.sess.targ_cfg.arch;
     abis.for_arch(arch).map(|abi| {
         match *abi {