rustc: Translate crust functions
This commit is contained in:
parent
78034aa22a
commit
214cdd0dee
@ -28,6 +28,7 @@ type upcalls =
|
||||
dynastack_free: ValueRef,
|
||||
alloc_c_stack: ValueRef,
|
||||
call_shim_on_c_stack: ValueRef,
|
||||
call_shim_on_rust_stack: ValueRef,
|
||||
rust_personality: ValueRef,
|
||||
reset_stack_limit: ValueRef};
|
||||
|
||||
@ -106,6 +107,9 @@ fn declare_upcalls(targ_cfg: @session::config,
|
||||
// arguments: void *args, void *fn_ptr
|
||||
[T_ptr(T_i8()), T_ptr(T_i8())],
|
||||
int_t),
|
||||
call_shim_on_rust_stack:
|
||||
d("call_shim_on_rust_stack",
|
||||
[T_ptr(T_i8()), T_ptr(T_i8())], int_t),
|
||||
rust_personality:
|
||||
d("rust_personality", [], T_i32()),
|
||||
reset_stack_limit:
|
||||
|
@ -4193,14 +4193,17 @@ fn copy_args_to_allocas(fcx: @fn_ctxt, bcx: @block_ctxt, args: [ast::arg],
|
||||
// Ties up the llstaticallocas -> llloadenv -> llderivedtydescs ->
|
||||
// lldynamicallocas -> lltop edges, and builds the return block.
|
||||
fn finish_fn(fcx: @fn_ctxt, lltop: BasicBlockRef) {
|
||||
tie_up_header_blocks(fcx, lltop);
|
||||
let ret_cx = new_raw_block_ctxt(fcx, fcx.llreturn);
|
||||
trans_fn_cleanups(fcx, ret_cx);
|
||||
RetVoid(ret_cx);
|
||||
}
|
||||
|
||||
fn tie_up_header_blocks(fcx: @fn_ctxt, lltop: BasicBlockRef) {
|
||||
Br(new_raw_block_ctxt(fcx, fcx.llstaticallocas), fcx.llloadenv);
|
||||
Br(new_raw_block_ctxt(fcx, fcx.llloadenv), fcx.llderivedtydescs_first);
|
||||
Br(new_raw_block_ctxt(fcx, fcx.llderivedtydescs), fcx.lldynamicallocas);
|
||||
Br(new_raw_block_ctxt(fcx, fcx.lldynamicallocas), lltop);
|
||||
|
||||
let ret_cx = new_raw_block_ctxt(fcx, fcx.llreturn);
|
||||
trans_fn_cleanups(fcx, ret_cx);
|
||||
RetVoid(ret_cx);
|
||||
}
|
||||
|
||||
enum self_arg { impl_self(ty::t), no_self, }
|
||||
@ -4552,13 +4555,20 @@ fn param_bounds(ccx: @crate_ctxt, tp: ast::ty_param) -> ty::param_bounds {
|
||||
ccx.tcx.ty_param_bounds.get(tp.id)
|
||||
}
|
||||
|
||||
fn register_fn_full(ccx: @crate_ctxt, sp: span, path: path, _flav: str,
|
||||
fn register_fn_full(ccx: @crate_ctxt, sp: span, path: path, flav: str,
|
||||
tps: [ast::ty_param], node_id: ast::node_id,
|
||||
node_type: ty::t) {
|
||||
let llfty = type_of_fn_from_ty(ccx, node_type,
|
||||
vec::map(tps, {|p| param_bounds(ccx, p)}));
|
||||
register_fn_fuller(ccx, sp, path, flav, node_id, node_type,
|
||||
lib::llvm::CCallConv, llfty);
|
||||
}
|
||||
|
||||
fn register_fn_fuller(ccx: @crate_ctxt, sp: span, path: path, _flav: str,
|
||||
node_id: ast::node_id, node_type: ty::t,
|
||||
cc: lib::llvm::CallConv, llfty: TypeRef) {
|
||||
let ps: str = mangle_exported_name(ccx, path, node_type);
|
||||
let llfn: ValueRef = decl_cdecl_fn(ccx.llmod, ps, llfty);
|
||||
let llfn: ValueRef = decl_fn(ccx.llmod, ps, cc, llfty);
|
||||
ccx.item_ids.insert(node_id, llfn);
|
||||
ccx.item_symbols.insert(node_id, ps);
|
||||
|
||||
@ -4747,9 +4757,13 @@ fn collect_item(ccx: @crate_ctxt, abi: @mutable option<ast::native_abi>,
|
||||
either::right(abi_) { *abi = option::some(abi_); }
|
||||
}
|
||||
}
|
||||
ast::item_fn(_, tps, _) {
|
||||
register_fn(ccx, i.span, my_path, "fn", tps,
|
||||
i.id);
|
||||
ast::item_fn(decl, tps, _) {
|
||||
if decl.purity != ast::crust_fn {
|
||||
register_fn(ccx, i.span, my_path, "fn", tps,
|
||||
i.id);
|
||||
} else {
|
||||
native::register_crust_fn(ccx, i.span, my_path, i.id);
|
||||
}
|
||||
}
|
||||
ast::item_impl(tps, _, _, methods) {
|
||||
let path = my_path + [path_name(int::str(i.id))];
|
||||
|
@ -1,13 +1,15 @@
|
||||
import driver::session::session;
|
||||
import syntax::codemap::span;
|
||||
import ctypes::c_uint;
|
||||
import front::attr;
|
||||
import lib::llvm::{ llvm, TypeRef, ValueRef };
|
||||
import syntax::ast;
|
||||
import back::link;
|
||||
import common::*;
|
||||
import build::*;
|
||||
import base::*;
|
||||
|
||||
export link_name, trans_native_mod, trans_crust_fn;
|
||||
export link_name, trans_native_mod, register_crust_fn, trans_crust_fn;
|
||||
|
||||
fn link_name(i: @ast::native_item) -> str {
|
||||
alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") {
|
||||
@ -20,34 +22,110 @@ type c_stack_tys = {
|
||||
arg_tys: [TypeRef],
|
||||
ret_ty: TypeRef,
|
||||
ret_def: bool,
|
||||
base_fn_ty: TypeRef,
|
||||
bundle_ty: TypeRef,
|
||||
shim_fn_ty: TypeRef
|
||||
};
|
||||
|
||||
fn c_stack_tys(ccx: @crate_ctxt,
|
||||
id: ast::node_id) -> @c_stack_tys {
|
||||
fn c_arg_and_ret_lltys(ccx: @crate_ctxt,
|
||||
id: ast::node_id) -> ([TypeRef], TypeRef, ty::t) {
|
||||
alt ty::get(ty::node_id_to_type(ccx.tcx, id)).struct {
|
||||
ty::ty_fn({inputs: arg_tys, output: ret_ty, _}) {
|
||||
let llargtys = type_of_explicit_args(ccx, arg_tys);
|
||||
let llretty = type_of(ccx, ret_ty);
|
||||
let bundle_ty = T_struct(llargtys + [T_ptr(llretty)]);
|
||||
ret @{
|
||||
arg_tys: llargtys,
|
||||
ret_ty: llretty,
|
||||
ret_def: !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty),
|
||||
base_fn_ty: T_fn(llargtys, llretty),
|
||||
bundle_ty: bundle_ty,
|
||||
shim_fn_ty: T_fn([T_ptr(bundle_ty)], T_void())
|
||||
};
|
||||
(llargtys, llretty, ret_ty)
|
||||
}
|
||||
_ {
|
||||
// Precondition?
|
||||
ccx.tcx.sess.bug("c_stack_tys called on non-function type");
|
||||
ccx.tcx.sess.bug("c_arg_and_ret_lltys called on non-function type");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn c_stack_tys(ccx: @crate_ctxt,
|
||||
id: ast::node_id) -> @c_stack_tys {
|
||||
let (llargtys, llretty, ret_ty) = c_arg_and_ret_lltys(ccx, id);
|
||||
let bundle_ty = T_struct(llargtys + [T_ptr(llretty)]);
|
||||
ret @{
|
||||
arg_tys: llargtys,
|
||||
ret_ty: llretty,
|
||||
ret_def: !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty),
|
||||
bundle_ty: bundle_ty,
|
||||
shim_fn_ty: T_fn([T_ptr(bundle_ty)], T_void())
|
||||
};
|
||||
}
|
||||
|
||||
type shim_arg_builder = fn(bcx: @block_ctxt, tys: @c_stack_tys,
|
||||
llargbundle: ValueRef) -> [ValueRef];
|
||||
|
||||
type shim_ret_builder = fn(bcx: @block_ctxt, tys: @c_stack_tys,
|
||||
llargbundle: ValueRef, llretval: ValueRef);
|
||||
|
||||
fn build_shim_fn_(ccx: @crate_ctxt,
|
||||
shim_name: str,
|
||||
llbasefn: ValueRef,
|
||||
tys: @c_stack_tys,
|
||||
cc: lib::llvm::CallConv,
|
||||
arg_builder: shim_arg_builder,
|
||||
ret_builder: shim_ret_builder) -> ValueRef {
|
||||
|
||||
let llshimfn = decl_internal_cdecl_fn(
|
||||
ccx.llmod, shim_name, tys.shim_fn_ty);
|
||||
|
||||
// Declare the body of the shim function:
|
||||
let fcx = new_fn_ctxt(ccx, [], llshimfn, none);
|
||||
let bcx = new_top_block_ctxt(fcx, none);
|
||||
let lltop = bcx.llbb;
|
||||
let llargbundle = llvm::LLVMGetParam(llshimfn, 0 as c_uint);
|
||||
let llargvals = arg_builder(bcx, tys, llargbundle);
|
||||
|
||||
// Create the call itself and store the return value:
|
||||
let llretval = CallWithConv(bcx, llbasefn,
|
||||
llargvals, cc); // r
|
||||
|
||||
ret_builder(bcx, tys, llargbundle, llretval);
|
||||
|
||||
build_return(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
|
||||
ret llshimfn;
|
||||
}
|
||||
|
||||
type wrap_arg_builder = fn(bcx: @block_ctxt, tys: @c_stack_tys,
|
||||
llwrapfn: ValueRef,
|
||||
llargbundle: ValueRef);
|
||||
|
||||
type wrap_ret_builder = fn(bcx: @block_ctxt, tys: @c_stack_tys,
|
||||
llargbundle: ValueRef);
|
||||
|
||||
fn build_wrap_fn_(ccx: @crate_ctxt,
|
||||
tys: @c_stack_tys,
|
||||
llshimfn: ValueRef,
|
||||
llwrapfn: ValueRef,
|
||||
shim_upcall: ValueRef,
|
||||
arg_builder: wrap_arg_builder,
|
||||
ret_builder: wrap_ret_builder) {
|
||||
|
||||
let fcx = new_fn_ctxt(ccx, [], llwrapfn, none);
|
||||
let bcx = new_top_block_ctxt(fcx, none);
|
||||
let lltop = bcx.llbb;
|
||||
|
||||
// Allocate the struct and write the arguments into it.
|
||||
let llargbundle = alloca(bcx, tys.bundle_ty);
|
||||
arg_builder(bcx, tys, llwrapfn, llargbundle);
|
||||
|
||||
// Create call itself.
|
||||
let llshimfnptr = PointerCast(bcx, llshimfn, T_ptr(T_i8()));
|
||||
let llrawargbundle = PointerCast(bcx, llargbundle, T_ptr(T_i8()));
|
||||
Call(bcx, shim_upcall, [llrawargbundle, llshimfnptr]);
|
||||
ret_builder(bcx, tys, llargbundle);
|
||||
|
||||
tie_up_header_blocks(fcx, lltop);
|
||||
|
||||
// Make sure our standard return block (that we didn't use) is terminated
|
||||
let ret_cx = new_raw_block_ctxt(fcx, fcx.llreturn);
|
||||
Unreachable(ret_cx);
|
||||
}
|
||||
|
||||
// For each native function F, we generate a wrapper function W and a shim
|
||||
// function S that all work together. The wrapper function W is the function
|
||||
// that other rust code actually invokes. Its job is to marshall the
|
||||
@ -89,46 +167,41 @@ fn trans_native_mod(ccx: @crate_ctxt,
|
||||
native_item: @ast::native_item,
|
||||
tys: @c_stack_tys,
|
||||
cc: lib::llvm::CallConv) -> ValueRef {
|
||||
|
||||
fn build_args(bcx: @block_ctxt, tys: @c_stack_tys,
|
||||
llargbundle: ValueRef) -> [ValueRef] {
|
||||
let llargvals = [];
|
||||
let i = 0u;
|
||||
let n = vec::len(tys.arg_tys);
|
||||
while i < n {
|
||||
let llargval = load_inbounds(bcx, llargbundle, [0, i as int]);
|
||||
llargvals += [llargval];
|
||||
i += 1u;
|
||||
}
|
||||
ret llargvals;
|
||||
}
|
||||
|
||||
fn build_ret(bcx: @block_ctxt, tys: @c_stack_tys,
|
||||
llargbundle: ValueRef, llretval: ValueRef) {
|
||||
if tys.ret_def {
|
||||
let n = vec::len(tys.arg_tys);
|
||||
// R** llretptr = &args->r;
|
||||
let llretptr = GEPi(bcx, llargbundle, [0, n as int]);
|
||||
// R* llretloc = *llretptr; /* (args->r) */
|
||||
let llretloc = Load(bcx, llretptr);
|
||||
// *args->r = r;
|
||||
Store(bcx, llretval, llretloc);
|
||||
}
|
||||
}
|
||||
|
||||
let lname = link_name(native_item);
|
||||
|
||||
// Declare the "prototype" for the base function F:
|
||||
let llbasefn = decl_fn(ccx.llmod, lname, cc, tys.base_fn_ty);
|
||||
|
||||
// Create the shim function:
|
||||
let llbasefnty = T_fn(tys.arg_tys, tys.ret_ty);
|
||||
let llbasefn = decl_fn(ccx.llmod, lname, cc, llbasefnty);
|
||||
// Name the shim function
|
||||
let shim_name = lname + "__c_stack_shim";
|
||||
let llshimfn = decl_internal_cdecl_fn(
|
||||
ccx.llmod, shim_name, tys.shim_fn_ty);
|
||||
|
||||
// Declare the body of the shim function:
|
||||
let fcx = new_fn_ctxt(ccx, [], llshimfn, none);
|
||||
let bcx = new_top_block_ctxt(fcx, none);
|
||||
let lltop = bcx.llbb;
|
||||
let llargbundle = llvm::LLVMGetParam(llshimfn, 0 as c_uint);
|
||||
let i = 0u, n = vec::len(tys.arg_tys);
|
||||
let llargvals = [];
|
||||
while i < n {
|
||||
let llargval = load_inbounds(bcx, llargbundle, [0, i as int]);
|
||||
llargvals += [llargval];
|
||||
i += 1u;
|
||||
}
|
||||
|
||||
// Create the call itself and store the return value:
|
||||
let llretval = CallWithConv(bcx, llbasefn,
|
||||
llargvals, cc); // r
|
||||
if tys.ret_def {
|
||||
// R** llretptr = &args->r;
|
||||
let llretptr = GEPi(bcx, llargbundle, [0, n as int]);
|
||||
// R* llretloc = *llretptr; /* (args->r) */
|
||||
let llretloc = Load(bcx, llretptr);
|
||||
// *args->r = r;
|
||||
Store(bcx, llretval, llretloc);
|
||||
}
|
||||
|
||||
// Finish up:
|
||||
build_return(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
|
||||
ret llshimfn;
|
||||
ret build_shim_fn_(ccx, shim_name, llbasefn, tys, cc,
|
||||
build_args, build_ret);
|
||||
}
|
||||
|
||||
fn build_wrap_fn(ccx: @crate_ctxt,
|
||||
@ -136,30 +209,32 @@ fn trans_native_mod(ccx: @crate_ctxt,
|
||||
num_tps: uint,
|
||||
llshimfn: ValueRef,
|
||||
llwrapfn: ValueRef) {
|
||||
let fcx = new_fn_ctxt(ccx, [], llwrapfn, none);
|
||||
let bcx = new_top_block_ctxt(fcx, none);
|
||||
let lltop = bcx.llbb;
|
||||
|
||||
// Allocate the struct and write the arguments into it.
|
||||
let llargbundle = alloca(bcx, tys.bundle_ty);
|
||||
let i = 0u, n = vec::len(tys.arg_tys);
|
||||
let implicit_args = 2u + num_tps; // ret + env
|
||||
while i < n {
|
||||
let llargval = llvm::LLVMGetParam(llwrapfn,
|
||||
(i + implicit_args) as c_uint);
|
||||
store_inbounds(bcx, llargval, llargbundle, [0, i as int]);
|
||||
i += 1u;
|
||||
fn build_args(bcx: @block_ctxt, tys: @c_stack_tys,
|
||||
llwrapfn: ValueRef, llargbundle: ValueRef,
|
||||
num_tps: uint) {
|
||||
let i = 0u, n = vec::len(tys.arg_tys);
|
||||
let implicit_args = 2u + num_tps; // ret + env
|
||||
while i < n {
|
||||
let llargval = llvm::LLVMGetParam(
|
||||
llwrapfn,
|
||||
(i + implicit_args) as c_uint);
|
||||
store_inbounds(bcx, llargval, llargbundle, [0, i as int]);
|
||||
i += 1u;
|
||||
}
|
||||
let llretptr = llvm::LLVMGetParam(llwrapfn, 0 as c_uint);
|
||||
store_inbounds(bcx, llretptr, llargbundle, [0, n as int]);
|
||||
}
|
||||
let llretptr = llvm::LLVMGetParam(llwrapfn, 0 as c_uint);
|
||||
store_inbounds(bcx, llretptr, llargbundle, [0, n as int]);
|
||||
|
||||
// Create call itself.
|
||||
let call_shim_on_c_stack = ccx.upcalls.call_shim_on_c_stack;
|
||||
let llshimfnptr = PointerCast(bcx, llshimfn, T_ptr(T_i8()));
|
||||
let llrawargbundle = PointerCast(bcx, llargbundle, T_ptr(T_i8()));
|
||||
Call(bcx, call_shim_on_c_stack, [llrawargbundle, llshimfnptr]);
|
||||
build_return(bcx);
|
||||
finish_fn(fcx, lltop);
|
||||
fn build_ret(bcx: @block_ctxt, _tys: @c_stack_tys,
|
||||
_llargbundle: ValueRef) {
|
||||
RetVoid(bcx);
|
||||
}
|
||||
|
||||
build_wrap_fn_(ccx, tys, llshimfn, llwrapfn,
|
||||
ccx.upcalls.call_shim_on_c_stack,
|
||||
bind build_args(_, _ ,_ , _, num_tps),
|
||||
build_ret);
|
||||
}
|
||||
|
||||
let cc = lib::llvm::CCallConv;
|
||||
@ -180,7 +255,7 @@ fn trans_native_mod(ccx: @crate_ctxt,
|
||||
build_wrap_fn(ccx, tys, vec::len(tps), llshimfn, llwrapfn);
|
||||
}
|
||||
none {
|
||||
ccx.sess.span_fatal(
|
||||
ccx.sess.span_bug(
|
||||
native_item.span,
|
||||
"unbound function item in trans_native_mod");
|
||||
}
|
||||
@ -191,6 +266,96 @@ fn trans_native_mod(ccx: @crate_ctxt,
|
||||
}
|
||||
|
||||
fn trans_crust_fn(ccx: @crate_ctxt, path: ast_map::path, decl: ast::fn_decl,
|
||||
body: ast::blk, llfndecl: ValueRef, id: ast::node_id) {
|
||||
trans_fn(ccx, path, decl, body, llfndecl, no_self, [], none, id)
|
||||
body: ast::blk, llwrapfn: ValueRef, id: ast::node_id) {
|
||||
|
||||
fn build_rust_fn(ccx: @crate_ctxt, path: ast_map::path,
|
||||
decl: ast::fn_decl, body: ast::blk,
|
||||
id: ast::node_id) -> ValueRef {
|
||||
let t = ty::node_id_to_type(ccx.tcx, id);
|
||||
let ps = link::mangle_internal_name_by_path(
|
||||
ccx, path + [ast_map::path_name("__rust_abi")]);
|
||||
let llty = type_of_fn_from_ty(ccx, t, []);
|
||||
let llfndecl = decl_internal_cdecl_fn(ccx.llmod, ps, llty);
|
||||
trans_fn(ccx, path, decl, body, llfndecl, no_self, [], none, id);
|
||||
ret llfndecl;
|
||||
}
|
||||
|
||||
fn build_shim_fn(ccx: @crate_ctxt, path: ast_map::path,
|
||||
llrustfn: ValueRef, tys: @c_stack_tys) -> ValueRef {
|
||||
|
||||
fn build_args(bcx: @block_ctxt, tys: @c_stack_tys,
|
||||
llargbundle: ValueRef) -> [ValueRef] {
|
||||
let llargvals = [];
|
||||
let i = 0u;
|
||||
let n = vec::len(tys.arg_tys);
|
||||
let llretptr = load_inbounds(bcx, llargbundle, [0, n as int]);
|
||||
llargvals += [llretptr];
|
||||
let llenvptr = C_null(T_opaque_box_ptr(bcx_ccx(bcx)));
|
||||
llargvals += [llenvptr];
|
||||
while i < n {
|
||||
let llargval = load_inbounds(bcx, llargbundle, [0, i as int]);
|
||||
llargvals += [llargval];
|
||||
i += 1u;
|
||||
}
|
||||
ret llargvals;
|
||||
}
|
||||
|
||||
fn build_ret(_bcx: @block_ctxt, _tys: @c_stack_tys,
|
||||
_llargbundle: ValueRef, _llretval: ValueRef) {
|
||||
// Nop. The return pointer in the Rust ABI function
|
||||
// is wired directly into the return slot in the shim struct
|
||||
}
|
||||
|
||||
let shim_name = link::mangle_internal_name_by_path(
|
||||
ccx, path + [ast_map::path_name("__rust_stack_shim")]);
|
||||
ret build_shim_fn_(ccx, shim_name, llrustfn, tys,
|
||||
lib::llvm::CCallConv,
|
||||
build_args, build_ret);
|
||||
}
|
||||
|
||||
fn build_wrap_fn(ccx: @crate_ctxt, llshimfn: ValueRef,
|
||||
llwrapfn: ValueRef, tys: @c_stack_tys) {
|
||||
|
||||
fn build_args(bcx: @block_ctxt, tys: @c_stack_tys,
|
||||
llwrapfn: ValueRef, llargbundle: ValueRef) {
|
||||
let llretptr = alloca(bcx, tys.ret_ty);
|
||||
let i = 0u, n = vec::len(tys.arg_tys);
|
||||
while i < n {
|
||||
let llargval = llvm::LLVMGetParam(
|
||||
llwrapfn, i as c_uint);
|
||||
store_inbounds(bcx, llargval, llargbundle, [0, i as int]);
|
||||
i += 1u;
|
||||
}
|
||||
store_inbounds(bcx, llretptr, llargbundle, [0, n as int]);
|
||||
}
|
||||
|
||||
fn build_ret(bcx: @block_ctxt, tys: @c_stack_tys,
|
||||
llargbundle: ValueRef) {
|
||||
let n = vec::len(tys.arg_tys);
|
||||
let llretval = load_inbounds(bcx, llargbundle, [0, n as int]);
|
||||
let llretval = Load(bcx, llretval);
|
||||
Ret(bcx, llretval);
|
||||
}
|
||||
|
||||
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);
|
||||
// The internal Rust ABI function - runs on the Rust stack
|
||||
let llrustfn = build_rust_fn(ccx, path, decl, body, id);
|
||||
// The internal shim function - runs on the Rust stack
|
||||
let llshimfn = build_shim_fn(ccx, path, llrustfn, tys);
|
||||
// The external C function - runs on the C stack
|
||||
build_wrap_fn(ccx, llshimfn, llwrapfn, tys)
|
||||
}
|
||||
|
||||
fn register_crust_fn(ccx: @crate_ctxt, sp: span,
|
||||
path: ast_map::path, node_id: ast::node_id) {
|
||||
let t = ty::node_id_to_type(ccx.tcx, node_id);
|
||||
let (llargtys, llretty, _) = c_arg_and_ret_lltys(ccx, node_id);
|
||||
let llfty = T_fn(llargtys, llretty);
|
||||
register_fn_fuller(ccx, sp, path, "crust fn", node_id,
|
||||
t, lib::llvm::CCallConv, llfty);
|
||||
}
|
@ -657,8 +657,8 @@ rust_dbg_lock_signal(lock_and_signal *lock) {
|
||||
typedef void *(*dbg_callback)(void*);
|
||||
|
||||
extern "C" CDECL void *
|
||||
rust_dbg_call(dbg_callback *cb, void *data) {
|
||||
return (*cb)(data);
|
||||
rust_dbg_call(dbg_callback cb, void *data) {
|
||||
return cb(data);
|
||||
}
|
||||
|
||||
//
|
||||
|
23
src/test/run-pass/crust-call-deep.rs
Normal file
23
src/test/run-pass/crust-call-deep.rs
Normal file
@ -0,0 +1,23 @@
|
||||
native mod rustrt {
|
||||
fn rust_dbg_call(cb: *u8,
|
||||
data: ctypes::uintptr_t) -> ctypes::uintptr_t;
|
||||
}
|
||||
|
||||
crust fn cb(data: ctypes::uintptr_t) -> ctypes::uintptr_t {
|
||||
if data == 1u {
|
||||
data
|
||||
} else {
|
||||
count(data - 1u) + 1u
|
||||
}
|
||||
}
|
||||
|
||||
fn count(n: uint) -> uint {
|
||||
#debug("n = %?", n);
|
||||
rustrt::rust_dbg_call(cb, n)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let result = count(1000u);
|
||||
#debug("result = %?", result);
|
||||
assert result == 1000u;
|
||||
}
|
23
src/test/run-pass/crust-call.rs
Normal file
23
src/test/run-pass/crust-call.rs
Normal file
@ -0,0 +1,23 @@
|
||||
native mod rustrt {
|
||||
fn rust_dbg_call(cb: *u8,
|
||||
data: ctypes::uintptr_t) -> ctypes::uintptr_t;
|
||||
}
|
||||
|
||||
crust fn cb(data: ctypes::uintptr_t) -> ctypes::uintptr_t {
|
||||
if data == 1u {
|
||||
data
|
||||
} else {
|
||||
fact(data - 1u) * data
|
||||
}
|
||||
}
|
||||
|
||||
fn fact(n: uint) -> uint {
|
||||
#debug("n = %?", n);
|
||||
rustrt::rust_dbg_call(cb, n)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let result = fact(10u);
|
||||
#debug("result = %?", result);
|
||||
assert result == 3628800u;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user