Skip to content

Commit 82a9abb

Browse files
committed
Change type of extern fns from *u8 to extern "ABI" fn
cc #3678
1 parent 94a084a commit 82a9abb

24 files changed

+193
-97
lines changed

doc/rust.md

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,20 +1006,25 @@ code_. They are defined in the same way as any other Rust function,
10061006
except that they have the `extern` modifier.
10071007

10081008
~~~
1009+
// Declares an extern fn, the ABI defaults to "C"
10091010
extern fn new_vec() -> ~[int] { ~[] }
1011+
1012+
// Declares an extern fn with "stdcall" ABI
1013+
extern "stdcall" fn new_vec_stdcall() -> ~[int] { ~[] }
10101014
~~~
10111015

1012-
Extern functions may not be called from Rust code,
1013-
but Rust code may take their value as a raw `u8` pointer.
1016+
Unlike normal functions, extern fns have an `extern "ABI" fn()`.
1017+
This is the same type as the functions declared in an extern
1018+
block.
10141019

10151020
~~~
10161021
# extern fn new_vec() -> ~[int] { ~[] }
1017-
let fptr: *u8 = new_vec;
1022+
let fptr: extern "C" fn() -> ~[int] = new_vec;
10181023
~~~
10191024

1020-
The primary motivation for extern functions is
1021-
to create callbacks for foreign functions that expect to receive function
1022-
pointers.
1025+
Extern functions may be called from Rust code, but
1026+
caution must be taken with respect to the size of the stack
1027+
segment, just as when calling an extern function normally.
10231028

10241029
### Type definitions
10251030

@@ -1384,14 +1389,13 @@ between the Rust ABI and the foreign ABI.
13841389
A number of [attributes](#attributes) control the behavior of external
13851390
blocks.
13861391

1387-
By default external blocks assume
1388-
that the library they are calling uses the standard C "cdecl" ABI.
1389-
Other ABIs may be specified using the `abi` attribute as in
1392+
By default external blocks assume that the library they are calling
1393+
uses the standard C "cdecl" ABI. Other ABIs may be specified using
1394+
an `abi` string, as shown here:
13901395

13911396
~~~{.xfail-test}
13921397
// Interface to the Windows API
1393-
#[abi = "stdcall"]
1394-
extern { }
1398+
extern "stdcall" { }
13951399
~~~
13961400

13971401
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,
14071411
which tends to not follow standard library naming conventions
14081412
and is linked to all Rust programs anyway.
14091413

1414+
The type of a function
1415+
declared in an extern block
1416+
is `extern "abi" fn(A1, ..., An) -> R`,
1417+
where `A1...An` are the declared types of its arguments
1418+
and `R` is the decalred return type.
1419+
14101420
## Attributes
14111421

14121422
~~~~~~~~{.ebnf .gram}

src/librustc/middle/trans/base.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ use middle::trans::expr;
5252
use middle::trans::foreign;
5353
use middle::trans::glue;
5454
use middle::trans::inline;
55+
use middle::trans::llrepr::LlvmRepr;
5556
use middle::trans::machine;
5657
use middle::trans::machine::{llalign_of_min, llsize_of};
5758
use middle::trans::meth;
@@ -1740,6 +1741,10 @@ pub fn copy_args_to_allocas(fcx: @mut FunctionContext,
17401741
args: &[ast::arg],
17411742
raw_llargs: &[ValueRef],
17421743
arg_tys: &[ty::t]) -> @mut Block {
1744+
debug!("copy_args_to_allocas: raw_llargs=%s arg_tys=%s",
1745+
raw_llargs.llrepr(fcx.ccx),
1746+
arg_tys.repr(fcx.ccx.tcx));
1747+
17431748
let _icx = push_ctxt("copy_args_to_allocas");
17441749
let mut bcx = bcx;
17451750

src/librustc/middle/trans/builder.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use std::hashmap::HashMap;
2222
use std::libc::{c_uint, c_ulonglong, c_char};
2323
use std::vec;
2424
use syntax::codemap::span;
25+
use std::ptr::is_not_null;
2526

2627
pub struct Builder {
2728
llbuilder: BuilderRef,
@@ -483,6 +484,7 @@ impl Builder {
483484
debug!("Store %s -> %s",
484485
self.ccx.tn.val_to_str(val),
485486
self.ccx.tn.val_to_str(ptr));
487+
assert!(is_not_null(self.llbuilder));
486488
self.count_insn("store");
487489
unsafe {
488490
llvm::LLVMBuildStore(self.llbuilder, val, ptr);

src/librustc/middle/trans/expr.rs

Lines changed: 23 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -824,56 +824,30 @@ fn trans_def_datum_unadjusted(bcx: @mut Block,
824824
{
825825
let _icx = push_ctxt("trans_def_datum_unadjusted");
826826

827-
match def {
827+
let fn_data = match def {
828828
ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
829-
let fn_data = callee::trans_fn_ref(bcx, did, ref_expr.id);
830-
return fn_data_to_datum(bcx, ref_expr, did, fn_data);
829+
callee::trans_fn_ref(bcx, did, ref_expr.id)
831830
}
832831
ast::def_static_method(impl_did, Some(trait_did), _) => {
833-
let fn_data = meth::trans_static_method_callee(bcx, impl_did,
834-
trait_did,
835-
ref_expr.id);
836-
return fn_data_to_datum(bcx, ref_expr, impl_did, fn_data);
832+
meth::trans_static_method_callee(bcx, impl_did,
833+
trait_did,
834+
ref_expr.id)
837835
}
838836
_ => {
839837
bcx.tcx().sess.span_bug(ref_expr.span, fmt!(
840838
"Non-DPS def %? referened by %s",
841839
def, bcx.node_id_to_str(ref_expr.id)));
842840
}
843-
}
841+
};
844842

845-
fn fn_data_to_datum(bcx: @mut Block,
846-
ref_expr: &ast::expr,
847-
def_id: ast::def_id,
848-
fn_data: callee::FnData) -> DatumBlock {
849-
/*!
850-
*
851-
* Translates a reference to a top-level fn item into a rust
852-
* value. This is just a fn pointer.
853-
*/
854-
855-
let is_extern = {
856-
let fn_tpt = ty::lookup_item_type(bcx.tcx(), def_id);
857-
ty::ty_fn_purity(fn_tpt.ty) == ast::extern_fn
858-
};
859-
let (rust_ty, llval) = if is_extern {
860-
let rust_ty = ty::mk_ptr(
861-
bcx.tcx(),
862-
ty::mt {
863-
ty: ty::mk_mach_uint(ast::ty_u8),
864-
mutbl: ast::m_imm
865-
}); // *u8
866-
(rust_ty, PointerCast(bcx, fn_data.llfn, Type::i8p()))
867-
} else {
868-
let fn_ty = expr_ty(bcx, ref_expr);
869-
(fn_ty, fn_data.llfn)
870-
};
871-
return DatumBlock {
872-
bcx: bcx,
873-
datum: Datum {val: llval,
874-
ty: rust_ty,
875-
mode: ByValue}
876-
};
843+
let fn_ty = expr_ty(bcx, ref_expr);
844+
DatumBlock {
845+
bcx: bcx,
846+
datum: Datum {
847+
val: fn_data.llfn,
848+
ty: fn_ty,
849+
mode: ByValue
850+
}
877851
}
878852
}
879853

@@ -1657,6 +1631,7 @@ pub fn cast_type_kind(t: ty::t) -> cast_kind {
16571631
ty::ty_float(*) => cast_float,
16581632
ty::ty_ptr(*) => cast_pointer,
16591633
ty::ty_rptr(*) => cast_pointer,
1634+
ty::ty_bare_fn(*) => cast_pointer,
16601635
ty::ty_int(*) => cast_integral,
16611636
ty::ty_uint(*) => cast_integral,
16621637
ty::ty_bool => cast_integral,
@@ -1719,10 +1694,16 @@ fn trans_imm_cast(bcx: @mut Block, expr: @ast::expr,
17191694
val_ty(lldiscrim_a),
17201695
lldiscrim_a, true),
17211696
cast_float => SIToFP(bcx, lldiscrim_a, ll_t_out),
1722-
_ => ccx.sess.bug("translating unsupported cast.")
1697+
_ => ccx.sess.bug(fmt!("translating unsupported cast: \
1698+
%s (%?) -> %s (%?)",
1699+
t_in.repr(ccx.tcx), k_in,
1700+
t_out.repr(ccx.tcx), k_out))
17231701
}
17241702
}
1725-
_ => ccx.sess.bug("translating unsupported cast.")
1703+
_ => ccx.sess.bug(fmt!("translating unsupported cast: \
1704+
%s (%?) -> %s (%?)",
1705+
t_in.repr(ccx.tcx), k_in,
1706+
t_out.repr(ccx.tcx), k_out))
17261707
};
17271708
return immediate_rvalue_bcx(bcx, newval, t_out);
17281709
}

src/librustc/middle/trans/llrepr.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use middle::trans::context::CrateContext;
12+
use middle::trans::type_::Type;
13+
use lib::llvm::ValueRef;
14+
15+
pub trait LlvmRepr {
16+
fn llrepr(&self, ccx: &CrateContext) -> ~str;
17+
}
18+
19+
impl<'self, T:LlvmRepr> LlvmRepr for &'self [T] {
20+
fn llrepr(&self, ccx: &CrateContext) -> ~str {
21+
let reprs = self.map(|t| t.llrepr(ccx));
22+
fmt!("[%s]", reprs.connect(","))
23+
}
24+
}
25+
26+
impl LlvmRepr for Type {
27+
fn llrepr(&self, ccx: &CrateContext) -> ~str {
28+
ccx.tn.type_to_str(*self)
29+
}
30+
}
31+
32+
impl LlvmRepr for ValueRef {
33+
fn llrepr(&self, ccx: &CrateContext) -> ~str {
34+
ccx.tn.val_to_str(*self)
35+
}
36+
}
37+
38+

src/librustc/middle/trans/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,4 @@ pub mod asm;
4545
pub mod type_;
4646
pub mod value;
4747
pub mod basic_block;
48+
pub mod llrepr;

src/librustc/middle/typeck/check/mod.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3099,22 +3099,6 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
30993099
let typ = fcx.local_ty(sp, nid);
31003100
return no_params(typ);
31013101
}
3102-
ast::def_fn(_, ast::extern_fn) => {
3103-
// extern functions are just u8 pointers
3104-
return ty_param_bounds_and_ty {
3105-
generics: ty::Generics {
3106-
type_param_defs: @~[],
3107-
region_param: None
3108-
},
3109-
ty: ty::mk_ptr(
3110-
fcx.ccx.tcx,
3111-
ty::mt {
3112-
ty: ty::mk_mach_uint(ast::ty_u8),
3113-
mutbl: ast::m_imm
3114-
})
3115-
};
3116-
}
3117-
31183102
ast::def_fn(id, _) | ast::def_static_method(id, _, _) |
31193103
ast::def_static(id, _) | ast::def_variant(_, id) |
31203104
ast::def_struct(id) => {

src/librustc/middle/typeck/collect.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,13 +1067,13 @@ pub fn ty_of_item(ccx: &CrateCtxt, it: &ast::item)
10671067
tcx.tcache.insert(local_def(it.id), tpt);
10681068
return tpt;
10691069
}
1070-
ast::item_fn(ref decl, purity, _, ref generics, _) => {
1070+
ast::item_fn(ref decl, purity, abi, ref generics, _) => {
10711071
assert!(rp.is_none());
10721072
let ty_generics = ty_generics(ccx, None, generics, 0);
10731073
let tofd = astconv::ty_of_bare_fn(ccx,
10741074
&empty_rscope,
10751075
purity,
1076-
AbiSet::Rust(),
1076+
abi,
10771077
&generics.lifetimes,
10781078
decl);
10791079
let tpt = ty_param_bounds_and_ty {

src/test/auxiliary/extern-crosscrate-source.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ pub mod rustrt {
1919
use std::libc;
2020

2121
extern {
22-
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
22+
pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
23+
data: libc::uintptr_t)
2324
-> libc::uintptr_t;
2425
}
2526
}

src/test/compile-fail/extern-no-call.rs renamed to src/test/compile-fail/extern-cstack-lint.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// error-pattern:expected function but found `*u8`
1211
extern fn f() {
1312
}
1413

15-
fn main() {
16-
f();
14+
extern fn call1() {
15+
f(); // OK from another extern fn!
1716
}
17+
18+
fn call2() {
19+
f(); //~ ERROR invoking non-Rust fn
20+
}
21+
22+
23+
fn main() {}

src/test/compile-fail/extern-wrong-value-type.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ extern fn f() {
1212
}
1313

1414
fn main() {
15-
// extern functions are *u8 types
16-
let _x: &fn() = f; //~ ERROR found `*u8`
15+
// extern functions are extern "C" fn
16+
let _x: extern "C" fn() = f; // OK
17+
let _x: &fn() = f; //~ ERROR mismatched types
1718
}

src/test/run-pass/const-cast.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use std::libc;
1212

1313
extern fn foo() {}
1414

15-
static x: *u8 = foo;
15+
static x: extern "C" fn() = foo;
1616
static y: *libc::c_void = x as *libc::c_void;
1717
static a: &'static int = &10;
1818
static b: *int = a as *int;

src/test/run-pass/const-cross-crate-extern.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313

1414
extern mod cci_const;
1515
use cci_const::bar;
16-
static foo: *u8 = bar;
16+
use std::cast::transmute;
17+
static foo: extern "C" fn() = bar;
1718

1819
pub fn main() {
19-
assert_eq!(foo, cci_const::bar);
20+
unsafe {
21+
assert_eq!(foo, bar);
22+
}
2023
}

src/test/run-pass/const-extern-function.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@
1010

1111
extern fn foopy() {}
1212

13-
static f: *u8 = foopy;
13+
static f: extern "C" fn() = foopy;
1414
static s: S = S { f: foopy };
1515

1616
struct S {
17-
f: *u8
17+
f: extern "C" fn()
1818
}
1919

2020
pub fn main() {
21-
assert_eq!(foopy, f);
22-
assert_eq!(f, s.f);
21+
unsafe {
22+
assert_eq!(foopy, f);
23+
assert_eq!(f, s.f);
24+
}
2325
}

src/test/run-pass/extern-call-deep.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ mod rustrt {
1414
use std::libc;
1515

1616
extern {
17-
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
17+
pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
18+
data: libc::uintptr_t)
1819
-> libc::uintptr_t;
1920
}
2021
}

src/test/run-pass/extern-call-deep2.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ mod rustrt {
1515
use std::libc;
1616

1717
extern {
18-
pub fn rust_dbg_call(cb: *u8, data: libc::uintptr_t)
18+
pub fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
19+
data: libc::uintptr_t)
1920
-> libc::uintptr_t;
2021
}
2122
}

0 commit comments

Comments
 (0)