From 94a084a4b45afe0bb8c1b1206184d4d0db4f4ec0 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 19 Aug 2013 21:28:31 -0400 Subject: [PATCH 1/3] Fix crash(!) by using the *Rust fn type* not the extern fn type cc #3678 --- src/librustc/middle/trans/foreign.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 5586f1183ef87..bd4e50e01b5d0 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -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(), From 82a9abbf624daaaca0c9761ee1bea6097472975c Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Aug 2013 09:27:48 -0400 Subject: [PATCH 2/3] Change type of extern fns from `*u8` to `extern "ABI" fn` cc #3678 --- doc/rust.md | 32 +++++---- src/librustc/middle/trans/base.rs | 5 ++ src/librustc/middle/trans/builder.rs | 2 + src/librustc/middle/trans/expr.rs | 65 +++++++------------ src/librustc/middle/trans/llrepr.rs | 38 +++++++++++ src/librustc/middle/trans/mod.rs | 1 + src/librustc/middle/typeck/check/mod.rs | 16 ----- src/librustc/middle/typeck/collect.rs | 4 +- .../auxiliary/extern-crosscrate-source.rs | 3 +- ...xtern-no-call.rs => extern-cstack-lint.rs} | 12 +++- .../compile-fail/extern-wrong-value-type.rs | 5 +- src/test/run-pass/const-cast.rs | 2 +- src/test/run-pass/const-cross-crate-extern.rs | 7 +- src/test/run-pass/const-extern-function.rs | 10 +-- src/test/run-pass/extern-call-deep.rs | 3 +- src/test/run-pass/extern-call-deep2.rs | 3 +- src/test/run-pass/extern-call-direct.rs | 20 ++++++ ...extern-call.rs => extern-call-indirect.rs} | 3 +- src/test/run-pass/extern-call-scrub.rs | 3 +- .../extern-compare-with-return-type.rs | 32 +++++++++ src/test/run-pass/extern-stress.rs | 3 +- src/test/run-pass/extern-take-value.rs | 15 +++-- src/test/run-pass/extern-yield.rs | 3 +- src/test/run-pass/foreign-call-no-runtime.rs | 3 +- 24 files changed, 193 insertions(+), 97 deletions(-) create mode 100644 src/librustc/middle/trans/llrepr.rs rename src/test/compile-fail/{extern-no-call.rs => extern-cstack-lint.rs} (78%) create mode 100644 src/test/run-pass/extern-call-direct.rs rename src/test/run-pass/{extern-call.rs => extern-call-indirect.rs} (88%) create mode 100644 src/test/run-pass/extern-compare-with-return-type.rs diff --git a/doc/rust.md b/doc/rust.md index 16927d0de7a4a..b316f889ad1e4 100644 --- a/doc/rust.md +++ b/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} diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 50b5140505ef3..cbd1ee1d5da48 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -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; @@ -1740,6 +1741,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; diff --git a/src/librustc/middle/trans/builder.rs b/src/librustc/middle/trans/builder.rs index cba7a2253952f..9b910ab1ebc05 100644 --- a/src/librustc/middle/trans/builder.rs +++ b/src/librustc/middle/trans/builder.rs @@ -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); diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 725b525233e3d..0912e412fcf6e 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -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); } diff --git a/src/librustc/middle/trans/llrepr.rs b/src/librustc/middle/trans/llrepr.rs new file mode 100644 index 0000000000000..43fd6625766ef --- /dev/null +++ b/src/librustc/middle/trans/llrepr.rs @@ -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 or the MIT license +// , 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) + } +} + + diff --git a/src/librustc/middle/trans/mod.rs b/src/librustc/middle/trans/mod.rs index cf6d465cb820c..008da7f7ff8f2 100644 --- a/src/librustc/middle/trans/mod.rs +++ b/src/librustc/middle/trans/mod.rs @@ -45,3 +45,4 @@ pub mod asm; pub mod type_; pub mod value; pub mod basic_block; +pub mod llrepr; diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index ad6bf69d55ad6..7d1b5f7e93f14 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -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) => { diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 7678a12b78a5f..6d577d382322a 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -1067,13 +1067,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 { diff --git a/src/test/auxiliary/extern-crosscrate-source.rs b/src/test/auxiliary/extern-crosscrate-source.rs index 03cb96a3729af..e34fb610e0605 100644 --- a/src/test/auxiliary/extern-crosscrate-source.rs +++ b/src/test/auxiliary/extern-crosscrate-source.rs @@ -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; } } diff --git a/src/test/compile-fail/extern-no-call.rs b/src/test/compile-fail/extern-cstack-lint.rs similarity index 78% rename from src/test/compile-fail/extern-no-call.rs rename to src/test/compile-fail/extern-cstack-lint.rs index 58649f3209bb1..8ccd92316e922 100644 --- a/src/test/compile-fail/extern-no-call.rs +++ b/src/test/compile-fail/extern-cstack-lint.rs @@ -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() {} diff --git a/src/test/compile-fail/extern-wrong-value-type.rs b/src/test/compile-fail/extern-wrong-value-type.rs index fbb0f6e46a1c4..069c5a77c6c33 100644 --- a/src/test/compile-fail/extern-wrong-value-type.rs +++ b/src/test/compile-fail/extern-wrong-value-type.rs @@ -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 } diff --git a/src/test/run-pass/const-cast.rs b/src/test/run-pass/const-cast.rs index 280fe44c3da3e..d511930c70fa7 100644 --- a/src/test/run-pass/const-cast.rs +++ b/src/test/run-pass/const-cast.rs @@ -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; diff --git a/src/test/run-pass/const-cross-crate-extern.rs b/src/test/run-pass/const-cross-crate-extern.rs index 5281c21762689..eb7ae3d6fec99 100644 --- a/src/test/run-pass/const-cross-crate-extern.rs +++ b/src/test/run-pass/const-cross-crate-extern.rs @@ -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); + } } diff --git a/src/test/run-pass/const-extern-function.rs b/src/test/run-pass/const-extern-function.rs index 9a8104cb14f71..e07af4b0383fd 100644 --- a/src/test/run-pass/const-extern-function.rs +++ b/src/test/run-pass/const-extern-function.rs @@ -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); + } } diff --git a/src/test/run-pass/extern-call-deep.rs b/src/test/run-pass/extern-call-deep.rs index 27ad2fc46e07d..1153cb4177daa 100644 --- a/src/test/run-pass/extern-call-deep.rs +++ b/src/test/run-pass/extern-call-deep.rs @@ -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; } } diff --git a/src/test/run-pass/extern-call-deep2.rs b/src/test/run-pass/extern-call-deep2.rs index 6c90443636d39..a8fa9c2cef028 100644 --- a/src/test/run-pass/extern-call-deep2.rs +++ b/src/test/run-pass/extern-call-deep2.rs @@ -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; } } diff --git a/src/test/run-pass/extern-call-direct.rs b/src/test/run-pass/extern-call-direct.rs new file mode 100644 index 0000000000000..bc6ee63c0f457 --- /dev/null +++ b/src/test/run-pass/extern-call-direct.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. + +// 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); +} diff --git a/src/test/run-pass/extern-call.rs b/src/test/run-pass/extern-call-indirect.rs similarity index 88% rename from src/test/run-pass/extern-call.rs rename to src/test/run-pass/extern-call-indirect.rs index 939487df174db..9929cb447a6c7 100644 --- a/src/test/run-pass/extern-call.rs +++ b/src/test/run-pass/extern-call-indirect.rs @@ -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; } } diff --git a/src/test/run-pass/extern-call-scrub.rs b/src/test/run-pass/extern-call-scrub.rs index 5abd3c7b9d918..4388ef65e9865 100644 --- a/src/test/run-pass/extern-call-scrub.rs +++ b/src/test/run-pass/extern-call-scrub.rs @@ -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; } } diff --git a/src/test/run-pass/extern-compare-with-return-type.rs b/src/test/run-pass/extern-compare-with-return-type.rs new file mode 100644 index 0000000000000..41bf4a10b5d9e --- /dev/null +++ b/src/test/run-pass/extern-compare-with-return-type.rs @@ -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 or the MIT license +// , 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); +} + diff --git a/src/test/run-pass/extern-stress.rs b/src/test/run-pass/extern-stress.rs index 4eda3f34b6c15..2323567ccce43 100644 --- a/src/test/run-pass/extern-stress.rs +++ b/src/test/run-pass/extern-stress.rs @@ -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; } } diff --git a/src/test/run-pass/extern-take-value.rs b/src/test/run-pass/extern-take-value.rs index 542686c9099f1..e636f511da8d3 100644 --- a/src/test/run-pass/extern-take-value.rs +++ b/src/test/run-pass/extern-take-value.rs @@ -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); + } } diff --git a/src/test/run-pass/extern-yield.rs b/src/test/run-pass/extern-yield.rs index ce51aafa9d809..fd0807dffc84c 100644 --- a/src/test/run-pass/extern-yield.rs +++ b/src/test/run-pass/extern-yield.rs @@ -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; } } diff --git a/src/test/run-pass/foreign-call-no-runtime.rs b/src/test/run-pass/foreign-call-no-runtime.rs index c8acdbf44781c..2fa4f191ed14d 100644 --- a/src/test/run-pass/foreign-call-no-runtime.rs +++ b/src/test/run-pass/foreign-call-no-runtime.rs @@ -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 { From ffb6404c5ade3af113738c3cb72fd853e82a379e Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Aug 2013 09:31:02 -0400 Subject: [PATCH 3/3] Adjust callbacks in the libraries for the new type of extern fns cc #3678 --- src/libextra/rl.rs | 26 +++++---- src/libstd/ptr.rs | 41 +++++++++++++ src/libstd/rt/task.rs | 11 +++- src/libstd/rt/uv/uvll.rs | 123 ++++++++++++++++++++++++++++++++------- 4 files changed, 168 insertions(+), 33 deletions(-) diff --git a/src/libextra/rl.rs b/src/libextra/rl.rs index db87cf94641bb..09ef7f22be591 100644 --- a/src/libextra/rl.rs +++ b/src/libextra/rl.rs @@ -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)) } diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index c11634034230b..5f232c7881a62 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -369,6 +369,47 @@ impl 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 Ord for *const T { diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index 3b8eb87f8af29..12ba39a6dcd67 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -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; } } diff --git a/src/libstd/rt/uv/uvll.rs b/src/libstd/rt/uv/uvll.rs index 0ea2175336ab0..71387b09a8d0a 100644 --- a/src/libstd/rt/uv/uvll.rs +++ b/src/libstd/rt/uv/uvll.rs @@ -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(handle: *T, cb: *u8) { +pub unsafe fn close(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(stream: *T, backlog: c_int, cb: *u8) -> c_int { +pub unsafe fn listen(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(req: *uv_write_t, stream: *T, buf_in: &[uv_buf_t], cb: *u8) -> c_int { +pub unsafe fn write(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;