mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-07 05:15:02 +00:00
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:
commit
4e3dbf959a
32
doc/rust.md
32
doc/rust.md
@ -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}
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(),
|
||||
|
38
src/librustc/middle/trans/llrepr.rs
Normal file
38
src/librustc/middle/trans/llrepr.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -45,3 +45,4 @@ pub mod asm;
|
||||
pub mod type_;
|
||||
pub mod value;
|
||||
pub mod basic_block;
|
||||
pub mod llrepr;
|
||||
|
@ -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) => {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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() {}
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
20
src/test/run-pass/extern-call-direct.rs
Normal file
20
src/test/run-pass/extern-call-direct.rs
Normal 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);
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
32
src/test/run-pass/extern-compare-with-return-type.rs
Normal file
32
src/test/run-pass/extern-compare-with-return-type.rs
Normal 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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user