auto merge of #8666 : nikomatsakis/rust/issue-3678-extern-fn-types, r=pcwalton

Change the type of crust fns like this one:

    extern fn foo() { ... }

from `*u8` to `extern "C" fn()`.

r? @pcwalton (or whomever)
This commit is contained in:
bors 2013-08-22 07:01:27 -07:00
commit 4e3dbf959a
29 changed files with 385 additions and 131 deletions

View File

@ -1006,20 +1006,25 @@ code_. They are defined in the same way as any other Rust function,
except that they have the `extern` modifier.
~~~
// Declares an extern fn, the ABI defaults to "C"
extern fn new_vec() -> ~[int] { ~[] }
// Declares an extern fn with "stdcall" ABI
extern "stdcall" fn new_vec_stdcall() -> ~[int] { ~[] }
~~~
Extern functions may not be called from Rust code,
but Rust code may take their value as a raw `u8` pointer.
Unlike normal functions, extern fns have an `extern "ABI" fn()`.
This is the same type as the functions declared in an extern
block.
~~~
# extern fn new_vec() -> ~[int] { ~[] }
let fptr: *u8 = new_vec;
let fptr: extern "C" fn() -> ~[int] = new_vec;
~~~
The primary motivation for extern functions is
to create callbacks for foreign functions that expect to receive function
pointers.
Extern functions may be called from Rust code, but
caution must be taken with respect to the size of the stack
segment, just as when calling an extern function normally.
### Type definitions
@ -1384,14 +1389,13 @@ between the Rust ABI and the foreign ABI.
A number of [attributes](#attributes) control the behavior of external
blocks.
By default external blocks assume
that the library they are calling uses the standard C "cdecl" ABI.
Other ABIs may be specified using the `abi` attribute as in
By default external blocks assume that the library they are calling
uses the standard C "cdecl" ABI. Other ABIs may be specified using
an `abi` string, as shown here:
~~~{.xfail-test}
// Interface to the Windows API
#[abi = "stdcall"]
extern { }
extern "stdcall" { }
~~~
The `link_name` attribute allows the name of the library to be specified.
@ -1407,6 +1411,12 @@ This is particularly useful for creating external blocks for libc,
which tends to not follow standard library naming conventions
and is linked to all Rust programs anyway.
The type of a function
declared in an extern block
is `extern "abi" fn(A1, ..., An) -> R`,
where `A1...An` are the declared types of its arguments
and `R` is the decalred return type.
## Attributes
~~~~~~~~{.ebnf .gram}

View File

@ -16,27 +16,31 @@ use std::libc::{c_char, c_int};
use std::local_data;
use std::str;
#[cfg(stage0)]
pub mod rustrt {
use std::libc::{c_char, c_int};
#[cfg(stage0)]
mod macro_hack {
#[macro_escape];
macro_rules! externfn(
(fn $name:ident ($($arg_name:ident : $arg_ty:ty),*) $(-> $ret_ty:ty),*) => (
extern {
fn $name($($arg_name : $arg_ty),*) $(-> $ret_ty),*;
}
)
)
extern {
fn linenoise(prompt: *c_char) -> *c_char;
fn linenoiseHistoryAdd(line: *c_char) -> c_int;
fn linenoiseHistorySetMaxLen(len: c_int) -> c_int;
fn linenoiseHistorySave(file: *c_char) -> c_int;
fn linenoiseHistoryLoad(file: *c_char) -> c_int;
fn linenoiseSetCompletionCallback(callback: *u8);
fn linenoiseAddCompletion(completions: *(), line: *c_char);
}
}
#[cfg(not(stage0))]
pub mod rustrt {
use std::libc::{c_char, c_int};
externfn!(fn linenoise(prompt: *c_char) -> *c_char)
externfn!(fn linenoiseHistoryAdd(line: *c_char) -> c_int)
externfn!(fn linenoiseHistorySetMaxLen(len: c_int) -> c_int)
externfn!(fn linenoiseHistorySave(file: *c_char) -> c_int)
externfn!(fn linenoiseHistoryLoad(file: *c_char) -> c_int)
externfn!(fn linenoiseSetCompletionCallback(callback: *u8))
externfn!(fn linenoiseSetCompletionCallback(callback: extern "C" fn(*i8, *())))
externfn!(fn linenoiseAddCompletion(completions: *(), line: *c_char))
}

View File

@ -52,6 +52,7 @@ use middle::trans::expr;
use middle::trans::foreign;
use middle::trans::glue;
use middle::trans::inline;
use middle::trans::llrepr::LlvmRepr;
use middle::trans::machine;
use middle::trans::machine::{llalign_of_min, llsize_of};
use middle::trans::meth;
@ -1739,6 +1740,10 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext,
args: &[ast::arg],
raw_llargs: &[ValueRef],
arg_tys: &[ty::t]) -> @mut Block {
debug!("copy_args_to_allocas: raw_llargs=%s arg_tys=%s",
raw_llargs.llrepr(fcx.ccx),
arg_tys.repr(fcx.ccx.tcx));
let _icx = push_ctxt("copy_args_to_allocas");
let mut bcx = bcx;

View File

@ -22,6 +22,7 @@ use std::hashmap::HashMap;
use std::libc::{c_uint, c_ulonglong, c_char};
use std::vec;
use syntax::codemap::span;
use std::ptr::is_not_null;
pub struct Builder {
llbuilder: BuilderRef,
@ -483,6 +484,7 @@ impl Builder {
debug!("Store %s -> %s",
self.ccx.tn.val_to_str(val),
self.ccx.tn.val_to_str(ptr));
assert!(is_not_null(self.llbuilder));
self.count_insn("store");
unsafe {
llvm::LLVMBuildStore(self.llbuilder, val, ptr);

View File

@ -824,56 +824,30 @@ fn trans_def_datum_unadjusted(bcx: @mut Block,
{
let _icx = push_ctxt("trans_def_datum_unadjusted");
match def {
let fn_data = match def {
ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id);
return fn_data_to_datum(bcx, ref_expr, did, fn_data);
callee::trans_fn_ref(bcx, did, ref_expr.id)
}
ast::def_static_method(impl_did, Some(trait_did), _) => {
let fn_data = meth::trans_static_method_callee(bcx, impl_did,
trait_did,
ref_expr.id);
return fn_data_to_datum(bcx, ref_expr, impl_did, fn_data);
meth::trans_static_method_callee(bcx, impl_did,
trait_did,
ref_expr.id)
}
_ => {
bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
"Non-DPS def %? referened by %s",
def, bcx.node_id_to_str(ref_expr.id)));
}
}
};
fn fn_data_to_datum(bcx: @mut Block,
ref_expr: &ast::expr,
def_id: ast::def_id,
fn_data: callee::FnData) -> DatumBlock {
/*!
*
* Translates a reference to a top-level fn item into a rust
* value. This is just a fn pointer.
*/
let is_extern = {
let fn_tpt = ty::lookup_item_type(bcx.tcx(), def_id);
ty::ty_fn_purity(fn_tpt.ty) == ast::extern_fn
};
let (rust_ty, llval) = if is_extern {
let rust_ty = ty::mk_ptr(
bcx.tcx(),
ty::mt {
ty: ty::mk_mach_uint(ast::ty_u8),
mutbl: ast::m_imm
}); // *u8
(rust_ty, PointerCast(bcx, fn_data.llfn, Type::i8p()))
} else {
let fn_ty = expr_ty(bcx, ref_expr);
(fn_ty, fn_data.llfn)
};
return DatumBlock {
bcx: bcx,
datum: Datum {val: llval,
ty: rust_ty,
mode: ByValue}
};
let fn_ty = expr_ty(bcx, ref_expr);
DatumBlock {
bcx: bcx,
datum: Datum {
val: fn_data.llfn,
ty: fn_ty,
mode: ByValue
}
}
}
@ -1657,6 +1631,7 @@ pub fn cast_type_kind(t: ty::t) -> cast_kind {
ty::ty_float(*) => cast_float,
ty::ty_ptr(*) => cast_pointer,
ty::ty_rptr(*) => cast_pointer,
ty::ty_bare_fn(*) => cast_pointer,
ty::ty_int(*) => cast_integral,
ty::ty_uint(*) => cast_integral,
ty::ty_bool => cast_integral,
@ -1719,10 +1694,16 @@ fn trans_imm_cast(bcx: @mut Block, expr: @ast::expr,
val_ty(lldiscrim_a),
lldiscrim_a, true),
cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
_ => ccx.sess.bug("translating unsupported cast.")
_ => ccx.sess.bug(fmt!("translating unsupported cast: \
%s (%?) -> %s (%?)",
t_in.repr(ccx.tcx), k_in,
t_out.repr(ccx.tcx), k_out))
}
}
_ => ccx.sess.bug("translating unsupported cast.")
_ => ccx.sess.bug(fmt!("translating unsupported cast: \
%s (%?) -> %s (%?)",
t_in.repr(ccx.tcx), k_in,
t_out.repr(ccx.tcx), k_out))
};
return immediate_rvalue_bcx(bcx, newval, t_out);
}

View File

@ -21,6 +21,7 @@ use middle::trans::cabi;
use middle::trans::build::*;
use middle::trans::builder::noname;
use middle::trans::common::*;
use middle::trans::llrepr::LlvmRepr;
use middle::trans::type_of::*;
use middle::trans::type_of;
use middle::ty;
@ -399,7 +400,29 @@ pub fn trans_rust_fn_with_foreign_abi(ccx: @mut CrateContext,
ccx, vec::append_one((*path).clone(), ast_map::path_name(
special_idents::clownshoe_abi
)));
let llty = type_of_fn_from_ty(ccx, t);
// Compute the LLVM type that the function would have if it
// were just a normal Rust function. This will be the type of
// the wrappee fn.
let llty = match ty::get(t).sty {
ty::ty_bare_fn(ref f) => {
assert!(!f.abis.is_rust() && !f.abis.is_intrinsic());
type_of_rust_fn(ccx, f.sig.inputs, f.sig.output)
}
_ => {
ccx.sess.bug(fmt!("build_rust_fn: extern fn %s has ty %s, \
expected a bare fn ty",
path.repr(tcx),
t.repr(tcx)));
}
};
debug!("build_rust_fn: path=%s id=%? t=%s llty=%s",
path.repr(tcx),
id,
t.repr(tcx),
llty.llrepr(ccx));
let llfndecl = base::decl_internal_cdecl_fn(ccx.llmod, ps, llty);
base::trans_fn(ccx,
(*path).clone(),

View File

@ -0,0 +1,38 @@
// 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 <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.
use middle::trans::context::CrateContext;
use middle::trans::type_::Type;
use lib::llvm::ValueRef;
pub trait LlvmRepr {
fn llrepr(&self, ccx: &CrateContext) -> ~str;
}
impl<'self, T:LlvmRepr> LlvmRepr for &'self [T] {
fn llrepr(&self, ccx: &CrateContext) -> ~str {
let reprs = self.map(|t| t.llrepr(ccx));
fmt!("[%s]", reprs.connect(","))
}
}
impl LlvmRepr for Type {
fn llrepr(&self, ccx: &CrateContext) -> ~str {
ccx.tn.type_to_str(*self)
}
}
impl LlvmRepr for ValueRef {
fn llrepr(&self, ccx: &CrateContext) -> ~str {
ccx.tn.val_to_str(*self)
}
}

View File

@ -45,3 +45,4 @@ pub mod asm;
pub mod type_;
pub mod value;
pub mod basic_block;
pub mod llrepr;

View File

@ -3099,22 +3099,6 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
let typ = fcx.local_ty(sp, nid);
return no_params(typ);
}
ast::def_fn(_, ast::extern_fn) => {
// extern functions are just u8 pointers
return ty_param_bounds_and_ty {
generics: ty::Generics {
type_param_defs: @~[],
region_param: None
},
ty: ty::mk_ptr(
fcx.ccx.tcx,
ty::mt {
ty: ty::mk_mach_uint(ast::ty_u8),
mutbl: ast::m_imm
})
};
}
ast::def_fn(id, _) | ast::def_static_method(id, _, _) |
ast::def_static(id, _) | ast::def_variant(_, id) |
ast::def_struct(id) => {

View File

@ -1087,13 +1087,13 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::item)
tcx.tcache.insert(local_def(it.id), tpt);
return tpt;
}
ast::item_fn(ref decl, purity, _, ref generics, _) => {
ast::item_fn(ref decl, purity, abi, ref generics, _) => {
assert!(rp.is_none());
let ty_generics = ty_generics(ccx, None, generics, 0);
let tofd = astconv::ty_of_bare_fn(ccx,
&empty_rscope,
purity,
AbiSet::Rust(),
abi,
&generics.lifetimes,
decl);
let tpt = ty_param_bounds_and_ty {

View File

@ -369,6 +369,47 @@ impl<T> Eq for *const T {
fn ne(&self, other: &*const T) -> bool { !self.eq(other) }
}
// Equality for extern "C" fn pointers
#[cfg(not(test))]
mod externfnpointers {
use cast;
use cmp::Eq;
impl<_R> Eq for extern "C" fn() -> _R {
#[inline]
fn eq(&self, other: &extern "C" fn() -> _R) -> bool {
let self_: *() = unsafe { cast::transmute(*self) };
let other_: *() = unsafe { cast::transmute(*other) };
self_ == other_
}
#[inline]
fn ne(&self, other: &extern "C" fn() -> _R) -> bool {
!self.eq(other)
}
}
macro_rules! fnptreq(
($($p:ident),*) => {
impl<_R,$($p),*> Eq for extern "C" fn($($p),*) -> _R {
#[inline]
fn eq(&self, other: &extern "C" fn($($p),*) -> _R) -> bool {
let self_: *() = unsafe { cast::transmute(*self) };
let other_: *() = unsafe { cast::transmute(*other) };
self_ == other_
}
#[inline]
fn ne(&self, other: &extern "C" fn($($p),*) -> _R) -> bool {
!self.eq(other)
}
}
}
)
fnptreq!(A)
fnptreq!(A,B)
fnptreq!(A,B,C)
fnptreq!(A,B,C,D)
fnptreq!(A,B,C,D,E)
}
// Comparison for pointers
#[cfg(not(test))]
impl<T> Ord for *const T {

View File

@ -445,8 +445,17 @@ impl Unwinder {
}
extern {
#[cfg(not(stage0))]
#[rust_stack]
fn rust_try(f: *u8, code: *c_void, data: *c_void) -> uintptr_t;
fn rust_try(f: extern "C" fn(*c_void, *c_void),
code: *c_void,
data: *c_void) -> uintptr_t;
#[cfg(stage0)]
#[rust_stack]
fn rust_try(f: *u8,
code: *c_void,
data: *c_void) -> uintptr_t;
}
}

View File

@ -31,6 +31,8 @@
use c_str::ToCStr;
use libc::{size_t, c_int, c_uint, c_void, c_char, uintptr_t};
#[cfg(not(stage0))]
use libc::ssize_t;
use libc::{malloc, free};
use libc;
use prelude::*;
@ -63,6 +65,7 @@ pub type uv_idle_t = c_void;
pub type uv_tcp_t = c_void;
pub type uv_udp_t = c_void;
pub type uv_connect_t = c_void;
pub type uv_connection_t = c_void;
pub type uv_write_t = c_void;
pub type uv_async_t = c_void;
pub type uv_timer_t = c_void;
@ -70,10 +73,70 @@ pub type uv_stream_t = c_void;
pub type uv_fs_t = c_void;
pub type uv_udp_send_t = c_void;
#[cfg(stage0)]
pub type uv_idle_cb = *u8;
#[cfg(stage0)]
pub type uv_alloc_cb = *u8;
#[cfg(stage0)]
pub type uv_read_cb = *u8;
#[cfg(stage0)]
pub type uv_udp_send_cb = *u8;
#[cfg(stage0)]
pub type uv_udp_recv_cb = *u8;
#[cfg(stage0)]
pub type uv_close_cb = *u8;
#[cfg(stage0)]
pub type uv_walk_cb = *u8;
#[cfg(stage0)]
pub type uv_async_cb = *u8;
#[cfg(stage0)]
pub type uv_connect_cb = *u8;
#[cfg(stage0)]
pub type uv_connection_cb = *u8;
#[cfg(stage0)]
pub type uv_timer_cb = *u8;
#[cfg(stage0)]
pub type uv_write_cb = *u8;
#[cfg(not(stage0))]
pub type uv_idle_cb = extern "C" fn(handle: *uv_idle_t,
status: c_int);
#[cfg(not(stage0))]
pub type uv_alloc_cb = extern "C" fn(stream: *uv_stream_t,
suggested_size: size_t) -> uv_buf_t;
#[cfg(not(stage0))]
pub type uv_read_cb = extern "C" fn(stream: *uv_stream_t,
nread: ssize_t,
buf: uv_buf_t);
#[cfg(not(stage0))]
pub type uv_udp_send_cb = extern "C" fn(req: *uv_udp_send_t,
status: c_int);
#[cfg(not(stage0))]
pub type uv_udp_recv_cb = extern "C" fn(handle: *uv_udp_t,
nread: ssize_t,
buf: uv_buf_t,
addr: *sockaddr,
flags: c_uint);
#[cfg(not(stage0))]
pub type uv_close_cb = extern "C" fn(handle: *uv_handle_t);
#[cfg(not(stage0))]
pub type uv_walk_cb = extern "C" fn(handle: *uv_handle_t,
arg: *c_void);
#[cfg(not(stage0))]
pub type uv_async_cb = extern "C" fn(handle: *uv_async_t,
status: c_int);
#[cfg(not(stage0))]
pub type uv_connect_cb = extern "C" fn(handle: *uv_connect_t,
status: c_int);
#[cfg(not(stage0))]
pub type uv_connection_cb = extern "C" fn(handle: *uv_connection_t,
status: c_int);
#[cfg(not(stage0))]
pub type uv_timer_cb = extern "C" fn(handle: *uv_timer_t,
status: c_int);
#[cfg(not(stage0))]
pub type uv_write_cb = extern "C" fn(handle: *uv_write_t,
status: c_int);
pub type sockaddr = c_void;
pub type sockaddr_in = c_void;
@ -191,13 +254,13 @@ pub unsafe fn run(loop_handle: *c_void) {
rust_uv_run(loop_handle);
}
pub unsafe fn close<T>(handle: *T, cb: *u8) {
pub unsafe fn close<T>(handle: *T, cb: uv_close_cb) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_close(handle as *c_void, cb);
}
pub unsafe fn walk(loop_handle: *c_void, cb: *u8, arg: *c_void) {
pub unsafe fn walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void) {
#[fixed_stack_segment]; #[inline(never)];
rust_uv_walk(loop_handle, cb, arg);
@ -332,14 +395,14 @@ pub unsafe fn tcp_init(loop_handle: *c_void, handle: *uv_tcp_t) -> c_int {
}
pub unsafe fn tcp_connect(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
addr_ptr: *sockaddr_in, after_connect_cb: *u8) -> c_int {
addr_ptr: *sockaddr_in, after_connect_cb: uv_connect_cb) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_connect(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
}
pub unsafe fn tcp_connect6(connect_ptr: *uv_connect_t, tcp_handle_ptr: *uv_tcp_t,
addr_ptr: *sockaddr_in6, after_connect_cb: *u8) -> c_int {
addr_ptr: *sockaddr_in6, after_connect_cb: uv_connect_cb) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_tcp_connect6(connect_ptr, tcp_handle_ptr, after_connect_cb, addr_ptr);
@ -387,7 +450,8 @@ pub unsafe fn tcp_simultaneous_accepts(handle: *uv_tcp_t, enable: c_int) -> c_in
return rust_uv_tcp_simultaneous_accepts(handle, enable);
}
pub unsafe fn listen<T>(stream: *T, backlog: c_int, cb: *u8) -> c_int {
pub unsafe fn listen<T>(stream: *T, backlog: c_int,
cb: uv_connection_cb) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_listen(stream as *c_void, backlog, cb);
@ -399,14 +463,19 @@ pub unsafe fn accept(server: *c_void, client: *c_void) -> c_int {
return rust_uv_accept(server as *c_void, client as *c_void);
}
pub unsafe fn write<T>(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int {
pub unsafe fn write<T>(req: *uv_write_t,
stream: *T,
buf_in: &[uv_buf_t],
cb: uv_write_cb) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
let buf_ptr = vec::raw::to_ptr(buf_in);
let buf_cnt = buf_in.len() as i32;
return rust_uv_write(req as *c_void, stream as *c_void, buf_ptr, buf_cnt, cb);
}
pub unsafe fn read_start(stream: *uv_stream_t, on_alloc: uv_alloc_cb, on_read: *u8) -> c_int {
pub unsafe fn read_start(stream: *uv_stream_t,
on_alloc: uv_alloc_cb,
on_read: uv_read_cb) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_read_start(stream as *c_void, on_alloc, on_read);
@ -435,7 +504,9 @@ pub unsafe fn err_name(err: *uv_err_t) -> *c_char {
return rust_uv_err_name(err);
}
pub unsafe fn async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> c_int {
pub unsafe fn async_init(loop_handle: *c_void,
async_handle: *uv_async_t,
cb: uv_async_cb) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
return rust_uv_async_init(loop_handle, async_handle, cb);
@ -460,7 +531,8 @@ pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int {
return rust_uv_timer_init(loop_ptr, timer_ptr);
}
pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: u64,
pub unsafe fn timer_start(timer_ptr: *uv_timer_t,
cb: uv_timer_cb, timeout: u64,
repeat: u64) -> c_int {
#[fixed_stack_segment]; #[inline(never)];
@ -634,8 +706,8 @@ extern {
fn rust_uv_loop_new() -> *c_void;
fn rust_uv_loop_delete(lp: *c_void);
fn rust_uv_run(loop_handle: *c_void);
fn rust_uv_close(handle: *c_void, cb: *u8);
fn rust_uv_walk(loop_handle: *c_void, cb: *u8, arg: *c_void);
fn rust_uv_close(handle: *c_void, cb: uv_close_cb);
fn rust_uv_walk(loop_handle: *c_void, cb: uv_walk_cb, arg: *c_void);
fn rust_uv_idle_new() -> *uv_idle_t;
fn rust_uv_idle_delete(handle: *uv_idle_t);
@ -644,7 +716,9 @@ extern {
fn rust_uv_idle_stop(handle: *uv_idle_t) -> c_int;
fn rust_uv_async_send(handle: *uv_async_t);
fn rust_uv_async_init(loop_handle: *c_void, async_handle: *uv_async_t, cb: *u8) -> c_int;
fn rust_uv_async_init(loop_handle: *c_void,
async_handle: *uv_async_t,
cb: uv_async_cb) -> c_int;
fn rust_uv_tcp_init(loop_handle: *c_void, handle_ptr: *uv_tcp_t) -> c_int;
fn rust_uv_buf_init(out_buf: *uv_buf_t, base: *u8, len: size_t);
fn rust_uv_last_error(loop_handle: *c_void) -> uv_err_t;
@ -658,10 +732,12 @@ extern {
fn rust_uv_ip6_name(src: *sockaddr_in6, dst: *u8, size: size_t) -> c_int;
fn rust_uv_ip4_port(src: *sockaddr_in) -> c_uint;
fn rust_uv_ip6_port(src: *sockaddr_in6) -> c_uint;
fn rust_uv_tcp_connect(req: *uv_connect_t, handle: *uv_tcp_t, cb: *u8,
fn rust_uv_tcp_connect(req: *uv_connect_t, handle: *uv_tcp_t,
cb: uv_connect_cb,
addr: *sockaddr_in) -> c_int;
fn rust_uv_tcp_bind(tcp_server: *uv_tcp_t, addr: *sockaddr_in) -> c_int;
fn rust_uv_tcp_connect6(req: *uv_connect_t, handle: *uv_tcp_t, cb: *u8,
fn rust_uv_tcp_connect6(req: *uv_connect_t, handle: *uv_tcp_t,
cb: uv_connect_cb,
addr: *sockaddr_in6) -> c_int;
fn rust_uv_tcp_bind6(tcp_server: *uv_tcp_t, addr: *sockaddr_in6) -> c_int;
fn rust_uv_tcp_getpeername(tcp_handle_ptr: *uv_tcp_t, name: *sockaddr_storage) -> c_int;
@ -674,10 +750,12 @@ extern {
fn rust_uv_udp_bind(server: *uv_udp_t, addr: *sockaddr_in, flags: c_uint) -> c_int;
fn rust_uv_udp_bind6(server: *uv_udp_t, addr: *sockaddr_in6, flags: c_uint) -> c_int;
fn rust_uv_udp_send(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t,
buf_cnt: c_int, addr: *sockaddr_in, cb: *u8) -> c_int;
buf_cnt: c_int, addr: *sockaddr_in, cb: uv_udp_send_cb) -> c_int;
fn rust_uv_udp_send6(req: *uv_udp_send_t, handle: *uv_udp_t, buf_in: *uv_buf_t,
buf_cnt: c_int, addr: *sockaddr_in6, cb: *u8) -> c_int;
fn rust_uv_udp_recv_start(server: *uv_udp_t, on_alloc: *u8, on_recv: *u8) -> c_int;
buf_cnt: c_int, addr: *sockaddr_in6, cb: uv_udp_send_cb) -> c_int;
fn rust_uv_udp_recv_start(server: *uv_udp_t,
on_alloc: uv_alloc_cb,
on_recv: uv_udp_recv_cb) -> c_int;
fn rust_uv_udp_recv_stop(server: *uv_udp_t) -> c_int;
fn rust_uv_get_udp_handle_from_send_req(req: *uv_udp_send_t) -> *uv_udp_t;
fn rust_uv_udp_getsockname(handle: *uv_udp_t, name: *sockaddr_storage) -> c_int;
@ -693,14 +771,17 @@ extern {
fn rust_uv_malloc_sockaddr_storage() -> *sockaddr_storage;
fn rust_uv_free_sockaddr_storage(ss: *sockaddr_storage);
fn rust_uv_listen(stream: *c_void, backlog: c_int, cb: *u8) -> c_int;
fn rust_uv_listen(stream: *c_void, backlog: c_int,
cb: uv_connection_cb) -> c_int;
fn rust_uv_accept(server: *c_void, client: *c_void) -> c_int;
fn rust_uv_write(req: *c_void, stream: *c_void, buf_in: *uv_buf_t, buf_cnt: c_int,
cb: *u8) -> c_int;
fn rust_uv_read_start(stream: *c_void, on_alloc: *u8, on_read: *u8) -> c_int;
cb: uv_write_cb) -> c_int;
fn rust_uv_read_start(stream: *c_void,
on_alloc: uv_alloc_cb,
on_read: uv_read_cb) -> c_int;
fn rust_uv_read_stop(stream: *c_void) -> c_int;
fn rust_uv_timer_init(loop_handle: *c_void, timer_handle: *uv_timer_t) -> c_int;
fn rust_uv_timer_start(timer_handle: *uv_timer_t, cb: *u8, timeout: libc::uint64_t,
fn rust_uv_timer_start(timer_handle: *uv_timer_t, cb: uv_timer_cb, timeout: libc::uint64_t,
repeat: libc::uint64_t) -> c_int;
fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int;

View File

@ -19,7 +19,8 @@ pub mod rustrt {
use std::libc;
extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
data: libc::uintptr_t)
-> libc::uintptr_t;
}
}

View File

@ -8,10 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// error-pattern:expected function but found `*u8`
extern fn f() {
}
fn main() {
f();
extern fn call1() {
f(); // OK from another extern fn!
}
fn call2() {
f(); //~ ERROR invoking non-Rust fn
}
fn main() {}

View File

@ -12,6 +12,7 @@ extern fn f() {
}
fn main() {
// extern functions are *u8 types
let _x: &fn() = f; //~ ERROR found `*u8`
// extern functions are extern "C" fn
let _x: extern "C" fn() = f; // OK
let _x: &fn() = f; //~ ERROR mismatched types
}

View File

@ -12,7 +12,7 @@ use std::libc;
extern fn foo() {}
static x: *u8 = foo;
static x: extern "C" fn() = foo;
static y: *libc::c_void = x as *libc::c_void;
static a: &'static int = &10;
static b: *int = a as *int;

View File

@ -13,8 +13,11 @@
extern mod cci_const;
use cci_const::bar;
static foo: *u8 = bar;
use std::cast::transmute;
static foo: extern "C" fn() = bar;
pub fn main() {
assert_eq!(foo, cci_const::bar);
unsafe {
assert_eq!(foo, bar);
}
}

View File

@ -10,14 +10,16 @@
extern fn foopy() {}
static f: *u8 = foopy;
static f: extern "C" fn() = foopy;
static s: S = S { f: foopy };
struct S {
f: *u8
f: extern "C" fn()
}
pub fn main() {
assert_eq!(foopy, f);
assert_eq!(f, s.f);
unsafe {
assert_eq!(foopy, f);
assert_eq!(f, s.f);
}
}

View File

@ -14,7 +14,8 @@ mod rustrt {
use std::libc;
extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
data: libc::uintptr_t)
-> libc::uintptr_t;
}
}

View File

@ -15,7 +15,8 @@ mod rustrt {
use std::libc;
extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
data: libc::uintptr_t)
-> libc::uintptr_t;
}
}

View File

@ -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 <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.
// Test direct calls to extern fns.
extern fn f(x: uint) -> uint { x * 2 }
fn main() {
#[fixed_stack_segment];
let x = f(22);
assert_eq!(x, 44);
}

View File

@ -14,7 +14,8 @@ mod rustrt {
use std::libc;
extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
data: libc::uintptr_t)
-> libc::uintptr_t;
}
}

View File

@ -19,7 +19,8 @@ mod rustrt {
use std::libc;
extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
data: libc::uintptr_t)
-> libc::uintptr_t;
}
}

View File

@ -0,0 +1,32 @@
// 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 <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.
// Tests that we can compare various kinds of extern fn signatures.
extern fn voidret1() {}
extern fn voidret2() {}
extern fn uintret() -> uint { 22 }
extern fn uintvoidret(x: uint) {}
extern fn uintuintuintuintret(x: uint, y: uint, z: uint) -> uint { x+y+z }
fn main() {
assert_eq!(voidret1, voidret1);
assert!(voidret1 != voidret2);
assert_eq!(uintret, uintret);
assert_eq!(uintvoidret, uintvoidret);
assert_eq!(uintuintuintuintret, uintuintuintuintret);
}

View File

@ -18,7 +18,8 @@ mod rustrt {
use std::libc;
extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
data: libc::uintptr_t)
-> libc::uintptr_t;
}
}

View File

@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use std::cast::transmute;
extern fn f() {
}
@ -15,11 +17,12 @@ extern fn g() {
}
pub fn main() {
// extern functions are *u8 types
let a: *u8 = f;
let b: *u8 = f;
let c: *u8 = g;
unsafe {
let a: extern "C" fn() = f;
let b: extern "C" fn() = f;
let c: extern "C" fn() = g;
assert_eq!(a, b);
assert!(a != c);
assert_eq!(a, b);
assert!(a != c);
}
}

View File

@ -15,7 +15,8 @@ mod rustrt {
use std::libc;
extern {
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
pub fn rust_dbg_call(cb: extern "C" fn (libc::uintptr_t) -> libc::uintptr_t,
data: libc::uintptr_t)
-> libc::uintptr_t;
}
}

View File

@ -2,7 +2,8 @@ use std::cast;
use std::libc;
use std::unstable::run_in_bare_thread;
externfn!(fn rust_dbg_call(cb: *u8, data: libc::uintptr_t) -> libc::uintptr_t)
externfn!(fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t),
data: libc::uintptr_t) -> libc::uintptr_t)
pub fn main() {
unsafe {