auto merge of #14191 : luqmana/rust/eu, r=alexcrichton

We were correctly determining the attributes needed for the parameters for extern fns, but when that extern fn was from another crate we never bothered to pass that information along to LLVM. (i.e never called `foreign::add_argument_attributes`).

I've just changed both local and non-local (crate) extern fn's to be dealt with together (through `foreign::register_foreign_item_fn`) so we don't run into something like again.

Fixes #14177.
This commit is contained in:
bors 2014-05-14 05:56:18 -07:00
commit d78718ad63
6 changed files with 109 additions and 25 deletions

View File

@ -860,15 +860,8 @@ pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> Val
did)
}
Some(..) | None => {
let c = foreign::llvm_calling_convention(ccx, fn_ty.abi);
let cconv = c.unwrap_or(lib::llvm::CCallConv);
let llty = type_of_fn_from_ty(ccx, t);
get_extern_fn(&mut *ccx.externs.borrow_mut(),
ccx.llmod,
name.as_slice(),
cconv,
llty,
fn_ty.sig.output)
foreign::register_foreign_item_fn(ccx, fn_ty.abi, t,
name.as_slice(), None)
}
}
}
@ -1976,7 +1969,11 @@ pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
match ni.node {
ast::ForeignItemFn(..) => {
let abi = ccx.tcx.map.get_foreign_abi(id);
foreign::register_foreign_item_fn(ccx, abi, ni)
let ty = ty::node_id_to_type(ccx.tcx(), ni.id);
let name = foreign::link_name(ni);
foreign::register_foreign_item_fn(ccx, abi, ty,
name.get().as_slice(),
Some(ni.span))
}
ast::ForeignItemStatic(..) => {
foreign::register_static(ccx, ni)

View File

@ -180,33 +180,42 @@ pub fn register_static(ccx: &CrateContext,
}
}
pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi,
foreign_item: &ast::ForeignItem) -> ValueRef {
pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi, fty: ty::t,
name: &str, span: Option<Span>) -> ValueRef {
/*!
* Registers a foreign function found in a library.
* Just adds a LLVM global.
*/
debug!("register_foreign_item_fn(abi={}, \
path={}, \
foreign_item.id={})",
ty={}, \
name={})",
abi.repr(ccx.tcx()),
ccx.tcx.map.path_to_str(foreign_item.id),
foreign_item.id);
fty.repr(ccx.tcx()),
name);
let cc = match llvm_calling_convention(ccx, abi) {
Some(cc) => cc,
None => {
ccx.sess().span_fatal(foreign_item.span,
format!("ABI `{}` has no suitable calling convention \
for target architecture",
abi.user_string(ccx.tcx())));
match span {
Some(s) => {
ccx.sess().span_fatal(s,
format!("ABI `{}` has no suitable calling convention \
for target architecture",
abi.user_string(ccx.tcx())))
}
None => {
ccx.sess().fatal(
format!("ABI `{}` has no suitable calling convention \
for target architecture",
abi.user_string(ccx.tcx())))
}
}
}
};
// Register the function as a C extern fn
let lname = link_name(foreign_item);
let tys = foreign_types_for_id(ccx, foreign_item.id);
let tys = foreign_types_for_fn_ty(ccx, fty);
// Make sure the calling convention is right for variadic functions
// (should've been caught if not in typeck)
@ -219,7 +228,7 @@ pub fn register_foreign_item_fn(ccx: &CrateContext, abi: Abi,
let llfn = base::get_extern_fn(&mut *ccx.externs.borrow_mut(),
ccx.llmod,
lname.get(),
name,
cc,
llfn_ty,
tys.fn_sig.output);
@ -433,17 +442,23 @@ pub fn trans_native_call<'a>(
pub fn trans_foreign_mod(ccx: &CrateContext, foreign_mod: &ast::ForeignMod) {
let _icx = push_ctxt("foreign::trans_foreign_mod");
for &foreign_item in foreign_mod.items.iter() {
let lname = link_name(foreign_item);
match foreign_item.node {
ast::ForeignItemFn(..) => {
match foreign_mod.abi {
Rust | RustIntrinsic => {}
abi => { register_foreign_item_fn(ccx, abi, foreign_item); }
abi => {
let ty = ty::node_id_to_type(ccx.tcx(), foreign_item.id);
register_foreign_item_fn(ccx, abi, ty,
lname.get().as_slice(),
Some(foreign_item.span));
}
}
}
_ => {}
}
let lname = link_name(foreign_item);
ccx.item_symbols.borrow_mut().insert(foreign_item.id,
lname.get().to_strbuf());
}

View File

@ -0,0 +1,8 @@
-include ../tools.mk
all:
$(CC) -std=c99 test.c -c -o $(TMPDIR)/test.o
$(AR) rcs $(TMPDIR)/libtest.a $(TMPDIR)/test.o
$(RUSTC) testcrate.rs -L $(TMPDIR)
$(RUSTC) test.rs -L $(TMPDIR)
$(call RUN,test) || exit 1

View File

@ -0,0 +1,10 @@
#include <stdio.h>
#include <stdint.h>
typedef union TestUnion {
uint64_t bits;
} TestUnion;
uint64_t give_back(TestUnion tu) {
return tu.bits;
}

View File

@ -0,0 +1,34 @@
// Copyright 2014 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
extern crate testcrate;
use std::mem;
#[link(name = "test", kind = "static")]
extern {
fn give_back(tu: testcrate::TestUnion) -> u64;
}
fn main() {
let magic: u64 = 0xDEADBEEF;
// Let's test calling it cross crate
let back = unsafe {
testcrate::give_back(mem::transmute(magic))
};
assert_eq!(magic, back);
// And just within this crate
let back = unsafe {
give_back(mem::transmute(magic))
};
assert_eq!(magic, back);
}

View File

@ -0,0 +1,20 @@
// Copyright 2014 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 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![crate_type = "lib"]
pub struct TestUnion {
val: u64
}
#[link(name = "test", kind = "static")]
extern {
pub fn give_back(tu: TestUnion) -> u64;
}