diff --git a/src/libcore/rt/thread.rs b/src/libcore/rt/thread.rs index cd46127451281..be1d86c9cf741 100644 --- a/src/libcore/rt/thread.rs +++ b/src/libcore/rt/thread.rs @@ -22,7 +22,7 @@ struct Thread { impl Thread { static fn start(main: ~fn()) -> Thread { fn substart(main: &fn()) -> *raw_thread { - unsafe { rust_raw_thread_start(main) } + unsafe { rust_raw_thread_start(&main) } } let raw = substart(main); Thread { @@ -39,6 +39,6 @@ impl Drop for Thread { } extern { - pub unsafe fn rust_raw_thread_start(f: &fn()) -> *raw_thread; + pub unsafe fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread; pub unsafe fn rust_raw_thread_join_delete(thread: *raw_thread); } diff --git a/src/libcore/unstable.rs b/src/libcore/unstable.rs index 7936b18dbe20c..9b6dcc312347a 100644 --- a/src/libcore/unstable.rs +++ b/src/libcore/unstable.rs @@ -47,7 +47,7 @@ mod rustrt { pub unsafe fn rust_lock_little_lock(lock: rust_little_lock); pub unsafe fn rust_unlock_little_lock(lock: rust_little_lock); - pub unsafe fn rust_raw_thread_start(f: &fn()) -> *raw_thread; + pub unsafe fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread; pub unsafe fn rust_raw_thread_join_delete(thread: *raw_thread); } } @@ -72,7 +72,7 @@ pub fn run_in_bare_thread(f: ~fn()) { let closure: &fn() = || { f() }; - let thread = rustrt::rust_raw_thread_start(closure); + let thread = rustrt::rust_raw_thread_start(&closure); rustrt::rust_raw_thread_join_delete(thread); chan.send(()); } diff --git a/src/librustc/lib/llvm.rs b/src/librustc/lib/llvm.rs index b0cc18a30a41d..23eb6743b9fa8 100644 --- a/src/librustc/lib/llvm.rs +++ b/src/librustc/lib/llvm.rs @@ -1443,7 +1443,7 @@ pub mod llvm { /** Prepares inline assembly. */ pub unsafe fn LLVMInlineAsm(Ty: TypeRef, AsmString: *c_char, Constraints: *c_char, SideEffects: Bool, - AlignStack: Bool, Dialect: AsmDialect) + AlignStack: Bool, Dialect: c_uint) -> ValueRef; } } diff --git a/src/librustc/middle/lint.rs b/src/librustc/middle/lint.rs index 93f0557028eae..47ec756fe0ee5 100644 --- a/src/librustc/middle/lint.rs +++ b/src/librustc/middle/lint.rs @@ -78,6 +78,7 @@ pub enum lint { deprecated_self, deprecated_mutable_fields, deprecated_drop, + foreign_mode, managed_heap_memory, owned_heap_memory, @@ -182,6 +183,13 @@ pub fn get_lint_dict() -> LintDict { default: warn }), + (@~"foreign_mode", + @LintSpec { + lint: foreign_mode, + desc: "warn about deprecated uses of modes in foreign fns", + default: warn + }), + (@~"deprecated_pattern", @LintSpec { lint: deprecated_pattern, @@ -753,6 +761,20 @@ fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) { fn check_foreign_fn(cx: ty::ctxt, fn_id: ast::node_id, decl: &ast::fn_decl) { + // warn about `&&` mode on foreign functions, both because it is + // deprecated and because its semantics have changed recently: + for decl.inputs.eachi |i, arg| { + match ty::resolved_mode(cx, arg.mode) { + ast::by_val | ast::by_copy => {} + ast::by_ref => { + cx.sess.span_lint( + foreign_mode, fn_id, fn_id, arg.ty.span, + fmt!("foreign function uses `&&` mode \ + on argument %u", i)); + } + } + } + let tys = vec::map(decl.inputs, |a| a.ty ); for vec::each(vec::append_one(tys, decl.output)) |ty| { match ty.node { @@ -785,7 +807,7 @@ fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) { if attr::foreign_abi(it.attrs) != either::Right(ast::foreign_abi_rust_intrinsic) => { for nmod.items.each |ni| { - match /*bad*/copy ni.node { + match ni.node { ast::foreign_item_fn(ref decl, _, _) => { check_foreign_fn(cx, it.id, decl); } diff --git a/src/librustc/middle/trans/build.rs b/src/librustc/middle/trans/build.rs index e75cf14ff6945..850ea908e74ee 100644 --- a/src/librustc/middle/trans/build.rs +++ b/src/librustc/middle/trans/build.rs @@ -885,7 +885,7 @@ pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char, let llfty = T_fn(~[], T_void()); let v = llvm::LLVMInlineAsm(llfty, asm, cons, volatile, - alignstack, dia); + alignstack, dia as c_uint); Call(cx, v, ~[]) } diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index 9e38252dc9a8a..5052ce0767115 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -757,7 +757,7 @@ pub fn trans_arg_expr(bcx: block, if formal_ty.ty != arg_datum.ty { // this could happen due to e.g. subtyping - let llformal_ty = type_of::type_of_explicit_arg(ccx, formal_ty); + let llformal_ty = type_of::type_of_explicit_arg(ccx, &formal_ty); debug!("casting actual type (%s) to match formal (%s)", bcx.val_str(val), bcx.llty_str(llformal_ty)); val = PointerCast(bcx, val, llformal_ty); diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 1e3c4f21bd875..fde1de5b63f21 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -58,59 +58,90 @@ pub fn link_name(ccx: @CrateContext, i: @ast::foreign_item) -> @~str { } } -struct c_stack_tys { - arg_tys: ~[TypeRef], - ret_ty: TypeRef, +struct ShimTypes { + fn_sig: ty::FnSig, + + /// LLVM types that will appear on the foreign function + llsig: LlvmSignature, + + /// True if there is a return value (not bottom, not unit) ret_def: bool, + + /// Type of the struct we will use to shuttle values back and forth. + /// This is always derived from the llsig. bundle_ty: TypeRef, + + /// Type of the shim function itself. shim_fn_ty: TypeRef, + + /// Adapter object for handling native ABI rules (trust me, you + /// don't want to know). fn_ty: cabi::FnType } -fn c_arg_and_ret_lltys(ccx: @CrateContext, - id: ast::node_id) -> (~[TypeRef], TypeRef, ty::t) { - match ty::get(ty::node_id_to_type(ccx.tcx, id)).sty { - ty::ty_bare_fn(ref fn_ty) => { - let llargtys = type_of_explicit_args(ccx, fn_ty.sig.inputs); - let llretty = type_of::type_of(ccx, fn_ty.sig.output); - (llargtys, llretty, fn_ty.sig.output) - } - _ => ccx.sess.bug(~"c_arg_and_ret_lltys called on non-function type") - } +struct LlvmSignature { + llarg_tys: ~[TypeRef], + llret_ty: TypeRef, } -fn c_stack_tys(ccx: @CrateContext, - id: ast::node_id) -> @c_stack_tys { - let (llargtys, llretty, ret_ty) = c_arg_and_ret_lltys(ccx, id); - // XXX: Bad copy. - let bundle_ty = T_struct(vec::append_one(copy llargtys, T_ptr(llretty))); - let ret_def = !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty); - let fn_ty = abi_info(ccx.sess.targ_cfg.arch). - compute_info(llargtys, llretty, ret_def); - return @c_stack_tys { - arg_tys: llargtys, - ret_ty: llretty, +fn foreign_signature(ccx: @CrateContext, + fn_sig: &ty::FnSig) -> LlvmSignature { + /*! + * The ForeignSignature is the LLVM types of the arguments/return type + * of a function. Note that these LLVM types are not quite the same + * as the LLVM types would be for a native Rust function because foreign + * functions just plain ignore modes. They also don't pass aggregate + * values by pointer like we do. + */ + + let llarg_tys = fn_sig.inputs.map(|arg| type_of(ccx, arg.ty)); + let llret_ty = type_of::type_of(ccx, fn_sig.output); + LlvmSignature {llarg_tys: llarg_tys, llret_ty: llret_ty} +} + +fn shim_types(ccx: @CrateContext, id: ast::node_id) -> ShimTypes { + let fn_sig = match ty::get(ty::node_id_to_type(ccx.tcx, id)).sty { + ty::ty_bare_fn(ref fn_ty) => copy fn_ty.sig, + _ => ccx.sess.bug(~"c_arg_and_ret_lltys called on non-function type") + }; + let llsig = foreign_signature(ccx, &fn_sig); + let bundle_ty = T_struct(vec::append_one(copy llsig.llarg_tys, + T_ptr(llsig.llret_ty))); + let ret_def = + !ty::type_is_bot(fn_sig.output) && + !ty::type_is_nil(fn_sig.output); + let fn_ty = + abi_info(ccx.sess.targ_cfg.arch).compute_info( + llsig.llarg_tys, + llsig.llret_ty, + ret_def); + ShimTypes { + fn_sig: fn_sig, + llsig: llsig, ret_def: ret_def, bundle_ty: bundle_ty, shim_fn_ty: T_fn(~[T_ptr(bundle_ty)], T_void()), fn_ty: fn_ty - }; + } } -type shim_arg_builder = &self/fn(bcx: block, tys: @c_stack_tys, - llargbundle: ValueRef) -> ~[ValueRef]; +type shim_arg_builder<'self> = + &'self fn(bcx: block, tys: &ShimTypes, + llargbundle: ValueRef) -> ~[ValueRef]; -type shim_ret_builder = &self/fn(bcx: block, tys: @c_stack_tys, - llargbundle: ValueRef, llretval: ValueRef); +type shim_ret_builder<'self> = + &'self fn(bcx: block, tys: &ShimTypes, + llargbundle: ValueRef, + llretval: ValueRef); fn build_shim_fn_(ccx: @CrateContext, +shim_name: ~str, llbasefn: ValueRef, - tys: @c_stack_tys, + tys: &ShimTypes, cc: lib::llvm::CallConv, arg_builder: shim_arg_builder, - ret_builder: shim_ret_builder) -> ValueRef { - + ret_builder: shim_ret_builder) -> ValueRef +{ let llshimfn = decl_internal_cdecl_fn( ccx.llmod, shim_name, tys.shim_fn_ty); @@ -122,8 +153,7 @@ fn build_shim_fn_(ccx: @CrateContext, let llargvals = arg_builder(bcx, tys, llargbundle); // Create the call itself and store the return value: - let llretval = CallWithConv(bcx, llbasefn, - llargvals, cc); // r + let llretval = CallWithConv(bcx, llbasefn, llargvals, cc); ret_builder(bcx, tys, llargbundle, llretval); @@ -133,21 +163,22 @@ fn build_shim_fn_(ccx: @CrateContext, return llshimfn; } -type wrap_arg_builder = &self/fn(bcx: block, tys: @c_stack_tys, - llwrapfn: ValueRef, - llargbundle: ValueRef); +type wrap_arg_builder<'self> = + &'self fn(bcx: block, tys: &ShimTypes, + llwrapfn: ValueRef, llargbundle: ValueRef); -type wrap_ret_builder = &self/fn(bcx: block, tys: @c_stack_tys, - llargbundle: ValueRef); +type wrap_ret_builder<'self> = + &'self fn(bcx: block, tys: &ShimTypes, + llargbundle: ValueRef); fn build_wrap_fn_(ccx: @CrateContext, - tys: @c_stack_tys, + tys: &ShimTypes, llshimfn: ValueRef, llwrapfn: ValueRef, shim_upcall: ValueRef, arg_builder: wrap_arg_builder, - ret_builder: wrap_ret_builder) { - + ret_builder: wrap_ret_builder) +{ let _icx = ccx.insn_ctxt("foreign::build_wrap_fn_"); let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, None); let bcx = top_scope_block(fcx, None); @@ -199,36 +230,83 @@ fn build_wrap_fn_(ccx: @CrateContext, // F(args->z, args->x, args->y); // } // -// Note: on i386, the layout of the args struct is generally the same as the -// desired layout of the arguments on the C stack. Therefore, we could use -// upcall_alloc_c_stack() to allocate the `args` structure and switch the -// stack pointer appropriately to avoid a round of copies. (In fact, the shim -// function itself is unnecessary). We used to do this, in fact, and will -// perhaps do so in the future. +// Note: on i386, the layout of the args struct is generally the same +// as the desired layout of the arguments on the C stack. Therefore, +// we could use upcall_alloc_c_stack() to allocate the `args` +// structure and switch the stack pointer appropriately to avoid a +// round of copies. (In fact, the shim function itself is +// unnecessary). We used to do this, in fact, and will perhaps do so +// in the future. pub fn trans_foreign_mod(ccx: @CrateContext, foreign_mod: &ast::foreign_mod, - abi: ast::foreign_abi) { - + abi: ast::foreign_abi) +{ let _icx = ccx.insn_ctxt("foreign::trans_foreign_mod"); + let mut cc = match abi { + ast::foreign_abi_rust_intrinsic | + ast::foreign_abi_cdecl => lib::llvm::CCallConv, + ast::foreign_abi_stdcall => lib::llvm::X86StdcallCallConv + }; + + for vec::each(foreign_mod.items) |foreign_item| { + match foreign_item.node { + ast::foreign_item_fn(*) => { + let id = foreign_item.id; + if abi != ast::foreign_abi_rust_intrinsic { + let llwrapfn = get_item_val(ccx, id); + let tys = shim_types(ccx, id); + if attr::attrs_contains_name( + foreign_item.attrs, "rust_stack") + { + build_direct_fn(ccx, llwrapfn, *foreign_item, + &tys, cc); + } else { + let llshimfn = build_shim_fn(ccx, *foreign_item, + &tys, cc); + build_wrap_fn(ccx, &tys, llshimfn, llwrapfn); + } + } else { + // Intrinsics are emitted by monomorphic fn + } + } + ast::foreign_item_const(*) => { + let ident = ccx.sess.parse_sess.interner.get( + foreign_item.ident); + ccx.item_symbols.insert(foreign_item.id, copy *ident); + } + } + } + fn build_shim_fn(ccx: @CrateContext, foreign_item: @ast::foreign_item, - tys: @c_stack_tys, - cc: lib::llvm::CallConv) -> ValueRef { + tys: &ShimTypes, + cc: lib::llvm::CallConv) -> ValueRef + { + /*! + * + * Build S, from comment above: + * + * void S(struct { X x; Y y; Z *z; } *args) { + * F(args->z, args->x, args->y); + * } + */ let _icx = ccx.insn_ctxt("foreign::build_shim_fn"); - fn build_args(bcx: block, tys: @c_stack_tys, + fn build_args(bcx: block, tys: &ShimTypes, llargbundle: ValueRef) -> ~[ValueRef] { let _icx = bcx.insn_ctxt("foreign::shim::build_args"); - return tys.fn_ty.build_shim_args(bcx, tys.arg_tys, llargbundle); + tys.fn_ty.build_shim_args( + bcx, tys.llsig.llarg_tys, llargbundle) } - fn build_ret(bcx: block, tys: @c_stack_tys, + fn build_ret(bcx: block, tys: &ShimTypes, llargbundle: ValueRef, llretval: ValueRef) { let _icx = bcx.insn_ctxt("foreign::shim::build_ret"); - tys.fn_ty.build_shim_ret(bcx, tys.arg_tys, tys.ret_def, - llargbundle, llretval); + tys.fn_ty.build_shim_ret( + bcx, tys.llsig.llarg_tys, + tys.ret_def, llargbundle, llretval); } let lname = link_name(ccx, foreign_item); @@ -239,7 +317,7 @@ pub fn trans_foreign_mod(ccx: @CrateContext, build_args, build_ret); } - fn base_fn(ccx: @CrateContext, lname: &str, tys: @c_stack_tys, + fn base_fn(ccx: @CrateContext, lname: &str, tys: &ShimTypes, cc: lib::llvm::CallConv) -> ValueRef { // Declare the "prototype" for the base function F: do tys.fn_ty.decl_fn |fnty| { @@ -250,7 +328,7 @@ pub fn trans_foreign_mod(ccx: @CrateContext, // FIXME (#2535): this is very shaky and probably gets ABIs wrong all // over the place fn build_direct_fn(ccx: @CrateContext, decl: ValueRef, - item: @ast::foreign_item, tys: @c_stack_tys, + item: @ast::foreign_item, tys: &ShimTypes, cc: lib::llvm::CallConv) { let fcx = new_fn_ctxt(ccx, ~[], decl, None); let bcx = top_scope_block(fcx, None), lltop = bcx.llbb; @@ -269,66 +347,55 @@ pub fn trans_foreign_mod(ccx: @CrateContext, } fn build_wrap_fn(ccx: @CrateContext, - tys: @c_stack_tys, + tys: &ShimTypes, llshimfn: ValueRef, llwrapfn: ValueRef) { + /*! + * + * Build W, from comment above: + * + * void W(Z* dest, void *env, X x, Y y) { + * struct { X x; Y y; Z *z; } args = { x, y, z }; + * call_on_c_stack_shim(S, &args); + * } + * + * One thing we have to be very careful of is to + * account for the Rust modes. + */ let _icx = ccx.insn_ctxt("foreign::build_wrap_fn"); - fn build_args(bcx: block, tys: @c_stack_tys, + build_wrap_fn_(ccx, tys, llshimfn, llwrapfn, + ccx.upcalls.call_shim_on_c_stack, + build_args, build_ret); + + fn build_args(bcx: block, tys: &ShimTypes, llwrapfn: ValueRef, llargbundle: ValueRef) { let _icx = bcx.insn_ctxt("foreign::wrap::build_args"); - let mut i = 0u; - let n = vec::len(tys.arg_tys); + let ccx = bcx.ccx(); + let n = vec::len(tys.llsig.llarg_tys); let implicit_args = first_real_arg; // return + env - while i < n { - let llargval = get_param(llwrapfn, i + implicit_args); + for uint::range(0, n) |i| { + let mut llargval = get_param(llwrapfn, i + implicit_args); + + // In some cases, Rust will pass a pointer which the + // native C type doesn't have. In that case, just + // load the value from the pointer. + if type_of::arg_is_indirect(ccx, &tys.fn_sig.inputs[i]) { + llargval = Load(bcx, llargval); + } + store_inbounds(bcx, llargval, llargbundle, ~[0u, i]); - i += 1u; } let llretptr = get_param(llwrapfn, 0u); store_inbounds(bcx, llretptr, llargbundle, ~[0u, n]); } - fn build_ret(bcx: block, _tys: @c_stack_tys, + fn build_ret(bcx: block, _tys: &ShimTypes, _llargbundle: ValueRef) { let _icx = bcx.insn_ctxt("foreign::wrap::build_ret"); RetVoid(bcx); } - - build_wrap_fn_(ccx, tys, llshimfn, llwrapfn, - ccx.upcalls.call_shim_on_c_stack, - build_args, build_ret); - } - - let mut cc = match abi { - ast::foreign_abi_rust_intrinsic | - ast::foreign_abi_cdecl => lib::llvm::CCallConv, - ast::foreign_abi_stdcall => lib::llvm::X86StdcallCallConv - }; - - for vec::each(foreign_mod.items) |foreign_item| { - match foreign_item.node { - ast::foreign_item_fn(*) => { - let id = foreign_item.id; - if abi != ast::foreign_abi_rust_intrinsic { - let llwrapfn = get_item_val(ccx, id); - let tys = c_stack_tys(ccx, id); - if attr::attrs_contains_name(foreign_item.attrs, "rust_stack") { - build_direct_fn(ccx, llwrapfn, *foreign_item, tys, cc); - } else { - let llshimfn = build_shim_fn(ccx, *foreign_item, tys, cc); - build_wrap_fn(ccx, tys, llshimfn, llwrapfn); - } - } else { - // Intrinsics are emitted by monomorphic fn - } - } - ast::foreign_item_const(*) => { - let ident = ccx.sess.parse_sess.interner.get(foreign_item.ident); - ccx.item_symbols.insert(foreign_item.id, copy *ident); - } - } } } @@ -842,6 +909,32 @@ pub fn trans_intrinsic(ccx: @CrateContext, finish_fn(fcx, lltop); } +/** + * Translates a "crust" fn, meaning a Rust fn that can be called + * from C code. In this case, we have to perform some adaptation + * to (1) switch back to the Rust stack and (2) adapt the C calling + * convention to our own. + * + * Example: Given a crust fn F(x: X, y: Y) -> Z, we generate a + * Rust function R as normal: + * + * void R(Z* dest, void *env, X x, Y y) {...} + * + * and then we generate a wrapper function W that looks like: + * + * Z W(X x, Y y) { + * struct { X x; Y y; Z *z; } args = { x, y, z }; + * call_on_c_stack_shim(S, &args); + * } + * + * Note that the wrapper follows the foreign (typically "C") ABI. + * The wrapper is the actual "value" of the foreign fn. Finally, + * we generate a shim function S that looks like: + * + * void S(struct { X x; Y y; Z *z; } *args) { + * R(args->z, NULL, args->x, args->y); + * } + */ pub fn trans_foreign_fn(ccx: @CrateContext, +path: ast_map::path, decl: &ast::fn_decl, @@ -867,28 +960,51 @@ pub fn trans_foreign_fn(ccx: @CrateContext, } fn build_shim_fn(ccx: @CrateContext, +path: ast_map::path, - llrustfn: ValueRef, tys: @c_stack_tys) -> ValueRef { + llrustfn: ValueRef, tys: &ShimTypes) -> ValueRef { + /*! + * + * Generate the shim S: + * + * void S(struct { X x; Y y; Z *z; } *args) { + * R(args->z, NULL, &args->x, args->y); + * } + * + * One complication is that we must adapt to the Rust + * calling convention, which introduces indirection + * in some cases. To demonstrate this, I wrote one of the + * entries above as `&args->x`, because presumably `X` is + * one of those types that is passed by pointer in Rust. + */ + let _icx = ccx.insn_ctxt("foreign::foreign::build_shim_fn"); - fn build_args(bcx: block, tys: @c_stack_tys, + fn build_args(bcx: block, tys: &ShimTypes, llargbundle: ValueRef) -> ~[ValueRef] { let _icx = bcx.insn_ctxt("foreign::extern::shim::build_args"); + let ccx = bcx.ccx(); let mut llargvals = ~[]; let mut i = 0u; - let n = vec::len(tys.arg_tys); + let n = tys.fn_sig.inputs.len(); let llretptr = load_inbounds(bcx, llargbundle, ~[0u, n]); llargvals.push(llretptr); let llenvptr = C_null(T_opaque_box_ptr(bcx.ccx())); llargvals.push(llenvptr); while i < n { - let llargval = load_inbounds(bcx, llargbundle, ~[0u, i]); + // Get a pointer to the argument: + let mut llargval = GEPi(bcx, llargbundle, [0u, i]); + + if !type_of::arg_is_indirect(ccx, &tys.fn_sig.inputs[i]) { + // If Rust would pass this by value, load the value. + llargval = Load(bcx, llargval); + } + llargvals.push(llargval); i += 1u; } return llargvals; } - fn build_ret(_bcx: block, _tys: @c_stack_tys, + fn build_ret(_bcx: block, _tys: &ShimTypes, _llargbundle: ValueRef, _llretval: ValueRef) { // Nop. The return pointer in the Rust ABI function // is wired directly into the return slot in the shim struct @@ -904,36 +1020,48 @@ pub fn trans_foreign_fn(ccx: @CrateContext, } fn build_wrap_fn(ccx: @CrateContext, llshimfn: ValueRef, - llwrapfn: ValueRef, tys: @c_stack_tys) { + llwrapfn: ValueRef, tys: &ShimTypes) + { + /*! + * + * Generate the wrapper W: + * + * Z W(X x, Y y) { + * struct { X x; Y y; Z *z; } args = { x, y, z }; + * call_on_c_stack_shim(S, &args); + * } + */ let _icx = ccx.insn_ctxt("foreign::foreign::build_wrap_fn"); - fn build_args(bcx: block, tys: @c_stack_tys, + build_wrap_fn_(ccx, tys, llshimfn, llwrapfn, + ccx.upcalls.call_shim_on_rust_stack, + build_args, build_ret); + + fn build_args(bcx: block, tys: &ShimTypes, llwrapfn: ValueRef, llargbundle: ValueRef) { let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_args"); - tys.fn_ty.build_wrap_args(bcx, tys.ret_ty, - llwrapfn, llargbundle); + tys.fn_ty.build_wrap_args( + bcx, tys.llsig.llret_ty, + llwrapfn, llargbundle); } - fn build_ret(bcx: block, tys: @c_stack_tys, + fn build_ret(bcx: block, tys: &ShimTypes, llargbundle: ValueRef) { let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_ret"); - tys.fn_ty.build_wrap_ret(bcx, tys.arg_tys, llargbundle); + tys.fn_ty.build_wrap_ret( + bcx, tys.llsig.llarg_tys, llargbundle); } - - build_wrap_fn_(ccx, tys, llshimfn, llwrapfn, - ccx.upcalls.call_shim_on_rust_stack, - build_args, build_ret); } - let tys = c_stack_tys(ccx, id); + let tys = shim_types(ccx, id); // The internal Rust ABI function - runs on the Rust stack // XXX: Bad copy. let llrustfn = build_rust_fn(ccx, copy path, decl, body, id); // The internal shim function - runs on the Rust stack - let llshimfn = build_shim_fn(ccx, path, llrustfn, tys); + let llshimfn = build_shim_fn(ccx, path, llrustfn, &tys); // The foreign C function - runs on the C stack - build_wrap_fn(ccx, llshimfn, llwrapfn, tys) + build_wrap_fn(ccx, llshimfn, llwrapfn, &tys) } pub fn register_foreign_fn(ccx: @CrateContext, @@ -944,11 +1072,8 @@ pub fn register_foreign_fn(ccx: @CrateContext, -> ValueRef { let _icx = ccx.insn_ctxt("foreign::register_foreign_fn"); let t = ty::node_id_to_type(ccx.tcx, node_id); - let (llargtys, llretty, ret_ty) = c_arg_and_ret_lltys(ccx, node_id); - let ret_def = !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty); - let fn_ty = abi_info(ccx.sess.targ_cfg.arch). - compute_info(llargtys, llretty, ret_def); - do fn_ty.decl_fn |fnty| { + let tys = shim_types(ccx, node_id); + do tys.fn_ty.decl_fn |fnty| { register_fn_fuller(ccx, sp, /*bad*/copy path, node_id, attrs, t, lib::llvm::CCallConv, fnty) } diff --git a/src/librustc/middle/trans/type_of.rs b/src/librustc/middle/trans/type_of.rs index 68eb0852445e0..2a390a03fa142 100644 --- a/src/librustc/middle/trans/type_of.rs +++ b/src/librustc/middle/trans/type_of.rs @@ -21,24 +21,22 @@ use util::ppaux; use core::option::None; use syntax::ast; -pub fn type_of_explicit_arg(ccx: @CrateContext, arg: ty::arg) -> TypeRef { - let llty = type_of(ccx, arg.ty); +pub fn arg_is_indirect(ccx: @CrateContext, arg: &ty::arg) -> bool { match ty::resolved_mode(ccx.tcx, arg.mode) { - ast::by_val => llty, - ast::by_copy => { - if ty::type_is_immediate(arg.ty) { - llty - } else { - T_ptr(llty) - } - } - _ => T_ptr(llty) + ast::by_val => false, + ast::by_copy => !ty::type_is_immediate(arg.ty), + ast::by_ref => true } } +pub fn type_of_explicit_arg(ccx: @CrateContext, arg: &ty::arg) -> TypeRef { + let llty = type_of(ccx, arg.ty); + if arg_is_indirect(ccx, arg) {T_ptr(llty)} else {llty} +} + pub fn type_of_explicit_args(ccx: @CrateContext, inputs: &[ty::arg]) -> ~[TypeRef] { - inputs.map(|arg| type_of_explicit_arg(ccx, *arg)) + inputs.map(|arg| type_of_explicit_arg(ccx, arg)) } pub fn type_of_fn(cx: @CrateContext, inputs: &[ty::arg], diff --git a/src/libstd/time.rs b/src/libstd/time.rs index d6e19515ba655..d768eef9a8c9b 100644 --- a/src/libstd/time.rs +++ b/src/libstd/time.rs @@ -30,10 +30,10 @@ pub mod rustrt { pub unsafe fn rust_tzset(); // FIXME: The i64 values can be passed by-val when #2064 is fixed. - pub unsafe fn rust_gmtime(&&sec: i64, &&nsec: i32, &&result: Tm); - pub unsafe fn rust_localtime(&&sec: i64, &&nsec: i32, &&result: Tm); - pub unsafe fn rust_timegm(&&tm: Tm, sec: &mut i64); - pub unsafe fn rust_mktime(&&tm: Tm, sec: &mut i64); + pub unsafe fn rust_gmtime(sec: i64, nsec: i32, result: &mut Tm); + pub unsafe fn rust_localtime(sec: i64, nsec: i32, result: &mut Tm); + pub unsafe fn rust_timegm(tm: &Tm, sec: &mut i64); + pub unsafe fn rust_mktime(tm: &Tm, sec: &mut i64); } } @@ -172,7 +172,7 @@ pub fn at_utc(clock: Timespec) -> Tm { unsafe { let mut Timespec { sec, nsec } = clock; let mut tm = empty_tm(); - rustrt::rust_gmtime(sec, nsec, tm); + rustrt::rust_gmtime(sec, nsec, &mut tm); tm } } @@ -187,7 +187,7 @@ pub fn at(clock: Timespec) -> Tm { unsafe { let mut Timespec { sec, nsec } = clock; let mut tm = empty_tm(); - rustrt::rust_localtime(sec, nsec, tm); + rustrt::rust_localtime(sec, nsec, &mut tm); tm } } @@ -217,9 +217,9 @@ pub impl Tm { unsafe { let mut sec = 0i64; if self.tm_gmtoff == 0_i32 { - rustrt::rust_timegm(*self, &mut sec); + rustrt::rust_timegm(self, &mut sec); } else { - rustrt::rust_mktime(*self, &mut sec); + rustrt::rust_mktime(self, &mut sec); } Timespec::new(sec, self.tm_nsec) } diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 8d83e2036b9be..5a9de9735ba03 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -434,18 +434,18 @@ rust_tzset() { } extern "C" CDECL void -rust_gmtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) { +rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) { tm tm; - time_t s = *sec; + time_t s = sec; GMTIME(&s, &tm); - tm_to_rust_tm(&tm, timeptr, 0, "UTC", *nsec); + tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec); } extern "C" CDECL void -rust_localtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) { +rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) { tm tm; - time_t s = *sec; + time_t s = sec; LOCALTIME(&s, &tm); #if defined(__WIN32__) @@ -457,7 +457,7 @@ rust_localtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) { const char *zone = tm.tm_zone; #endif - tm_to_rust_tm(&tm, timeptr, gmtoff, zone, *nsec); + tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec); } extern "C" CDECL void @@ -844,6 +844,38 @@ rust_readdir() { #endif +// These functions are used in the unit tests for C ABI calls. + +extern "C" CDECL uint32_t +rust_dbg_extern_identity_u32(uint32_t u) { + return u; +} + +extern "C" CDECL uint64_t +rust_dbg_extern_identity_u64(uint64_t u) { + return u; +} + +struct TwoU64s { + uint64_t one; + uint64_t two; +}; + +extern "C" CDECL TwoU64s +rust_dbg_extern_identity_TwoU64s(TwoU64s u) { + return u; +} + +extern "C" CDECL double +rust_dbg_extern_identity_double(double u) { + return u; +} + +extern "C" CDECL char +rust_dbg_extern_identity_u8(char u) { + return u; +} + // // Local Variables: diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 886d945b144e2..7fb6334ca754c 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -195,4 +195,9 @@ rust_get_exchange_count_ptr rust_get_sched_tls_key swap_registers rust_readdir -rust_opendir \ No newline at end of file +rust_opendir +rust_dbg_extern_identity_u32 +rust_dbg_extern_identity_u64 +rust_dbg_extern_identity_TwoU64s +rust_dbg_extern_identity_double +rust_dbg_extern_identity_u8 diff --git a/src/rustllvm/RustWrapper.cpp b/src/rustllvm/RustWrapper.cpp index 7686dcd4ff4dc..12b305720cc93 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/src/rustllvm/RustWrapper.cpp @@ -546,8 +546,8 @@ extern "C" LLVMValueRef LLVMInlineAsm(LLVMTypeRef Ty, char *Constraints, LLVMBool HasSideEffects, LLVMBool IsAlignStack, - InlineAsm::AsmDialect Dialect) { + unsigned Dialect) { return wrap(InlineAsm::get(unwrap(Ty), AsmString, Constraints, HasSideEffects, - IsAlignStack, Dialect)); + IsAlignStack, (InlineAsm::AsmDialect) Dialect)); } diff --git a/src/test/run-pass/extern-pass-TwoU64s-ref.rs b/src/test/run-pass/extern-pass-TwoU64s-ref.rs new file mode 100644 index 0000000000000..00754afa703b2 --- /dev/null +++ b/src/test/run-pass/extern-pass-TwoU64s-ref.rs @@ -0,0 +1,31 @@ +// Copyright 2012 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. + +// Test that we ignore modes when calling extern functions. + +// xfail-test --- broken on 32-bit ABIs! (#5347) + +#[deriving_eq] +struct TwoU64s { + one: u64, two: u64 +} + +pub extern { + pub fn rust_dbg_extern_identity_TwoU64s(&&u: TwoU64s) -> TwoU64s; +} + +pub fn main() { + unsafe { + let x = TwoU64s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU64s(x); + fail_unless!(x == y); + } +} + diff --git a/src/test/run-pass/extern-pass-TwoU64s.rs b/src/test/run-pass/extern-pass-TwoU64s.rs new file mode 100644 index 0000000000000..2baf383ce545f --- /dev/null +++ b/src/test/run-pass/extern-pass-TwoU64s.rs @@ -0,0 +1,32 @@ +// Copyright 2012 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. + +// Test a foreign function that accepts and returns a struct +// by value. + +// xfail-test --- broken on 32-bit ABIs! (#5347) + +#[deriving_eq] +struct TwoU64s { + one: u64, two: u64 +} + +pub extern { + pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s; +} + +pub fn main() { + unsafe { + let x = TwoU64s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU64s(x); + fail_unless!(x == y); + } +} + diff --git a/src/test/run-pass/extern-pass-char.rs b/src/test/run-pass/extern-pass-char.rs new file mode 100644 index 0000000000000..104ea342cd5e0 --- /dev/null +++ b/src/test/run-pass/extern-pass-char.rs @@ -0,0 +1,22 @@ +// Copyright 2012 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. + +// Test a function that takes/returns a u8. + +pub extern { + pub fn rust_dbg_extern_identity_u8(v: u8) -> u8; +} + +pub fn main() { + unsafe { + fail_unless!(22_u8 == rust_dbg_extern_identity_u8(22_u8)); + } +} + diff --git a/src/test/run-pass/extern-pass-double.rs b/src/test/run-pass/extern-pass-double.rs new file mode 100644 index 0000000000000..afdec4d100298 --- /dev/null +++ b/src/test/run-pass/extern-pass-double.rs @@ -0,0 +1,20 @@ +// Copyright 2012 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. + +pub extern { + pub fn rust_dbg_extern_identity_double(v: f64) -> f64; +} + +pub fn main() { + unsafe { + fail_unless!(22.0_f64 == rust_dbg_extern_identity_double(22.0_f64)); + } +} + diff --git a/src/test/run-pass/extern-pass-u32.rs b/src/test/run-pass/extern-pass-u32.rs new file mode 100644 index 0000000000000..0d6220e7b25cd --- /dev/null +++ b/src/test/run-pass/extern-pass-u32.rs @@ -0,0 +1,22 @@ +// Copyright 2012 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. + +// Test a function that takes/returns a u32. + +pub extern { + pub fn rust_dbg_extern_identity_u32(v: u32) -> u32; +} + +pub fn main() { + unsafe { + fail_unless!(22_u32 == rust_dbg_extern_identity_u32(22_u32)); + } +} + diff --git a/src/test/run-pass/extern-pass-u64.rs b/src/test/run-pass/extern-pass-u64.rs new file mode 100644 index 0000000000000..3177703523833 --- /dev/null +++ b/src/test/run-pass/extern-pass-u64.rs @@ -0,0 +1,22 @@ +// Copyright 2012 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. + +// Test a call to a function that takes/returns a u64. + +pub extern { + pub fn rust_dbg_extern_identity_u64(v: u64) -> u64; +} + +pub fn main() { + unsafe { + fail_unless!(22_u64 == rust_dbg_extern_identity_u64(22_u64)); + } +} +