diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index 14af20f0cb9ee..160bc5111688a 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -33,6 +33,7 @@ pub enum CallConv { ColdCallConv = 9, X86StdcallCallConv = 64, X86FastcallCallConv = 65, + X86_64_Win64 = 79, } pub enum Visibility { diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 7da80507df07d..716ea049b66ed 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -33,7 +33,7 @@ use syntax::{ast}; use syntax::{attr, ast_map}; use syntax::parse::token::special_idents; use syntax::abi::{RustIntrinsic, Rust, Stdcall, Fastcall, System, - Cdecl, Aapcs, C, AbiSet}; + Cdecl, Aapcs, C, AbiSet, Win64}; use util::ppaux::{Repr, UserString}; use middle::trans::type_::Type; @@ -96,6 +96,7 @@ pub fn llvm_calling_convention(ccx: &mut CrateContext, Stdcall => lib::llvm::X86StdcallCallConv, Fastcall => lib::llvm::X86FastcallCallConv, C => lib::llvm::CCallConv, + Win64 => lib::llvm::X86_64_Win64, // NOTE These API constants ought to be more specific Cdecl => lib::llvm::CCallConv, @@ -398,11 +399,19 @@ pub fn register_rust_fn_with_foreign_abi(ccx: @mut CrateContext, let tys = foreign_types_for_id(ccx, node_id); let llfn_ty = lltype_for_fn_from_foreign_types(&tys); + let t = ty::node_id_to_type(ccx.tcx, node_id); + let cconv = match ty::get(t).sty { + ty::ty_bare_fn(ref fn_ty) => { + let c = llvm_calling_convention(ccx, fn_ty.abis); + c.unwrap_or(lib::llvm::CCallConv) + } + _ => lib::llvm::CCallConv + }; let llfn = base::register_fn_llvmty(ccx, sp, sym, node_id, - lib::llvm::CCallConv, + cconv, llfn_ty); add_argument_attributes(&tys, llfn); debug!("register_rust_fn_with_foreign_abi(node_id={:?}, llfn_ty={}, llfn={})", diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 972d2f43e73f5..4e9ba5532f37e 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -23,6 +23,7 @@ pub enum Abi { Stdcall, Fastcall, Aapcs, + Win64, // Multiplatform ABIs second Rust, @@ -73,6 +74,8 @@ static AbiDatas: &'static [AbiData] = &[ AbiData {abi: Stdcall, name: "stdcall", abi_arch: Archs(IntelBits)}, AbiData {abi: Fastcall, name:"fastcall", abi_arch: Archs(IntelBits)}, AbiData {abi: Aapcs, name: "aapcs", abi_arch: Archs(ArmBits)}, + AbiData {abi: Win64, name: "win64", + abi_arch: Archs(1 << (X86_64 as uint))}, // Cross-platform ABIs // diff --git a/src/test/auxiliary/extern_calling_convention.rs b/src/test/auxiliary/extern_calling_convention.rs new file mode 100644 index 0000000000000..41c57831da64f --- /dev/null +++ b/src/test/auxiliary/extern_calling_convention.rs @@ -0,0 +1,37 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Make sure Rust generates the correct calling convention for extern +// functions. + +#[inline(never)] +#[cfg(target_arch = "x86_64")] +pub extern "win64" fn foo(a: int, b: int, c: int, d: int) { + assert!(a == 1); + assert!(b == 2); + assert!(c == 3); + assert!(d == 4); + + println!("a: {:?}, b: {:?}, c: {:?}, d: {:?}", + a, b, c, d) +} + +#[inline(never)] +#[cfg(target_arch = "x86")] +#[cfg(target_arch = "arm")] +pub extern fn foo(a: int, b: int, c: int, d: int) { + assert!(a == 1); + assert!(b == 2); + assert!(c == 3); + assert!(d == 4); + + println!("a: {:?}, b: {:?}, c: {:?}, d: {:?}", + a, b, c, d) +} diff --git a/src/test/run-pass/extern-calling-convention-test.rs b/src/test/run-pass/extern-calling-convention-test.rs new file mode 100644 index 0000000000000..e8609a8b60b1a --- /dev/null +++ b/src/test/run-pass/extern-calling-convention-test.rs @@ -0,0 +1,20 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-fast: aux-build not compatible with fast +// aux-build:extern_calling_convention.rs + +extern mod extern_calling_convention; + +use extern_calling_convention::foo; + +fn main() { + foo(1, 2, 3, 4); +}