Skip to content

Use attributes for native module and functions #1178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 20 additions & 11 deletions doc/tutorial/ffi.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ OpenSSL libraries installed, it should 'just work'.
use std;
import std::{vec, str};

native "cdecl" mod crypto {
#[abi = "cdecl"]
native mod crypto {
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
}

Expand All @@ -41,7 +42,8 @@ OpenSSL libraries installed, it should 'just work'.
Before we can call `SHA1`, we have to declare it. That is what this
part of the program is responsible for:

native "cdecl" mod crypto {
#[abi = "cdecl"]
native mod crypto {
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
}

Expand All @@ -52,12 +54,17 @@ of functions are available in that library.
In this case, it'll change the name `crypto` to a shared library name
in a platform-specific way (`libcrypto.so` on Linux, for example), and
link that in. If you want the module to have a different name from the
actual library, you can say `native "cdecl" mod something = "crypto" {
... }`.
actual library, you can use the `"link_name"` attribute, like:

The `"cdecl"` word indicates the calling convention to use for
functions in this module. Most C libraries use cdecl as their calling
convention. You can also specify `"x86stdcall"` to use stdcall
#[abi = "cdecl"]
#[link_name = "crypto"]
native mod something {
fn SHA1(src: *u8, sz: uint, out: *u8) -> *u8;
}

The `#[abi = "cdecl"]` attribute indicates the calling convention to
use for functions in this module. Most C libraries use cdecl as their
calling convention. You can also specify `"x86stdcall"` to use stdcall
instead.

FIXME: Mention c-stack variants? Are they going to change?
Expand Down Expand Up @@ -164,7 +171,9 @@ microsecond-resolution timer.
use std;
type timeval = {mutable tv_sec: u32,
mutable tv_usec: u32};
native "cdecl" mod libc = "" {
#[abi = "cdecl"]
#[link_name = ""]
native mod libc {
fn gettimeofday(tv: *timeval, tz: *()) -> i32;
}
fn unix_time_in_microseconds() -> u64 unsafe {
Expand All @@ -173,9 +182,9 @@ microsecond-resolution timer.
ret (x.tv_sec as u64) * 1000_000_u64 + (x.tv_usec as u64);
}

The `libc = ""` sets the name of the native module to the empty string
to prevent the rust compiler from trying to link it. The standard C
library is already linked with Rust programs.
The `#[link_name = ""]` sets the name of the native module to the
empty string to prevent the rust compiler from trying to link it.
The standard C library is already linked with Rust programs.

A `timeval`, in C, is a struct with two 32-bit integers. Thus, we
define a record type with the same contents, and declare
Expand Down
10 changes: 10 additions & 0 deletions src/comp/front/attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export require_unique_names;
export get_attr_name;
export get_meta_item_name;
export get_meta_item_value_str;
export get_meta_item_value_str_by_name;
export get_meta_item_list;
export mk_name_value_item_str;
export mk_name_value_item;
Expand Down Expand Up @@ -85,6 +86,15 @@ fn get_meta_item_value_str(meta: @ast::meta_item) -> option::t<str> {
}
}

fn get_meta_item_value_str_by_name(attrs: [ast::attribute], name: ast::ident)
-> option::t<str> {
let mattrs = find_attrs_by_name(attrs, name);
if vec::len(mattrs) > 0u {
ret get_meta_item_value_str(attr_meta(mattrs[0]));
}
ret option::none;
}

fn get_meta_item_list(meta: @ast::meta_item) -> option::t<[@ast::meta_item]> {
alt meta.node {
ast::meta_list(_, l) { option::some(l) }
Expand Down
3 changes: 1 addition & 2 deletions src/comp/front/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ fn fold_native_mod(cfg: ast::crate_cfg, nm: ast::native_mod,
fld: fold::ast_fold) -> ast::native_mod {
let filter = bind filter_native_item(cfg, _);
let filtered_items = vec::filter_map(filter, nm.items);
ret {native_name: nm.native_name,
abi: nm.abi,
ret {abi: nm.abi,
view_items: vec::map(fld.fold_view_item, nm.view_items),
items: filtered_items};
}
Expand Down
4 changes: 3 additions & 1 deletion src/comp/lib/llvm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ const LLVMRealULE: uint = 13u;
const LLVMRealUNE: uint = 14u;

#[link_args = "-Lrustllvm"]
native "cdecl" mod llvm = "rustllvm" {
#[link_name = "rustllvm"]
#[abi = "cdecl"]
native mod llvm {

type ModuleRef;
type ContextRef;
Expand Down
7 changes: 6 additions & 1 deletion src/comp/metadata/creader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ fn visit_item(e: env, i: @ast::item) {
ret;
}
let cstore = e.sess.get_cstore();
if !cstore::add_used_library(cstore, m.native_name) { ret; }
let native_name = i.ident;
alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") {
some(nn) { native_name = nn; }
none. { }
}
if !cstore::add_used_library(cstore, native_name) { ret; }
for a: ast::attribute in
attr::find_attrs_by_name(i.attrs, "link_args") {

Expand Down
2 changes: 1 addition & 1 deletion src/comp/metadata/encoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ fn encode_info_for_native_item(ecx: @encode_ctxt, ebml_w: ebml::writer,
encode_type(ecx, ebml_w,
ty::mk_native(ecx.ccx.tcx, local_def(nitem.id)));
}
native_item_fn(_, fn_decl, tps) {
native_item_fn(fn_decl, tps) {
let letter =
alt fn_decl.purity {
unsafe_fn. { 'U' }
Expand Down
4 changes: 2 additions & 2 deletions src/comp/middle/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,7 @@ fn lookup_in_scope(e: env, sc: scopes, sp: span, name: ident, ns: namespace)
}
scope_native_item(it) {
alt it.node {
ast::native_item_fn(_, decl, ty_params) {
ast::native_item_fn(decl, ty_params) {
ret lookup_in_fn(name, decl, ty_params, ns);
}
}
Expand Down Expand Up @@ -1077,7 +1077,7 @@ fn lookup_in_mie(e: env, mie: mod_index_entry, ns: namespace) ->
ret some(ast::def_native_ty(local_def(native_item.id)));
}
}
ast::native_item_fn(_, decl, _) {
ast::native_item_fn(decl, _) {
if ns == ns_value {
ret some(ast::def_native_fn(
local_def(native_item.id),
Expand Down
16 changes: 8 additions & 8 deletions src/comp/middle/trans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import std::map::hashmap;
import std::map::{new_int_hash, new_str_hash};
import std::option::{some, none};
import driver::session;
import front::attr;
import middle::{ty, gc};
import middle::freevars::*;
import back::{link, abi, upcall};
Expand Down Expand Up @@ -5585,7 +5586,7 @@ fn native_fn_ty_param_count(cx: @crate_ctxt, id: ast::node_id) -> uint {
cx.sess.bug("register_native_fn(): native fn isn't \
actually a fn");
}
ast::native_item_fn(_, _, tps) {
ast::native_item_fn(_, tps) {
count = std::vec::len::<ast::ty_param>(tps);
}
}
Expand Down Expand Up @@ -5805,14 +5806,13 @@ fn item_path(item: @ast::item) -> [str] { ret [item.ident]; }
fn collect_native_item(ccx: @crate_ctxt, i: @ast::native_item, &&pt: [str],
_v: vt<[str]>) {
alt i.node {
ast::native_item_fn(link_name, _, _) {
ast::native_item_fn(_, _) {
if !ccx.obj_methods.contains_key(i.id) {
let name =
if option::is_some(link_name) {
option::get(link_name)
} else {
i.ident
};
let name = i.ident;
alt attr::get_meta_item_value_str_by_name(i.attrs, "link_name") {
none. { }
option::some(ln) { name = ln; }
}
register_native_fn(ccx, i.span, pt, name, i.id);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/comp/middle/typeck.rs
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,7 @@ mod collect {
abi: ast::native_abi) -> ty::ty_param_kinds_and_ty {
let no_kinds: [ast::kind] = [];
alt it.node {
ast::native_item_fn(_, fn_decl, params) {
ast::native_item_fn(fn_decl, params) {
let get = bind getter(cx, _);
let convert = bind ast_ty_to_ty(cx.tcx, get, _);
let f = bind ty_of_arg(cx, _);
Expand Down Expand Up @@ -819,7 +819,7 @@ mod collect {
ast::native_item_ty. {
// FIXME: Native types have no annotation. Should they? --pcw
}
ast::native_item_fn(_, _, _) {
ast::native_item_fn(_, _) {
write::ty_only(cx.tcx, i.id, tpt.ty);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/comp/syntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ tag native_abi {
}

type native_mod =
{native_name: str,
{// FIXME: Removing abi from AST. Depends on Issue #1179.
abi: native_abi,
view_items: [@view_item],
items: [@native_item]};
Expand Down Expand Up @@ -501,7 +501,7 @@ type native_item =

tag native_item_ {
native_item_ty;
native_item_fn(option::t<str>, fn_decl, [ty_param]);
native_item_fn(fn_decl, [ty_param]);
}

//
Expand Down
8 changes: 3 additions & 5 deletions src/comp/syntax/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,8 @@ fn noop_fold_native_item(&&ni: @native_item, fld: ast_fold) -> @native_item {
node:
alt ni.node {
native_item_ty. { native_item_ty }
native_item_fn(st, fdec, typms) {
native_item_fn(st,
{inputs: vec::map(fold_arg, fdec.inputs),
native_item_fn(fdec, typms) {
native_item_fn({inputs: vec::map(fold_arg, fdec.inputs),
output: fld.fold_ty(fdec.output),
purity: fdec.purity,
il: fdec.il,
Expand Down Expand Up @@ -453,8 +452,7 @@ fn noop_fold_mod(m: _mod, fld: ast_fold) -> _mod {
}

fn noop_fold_native_mod(nm: native_mod, fld: ast_fold) -> native_mod {
ret {native_name: nm.native_name,
abi: nm.abi,
ret {abi: nm.abi,
view_items: vec::map(fld.fold_view_item, nm.view_items),
items: vec::map(fld.fold_native_item, nm.items)}
}
Expand Down
48 changes: 22 additions & 26 deletions src/comp/syntax/parse/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import token::can_begin_expr;
import codemap::span;
import util::interner;
import ast::{node_id, spanned};
import front::attr;

tag restriction { UNRESTRICTED; RESTRICT_NO_CALL_EXPRS; }

Expand Down Expand Up @@ -1956,13 +1957,11 @@ fn parse_item_native_fn(p: parser, attrs: [ast::attribute],
let lo = p.get_last_lo_pos();
let t = parse_fn_header(p);
let decl = parse_fn_decl(p, purity, ast::il_normal);
let link_name = none;
if p.peek() == token::EQ { p.bump(); link_name = some(parse_str(p)); }
let hi = p.get_hi_pos();
expect(p, token::SEMI);
ret @{ident: t.ident,
attrs: attrs,
node: ast::native_item_fn(link_name, decl, t.tps),
node: ast::native_item_fn(decl, t.tps),
id: p.get_id(),
span: ast_util::mk_sp(lo, hi)};
}
Expand All @@ -1979,7 +1978,7 @@ fn parse_native_item(p: parser, attrs: [ast::attribute]) ->
} else { unexpected(p, p.peek()); }
}

fn parse_native_mod_items(p: parser, native_name: str, abi: ast::native_abi,
fn parse_native_mod_items(p: parser, abi: ast::native_abi,
first_item_attrs: [ast::attribute]) ->
ast::native_mod {
// Shouldn't be any view items since we've already parsed an item attr
Expand All @@ -1994,40 +1993,37 @@ fn parse_native_mod_items(p: parser, native_name: str, abi: ast::native_abi,
initial_attrs = [];
items += [parse_native_item(p, attrs)];
}
ret {native_name: native_name,
abi: abi,
ret {abi: abi,
view_items: view_items,
items: items};
}

fn parse_item_native_mod(p: parser, attrs: [ast::attribute]) -> @ast::item {
let lo = p.get_last_lo_pos();
let abi = ast::native_abi_cdecl;
if !is_word(p, "mod") {
let t = parse_str(p);
if str::eq(t, "rust-intrinsic") {
abi = ast::native_abi_rust_intrinsic;
} else if str::eq(t, "cdecl") {
abi = ast::native_abi_cdecl;
} else if str::eq(t, "stdcall") {
abi = ast::native_abi_stdcall;
} else {
p.fatal("unsupported abi: " + t);
}
}
expect_word(p, "mod");
let id = parse_ident(p);
let native_name;
if p.peek() == token::EQ {
expect(p, token::EQ);
native_name = parse_str(p);
} else { native_name = id; }
expect(p, token::LBRACE);
let more_attrs = parse_inner_attrs_and_next(p);
let inner_attrs = more_attrs.inner;
let first_item_outer_attrs = more_attrs.next;
let m =
parse_native_mod_items(p, native_name, abi, first_item_outer_attrs);
let abi =
alt attr::get_meta_item_value_str_by_name(
attrs + inner_attrs, "abi") {
none. { ast::native_abi_cdecl }
some("rust-intrinsic") {
ast::native_abi_rust_intrinsic
}
some("cdecl") {
ast::native_abi_cdecl
}
some("stdcall") {
ast::native_abi_stdcall
}
some(t) {
p.fatal("unsupported abi: " + t);
}
};
let m = parse_native_mod_items(p, abi, first_item_outer_attrs);
let hi = p.get_hi_pos();
expect(p, token::RBRACE);
ret mk_item(p, lo, hi, id, ast::item_native_mod(m), attrs + inner_attrs);
Expand Down
22 changes: 1 addition & 21 deletions src/comp/syntax/print/pprust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -350,13 +350,9 @@ fn print_native_item(s: ps, item: @ast::native_item) {



ast::native_item_fn(lname, decl, typarams) {
ast::native_item_fn(decl, typarams) {
print_fn(s, decl, ast::proto_bare, item.ident, typarams,
decl.constraints);
alt lname {
none. { }
some(ss) { space(s.s); word_space(s, "="); print_string(s, ss); }
}
end(s); // end head-ibox
word(s.s, ";");
end(s); // end the outer fn box
Expand Down Expand Up @@ -399,24 +395,8 @@ fn print_item(s: ps, &&item: @ast::item) {
}
ast::item_native_mod(nmod) {
head(s, "native");
alt nmod.abi {
ast::native_abi_rust_intrinsic. {
word_nbsp(s, "\"rust-intrinsic\"");
}
ast::native_abi_cdecl. {
word_nbsp(s, "\"cdecl\"");
}
ast::native_abi_stdcall. {
word_nbsp(s, "\"stdcall\"");
}
}
word_nbsp(s, "mod");
word_nbsp(s, item.ident);
if !str::eq(nmod.native_name, item.ident) {
word_space(s, "=");
print_string(s, nmod.native_name);
nbsp(s);
}
bopen(s);
print_native_mod(s, nmod, item.attrs);
bclose(s, item.span);
Expand Down
2 changes: 1 addition & 1 deletion src/comp/syntax/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ fn visit_pat<E>(p: @pat, e: E, v: vt<E>) {

fn visit_native_item<E>(ni: @native_item, e: E, v: vt<E>) {
alt ni.node {
native_item_fn(_, fd, _) { visit_fn_decl(fd, e, v); }
native_item_fn(fd, _) { visit_fn_decl(fd, e, v); }
native_item_ty. { }
}
}
Expand Down
Loading