auto merge of #5307 : nikomatsakis/rust/remove-by-val, r=nikomatsakis
This is done in two steps: First, we make foreign functions not consider modes at all. This is because previously ++ mode was the only way to pass structs to foreign functions and so forth. We also add a lint mode warning if you use `&&` mode in a foreign function, since the semantics of that change (it used to pass a pointer to the C function, now it doesn't). Then, we remove by value and make it equivalent to `+` mode. At the same time, we stop parsing `-` mode and convert all uses of it to `+` mode (it was already being parsed to `+` mode anyhow). This obsoletes pull request #5298. r? @brson
This commit is contained in:
commit
ab5472a724
@ -12,7 +12,7 @@ pub mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
#[link_name = "rusti"]
|
||||
pub extern {
|
||||
fn forget<T>(-x: T);
|
||||
fn forget<T>(+x: T);
|
||||
fn reinterpret_cast<T, U>(&&e: T) -> U;
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ struct Thread {
|
||||
impl Thread {
|
||||
static fn start(main: ~fn()) -> Thread {
|
||||
fn substart(main: &fn()) -> *raw_thread {
|
||||
unsafe { rust_raw_thread_start(main) }
|
||||
unsafe { rust_raw_thread_start(&main) }
|
||||
}
|
||||
let raw = substart(main);
|
||||
Thread {
|
||||
@ -39,6 +39,6 @@ impl Drop for Thread {
|
||||
}
|
||||
|
||||
extern {
|
||||
pub unsafe fn rust_raw_thread_start(f: &fn()) -> *raw_thread;
|
||||
pub unsafe fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread;
|
||||
pub unsafe fn rust_raw_thread_join_delete(thread: *raw_thread);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ mod rustrt {
|
||||
pub unsafe fn rust_lock_little_lock(lock: rust_little_lock);
|
||||
pub unsafe fn rust_unlock_little_lock(lock: rust_little_lock);
|
||||
|
||||
pub unsafe fn rust_raw_thread_start(f: &fn()) -> *raw_thread;
|
||||
pub unsafe fn rust_raw_thread_start(f: &(&fn())) -> *raw_thread;
|
||||
pub unsafe fn rust_raw_thread_join_delete(thread: *raw_thread);
|
||||
}
|
||||
}
|
||||
@ -72,7 +72,7 @@ pub fn run_in_bare_thread(f: ~fn()) {
|
||||
let closure: &fn() = || {
|
||||
f()
|
||||
};
|
||||
let thread = rustrt::rust_raw_thread_start(closure);
|
||||
let thread = rustrt::rust_raw_thread_start(&closure);
|
||||
rustrt::rust_raw_thread_join_delete(thread);
|
||||
chan.send(());
|
||||
}
|
||||
|
@ -34,8 +34,8 @@ pub extern {
|
||||
|
||||
pub fn size_of<T>() -> uint;
|
||||
|
||||
pub fn move_val<T>(dst: &mut T, -src: T);
|
||||
pub fn move_val_init<T>(dst: &mut T, -src: T);
|
||||
pub fn move_val<T>(dst: &mut T, +src: T);
|
||||
pub fn move_val_init<T>(dst: &mut T, +src: T);
|
||||
|
||||
pub fn min_align_of<T>() -> uint;
|
||||
pub fn pref_align_of<T>() -> uint;
|
||||
|
@ -486,7 +486,7 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
|
||||
|
||||
// This calculates CMH as defined above
|
||||
fn crate_meta_extras_hash(symbol_hasher: &hash::State,
|
||||
-cmh_items: ~[@ast::meta_item],
|
||||
+cmh_items: ~[@ast::meta_item],
|
||||
dep_hashes: ~[~str]) -> @str {
|
||||
fn len_and_str(s: &str) -> ~str {
|
||||
fmt!("%u_%s", s.len(), s)
|
||||
@ -535,7 +535,7 @@ pub fn build_link_meta(sess: Session, c: &ast::crate, output: &Path,
|
||||
name, default));
|
||||
}
|
||||
|
||||
fn crate_meta_name(sess: Session, output: &Path, -opt_name: Option<@str>)
|
||||
fn crate_meta_name(sess: Session, output: &Path, +opt_name: Option<@str>)
|
||||
-> @str {
|
||||
return match opt_name {
|
||||
Some(v) => v,
|
||||
|
@ -440,7 +440,7 @@ pub fn pretty_print_input(sess: Session, +cfg: ast::crate_cfg, input: input,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_os(triple: ~str) -> Option<session::os> {
|
||||
pub fn get_os(triple: &str) -> Option<session::os> {
|
||||
if str::contains(triple, ~"win32") ||
|
||||
str::contains(triple, ~"mingw32") {
|
||||
Some(session::os_win32)
|
||||
@ -455,7 +455,7 @@ pub fn get_os(triple: ~str) -> Option<session::os> {
|
||||
} else { None }
|
||||
}
|
||||
|
||||
pub fn get_arch(triple: ~str) -> Option<session::arch> {
|
||||
pub fn get_arch(triple: &str) -> Option<session::arch> {
|
||||
if str::contains(triple, ~"i386") ||
|
||||
str::contains(triple, ~"i486") ||
|
||||
str::contains(triple, ~"i586") ||
|
||||
|
@ -1443,7 +1443,7 @@ pub mod llvm {
|
||||
/** Prepares inline assembly. */
|
||||
pub unsafe fn LLVMInlineAsm(Ty: TypeRef, AsmString: *c_char,
|
||||
Constraints: *c_char, SideEffects: Bool,
|
||||
AlignStack: Bool, Dialect: AsmDialect)
|
||||
AlignStack: Bool, Dialect: c_uint)
|
||||
-> ValueRef;
|
||||
}
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ fn metas_with_ident(ident: @~str, +metas: ~[@ast::meta_item])
|
||||
metas_with(ident, @~"name", metas)
|
||||
}
|
||||
|
||||
fn existing_match(e: @mut Env, metas: ~[@ast::meta_item], hash: @~str)
|
||||
fn existing_match(e: @mut Env, metas: &[@ast::meta_item], hash: @~str)
|
||||
-> Option<int> {
|
||||
for e.crate_cache.each |c| {
|
||||
if loader::metadata_matches(*c.metas, metas)
|
||||
|
@ -560,7 +560,7 @@ pub fn maybe_get_item_ast(intr: @ident_interner, cdata: cmd, tcx: ty::ctxt,
|
||||
let item_path = item_path(intr, item_doc);
|
||||
vec::from_slice(item_path.init())
|
||||
};
|
||||
match decode_inlined_item(cdata, tcx, path, item_doc) {
|
||||
match decode_inlined_item(cdata, tcx, copy path, item_doc) {
|
||||
Some(ref ii) => csearch::found((/*bad*/copy *ii)),
|
||||
None => {
|
||||
match item_parent_item(item_doc) {
|
||||
|
@ -176,7 +176,7 @@ fn crate_matches(crate_data: @~[u8],
|
||||
metadata_matches(linkage_metas, metas)
|
||||
}
|
||||
|
||||
pub fn metadata_matches(extern_metas: ~[@ast::meta_item],
|
||||
pub fn metadata_matches(extern_metas: &[@ast::meta_item],
|
||||
local_metas: &[@ast::meta_item]) -> bool {
|
||||
|
||||
debug!("matching %u metadata requirements against %u items",
|
||||
|
@ -427,7 +427,6 @@ fn parse_mode(st: @mut PState) -> ast::mode {
|
||||
let m = ast::expl(match next(st) {
|
||||
'+' => ast::by_copy,
|
||||
'=' => ast::by_ref,
|
||||
'#' => ast::by_val,
|
||||
_ => fail!(~"bad mode")
|
||||
});
|
||||
return m;
|
||||
|
@ -342,7 +342,6 @@ pub fn enc_mode(w: io::Writer, cx: @ctxt, m: mode) {
|
||||
match ty::resolved_mode(cx.tcx, m) {
|
||||
by_copy => w.write_char('+'),
|
||||
by_ref => w.write_char('='),
|
||||
by_val => w.write_char('#')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,7 +105,7 @@ pub fn encode_inlined_item(ecx: @e::EncodeContext,
|
||||
pub fn decode_inlined_item(cdata: @cstore::crate_metadata,
|
||||
tcx: ty::ctxt,
|
||||
maps: Maps,
|
||||
path: ast_map::path,
|
||||
+path: ast_map::path,
|
||||
par_doc: ebml::Doc)
|
||||
-> Option<ast::inlined_item> {
|
||||
let dcx = @DecodeContext {
|
||||
|
@ -156,7 +156,7 @@ fn req_loans_in_expr(ex: @ast::expr,
|
||||
let arg_cmt = self.bccx.cat_expr(*arg);
|
||||
self.guarantee_valid(arg_cmt, m_imm, scope_r);
|
||||
}
|
||||
ast::by_val | ast::by_copy => {}
|
||||
ast::by_copy => {}
|
||||
}
|
||||
}
|
||||
visit::visit_expr(ex, self, vt);
|
||||
@ -172,7 +172,7 @@ fn req_loans_in_expr(ex: @ast::expr,
|
||||
let arg_cmt = self.bccx.cat_expr(*arg);
|
||||
self.guarantee_valid(arg_cmt, m_imm, scope_r);
|
||||
}
|
||||
ast::by_val | ast::by_copy => {}
|
||||
ast::by_copy => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,6 +78,7 @@ pub enum lint {
|
||||
deprecated_self,
|
||||
deprecated_mutable_fields,
|
||||
deprecated_drop,
|
||||
foreign_mode,
|
||||
|
||||
managed_heap_memory,
|
||||
owned_heap_memory,
|
||||
@ -182,6 +183,13 @@ pub fn get_lint_dict() -> LintDict {
|
||||
default: warn
|
||||
}),
|
||||
|
||||
(@~"foreign_mode",
|
||||
@LintSpec {
|
||||
lint: foreign_mode,
|
||||
desc: "warn about deprecated uses of modes in foreign fns",
|
||||
default: warn
|
||||
}),
|
||||
|
||||
(@~"deprecated_pattern",
|
||||
@LintSpec {
|
||||
lint: deprecated_pattern,
|
||||
@ -753,6 +761,20 @@ fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) {
|
||||
|
||||
fn check_foreign_fn(cx: ty::ctxt, fn_id: ast::node_id,
|
||||
decl: &ast::fn_decl) {
|
||||
// warn about `&&` mode on foreign functions, both because it is
|
||||
// deprecated and because its semantics have changed recently:
|
||||
for decl.inputs.eachi |i, arg| {
|
||||
match ty::resolved_mode(cx, arg.mode) {
|
||||
ast::by_copy => {}
|
||||
ast::by_ref => {
|
||||
cx.sess.span_lint(
|
||||
foreign_mode, fn_id, fn_id, arg.ty.span,
|
||||
fmt!("foreign function uses `&&` mode \
|
||||
on argument %u", i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let tys = vec::map(decl.inputs, |a| a.ty );
|
||||
for vec::each(vec::append_one(tys, decl.output)) |ty| {
|
||||
match ty.node {
|
||||
@ -785,7 +807,7 @@ fn check_item_ctypes(cx: ty::ctxt, it: @ast::item) {
|
||||
if attr::foreign_abi(it.attrs) !=
|
||||
either::Right(ast::foreign_abi_rust_intrinsic) => {
|
||||
for nmod.items.each |ni| {
|
||||
match /*bad*/copy ni.node {
|
||||
match ni.node {
|
||||
ast::foreign_item_fn(ref decl, _, _) => {
|
||||
check_foreign_fn(cx, it.id, decl);
|
||||
}
|
||||
|
@ -427,7 +427,7 @@ pub impl IrMaps {
|
||||
v.push(id);
|
||||
}
|
||||
Arg(_, _, by_ref) |
|
||||
Arg(_, _, by_val) | ImplicitRet => {
|
||||
ImplicitRet => {
|
||||
debug!("--but it is not owned");
|
||||
}
|
||||
}
|
||||
@ -1006,7 +1006,7 @@ pub impl Liveness {
|
||||
// inputs passed by & mode should be considered live on exit:
|
||||
for decl.inputs.each |arg| {
|
||||
match ty::resolved_mode(self.tcx, arg.mode) {
|
||||
by_val | by_ref => {
|
||||
by_ref => {
|
||||
// By val and by ref do not own, so register a
|
||||
// read at the end. This will prevent us from
|
||||
// moving out of such variables but also prevent
|
||||
|
@ -486,14 +486,6 @@ pub impl mem_categorization_ctxt {
|
||||
let lp = match ty::resolved_mode(self.tcx, mode) {
|
||||
ast::by_copy => Some(@lp_arg(vid)),
|
||||
ast::by_ref => None,
|
||||
ast::by_val => {
|
||||
// by-value is this hybrid mode where we have a
|
||||
// pointer but we do not own it. This is not
|
||||
// considered loanable because, for example, a by-ref
|
||||
// and and by-val argument might both actually contain
|
||||
// the same unique ptr.
|
||||
None
|
||||
}
|
||||
};
|
||||
@cmt_ {
|
||||
id:id,
|
||||
|
@ -782,7 +782,7 @@ pub impl VisitContext {
|
||||
*/
|
||||
|
||||
match arg_mode {
|
||||
by_val | by_ref => self.use_expr(arg_expr, Read, visitor),
|
||||
by_ref => self.use_expr(arg_expr, Read, visitor),
|
||||
by_copy => self.consume_expr(arg_expr, visitor)
|
||||
}
|
||||
}
|
||||
|
@ -2021,7 +2021,7 @@ pub impl Resolver {
|
||||
}
|
||||
|
||||
fn import_path_to_str(@mut self,
|
||||
idents: ~[ident],
|
||||
idents: &[ident],
|
||||
subclass: ImportDirectiveSubclass)
|
||||
-> @~str {
|
||||
if idents.is_empty() {
|
||||
@ -2573,7 +2573,7 @@ pub impl Resolver {
|
||||
/// Resolves the given module path from the given root `module_`.
|
||||
fn resolve_module_path_from_root(@mut self,
|
||||
module_: @mut Module,
|
||||
module_path: ~[ident],
|
||||
module_path: &[ident],
|
||||
index: uint,
|
||||
span: span,
|
||||
mut name_search_type: NameSearchType)
|
||||
@ -2658,7 +2658,7 @@ pub impl Resolver {
|
||||
/// rooted at the given module.
|
||||
fn resolve_module_path_for_import(@mut self,
|
||||
module_: @mut Module,
|
||||
module_path: ~[ident],
|
||||
module_path: &[ident],
|
||||
use_lexical_scope: UseLexicalScopeFlag,
|
||||
span: span)
|
||||
-> ResolveResult<@mut Module> {
|
||||
@ -2944,7 +2944,7 @@ pub impl Resolver {
|
||||
*/
|
||||
fn resolve_module_prefix(@mut self,
|
||||
module_: @mut Module,
|
||||
module_path: ~[ident])
|
||||
module_path: &[ident])
|
||||
-> ResolveResult<ModulePrefixResult> {
|
||||
let interner = self.session.parse_sess.interner;
|
||||
|
||||
@ -3876,7 +3876,7 @@ pub impl Resolver {
|
||||
generics: &Generics,
|
||||
opt_trait_reference: Option<@trait_ref>,
|
||||
self_type: @Ty,
|
||||
methods: ~[@method],
|
||||
methods: &[@method],
|
||||
visitor: ResolveVisitor) {
|
||||
// If applicable, create a rib for the type parameters.
|
||||
let outer_type_parameter_count = generics.ty_params.len();
|
||||
|
@ -599,7 +599,7 @@ pub fn enter_rec_or_struct(bcx: block,
|
||||
dm: DefMap,
|
||||
m: &[@Match/&r],
|
||||
col: uint,
|
||||
fields: ~[ast::ident],
|
||||
fields: &[ast::ident],
|
||||
val: ValueRef)
|
||||
-> ~[@Match/&r] {
|
||||
debug!("enter_rec_or_struct(bcx=%s, m=%s, col=%u, val=%?)",
|
||||
|
@ -1682,12 +1682,6 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
|
||||
|
||||
add_clean(bcx, llarg, arg_ty.ty);
|
||||
}
|
||||
ast::by_val => {
|
||||
// always by value, also not owned, so don't add a cleanup:
|
||||
let alloc = alloc_ty(bcx, arg_ty.ty);
|
||||
Store(bcx, raw_llarg, alloc);
|
||||
llarg = alloc;
|
||||
}
|
||||
}
|
||||
|
||||
bcx = _match::bind_irrefutable_pat(bcx,
|
||||
@ -1812,7 +1806,7 @@ pub fn trans_fn(ccx: @CrateContext,
|
||||
debug!("trans_fn(ty_self=%?)", ty_self);
|
||||
let _icx = ccx.insn_ctxt("trans_fn");
|
||||
ccx.stats.n_fns += 1;
|
||||
let the_path_str = path_str(ccx.sess, &path);
|
||||
let the_path_str = path_str(ccx.sess, path);
|
||||
trans_closure(ccx, path, decl, body, llfndecl, ty_self,
|
||||
param_substs, id, impl_id,
|
||||
|fcx| {
|
||||
|
@ -885,7 +885,7 @@ pub fn InlineAsmCall(cx: block, asm: *c_char, cons: *c_char,
|
||||
|
||||
let llfty = T_fn(~[], T_void());
|
||||
let v = llvm::LLVMInlineAsm(llfty, asm, cons, volatile,
|
||||
alignstack, dia);
|
||||
alignstack, dia as c_uint);
|
||||
|
||||
Call(cx, v, ~[])
|
||||
}
|
||||
|
@ -720,14 +720,6 @@ pub fn trans_arg_expr(bcx: block,
|
||||
val = arg_datum.to_ref_llval(bcx);
|
||||
}
|
||||
|
||||
ast::by_val => {
|
||||
// NB: avoid running the take glue.
|
||||
|
||||
fail_unless!(!bcx.ccx().maps.moves_map.contains_key(
|
||||
&arg_expr.id));
|
||||
val = arg_datum.to_value_llval(bcx);
|
||||
}
|
||||
|
||||
ast::by_copy => {
|
||||
debug!("by copy arg with type %s, storing to scratch",
|
||||
bcx.ty_to_str(arg_datum.ty));
|
||||
@ -757,7 +749,7 @@ pub fn trans_arg_expr(bcx: block,
|
||||
|
||||
if formal_ty.ty != arg_datum.ty {
|
||||
// this could happen due to e.g. subtyping
|
||||
let llformal_ty = type_of::type_of_explicit_arg(ccx, formal_ty);
|
||||
let llformal_ty = type_of::type_of_explicit_arg(ccx, &formal_ty);
|
||||
debug!("casting actual type (%s) to match formal (%s)",
|
||||
bcx.val_str(val), bcx.llty_str(llformal_ty));
|
||||
val = PointerCast(bcx, val, llformal_ty);
|
||||
|
@ -54,7 +54,7 @@ use core::vec::raw::to_ptr;
|
||||
use core::vec;
|
||||
use std::oldmap::{HashMap, Set};
|
||||
use syntax::ast::ident;
|
||||
use syntax::ast_map::path;
|
||||
use syntax::ast_map::{path, path_elt};
|
||||
use syntax::codemap::span;
|
||||
use syntax::parse::token::ident_interner;
|
||||
use syntax::{ast, ast_map};
|
||||
@ -590,7 +590,7 @@ pub struct block_ {
|
||||
fcx: fn_ctxt
|
||||
}
|
||||
|
||||
pub fn block_(llbb: BasicBlockRef, parent: Option<block>, -kind: block_kind,
|
||||
pub fn block_(llbb: BasicBlockRef, parent: Option<block>, +kind: block_kind,
|
||||
is_lpad: bool, node_info: Option<NodeInfo>, fcx: fn_ctxt)
|
||||
-> block_ {
|
||||
|
||||
@ -608,7 +608,7 @@ pub fn block_(llbb: BasicBlockRef, parent: Option<block>, -kind: block_kind,
|
||||
|
||||
pub type block = @mut block_;
|
||||
|
||||
pub fn mk_block(llbb: BasicBlockRef, parent: Option<block>, -kind: block_kind,
|
||||
pub fn mk_block(llbb: BasicBlockRef, parent: Option<block>, +kind: block_kind,
|
||||
is_lpad: bool, node_info: Option<NodeInfo>, fcx: fn_ctxt)
|
||||
-> block {
|
||||
@mut block_(llbb, parent, kind, is_lpad, node_info, fcx)
|
||||
@ -1320,9 +1320,9 @@ pub fn align_to(cx: block, off: ValueRef, align: ValueRef) -> ValueRef {
|
||||
return build::And(cx, bumped, build::Not(cx, mask));
|
||||
}
|
||||
|
||||
pub fn path_str(sess: session::Session, p: &path) -> ~str {
|
||||
pub fn path_str(sess: session::Session, p: &[path_elt]) -> ~str {
|
||||
let mut r = ~"", first = true;
|
||||
for vec::each(*p) |e| {
|
||||
for p.each |e| {
|
||||
match *e {
|
||||
ast_map::path_name(s) | ast_map::path_mod(s) => {
|
||||
if first { first = false; }
|
||||
|
@ -192,7 +192,7 @@ pub fn trans_log(log_ex: @ast::expr,
|
||||
bcx.fcx.path.filtered(|e|
|
||||
match *e { path_mod(_) => true, _ => false }
|
||||
));
|
||||
let modname = path_str(ccx.sess, &modpath);
|
||||
let modname = path_str(ccx.sess, modpath);
|
||||
|
||||
let global = if ccx.module_data.contains_key(&modname) {
|
||||
ccx.module_data.get(&modname)
|
||||
|
@ -58,59 +58,90 @@ pub fn link_name(ccx: @CrateContext, i: @ast::foreign_item) -> @~str {
|
||||
}
|
||||
}
|
||||
|
||||
struct c_stack_tys {
|
||||
arg_tys: ~[TypeRef],
|
||||
ret_ty: TypeRef,
|
||||
struct ShimTypes {
|
||||
fn_sig: ty::FnSig,
|
||||
|
||||
/// LLVM types that will appear on the foreign function
|
||||
llsig: LlvmSignature,
|
||||
|
||||
/// True if there is a return value (not bottom, not unit)
|
||||
ret_def: bool,
|
||||
|
||||
/// Type of the struct we will use to shuttle values back and forth.
|
||||
/// This is always derived from the llsig.
|
||||
bundle_ty: TypeRef,
|
||||
|
||||
/// Type of the shim function itself.
|
||||
shim_fn_ty: TypeRef,
|
||||
|
||||
/// Adapter object for handling native ABI rules (trust me, you
|
||||
/// don't want to know).
|
||||
fn_ty: cabi::FnType
|
||||
}
|
||||
|
||||
fn c_arg_and_ret_lltys(ccx: @CrateContext,
|
||||
id: ast::node_id) -> (~[TypeRef], TypeRef, ty::t) {
|
||||
match ty::get(ty::node_id_to_type(ccx.tcx, id)).sty {
|
||||
ty::ty_bare_fn(ref fn_ty) => {
|
||||
let llargtys = type_of_explicit_args(ccx, fn_ty.sig.inputs);
|
||||
let llretty = type_of::type_of(ccx, fn_ty.sig.output);
|
||||
(llargtys, llretty, fn_ty.sig.output)
|
||||
}
|
||||
_ => ccx.sess.bug(~"c_arg_and_ret_lltys called on non-function type")
|
||||
}
|
||||
struct LlvmSignature {
|
||||
llarg_tys: ~[TypeRef],
|
||||
llret_ty: TypeRef,
|
||||
}
|
||||
|
||||
fn c_stack_tys(ccx: @CrateContext,
|
||||
id: ast::node_id) -> @c_stack_tys {
|
||||
let (llargtys, llretty, ret_ty) = c_arg_and_ret_lltys(ccx, id);
|
||||
// XXX: Bad copy.
|
||||
let bundle_ty = T_struct(vec::append_one(copy llargtys, T_ptr(llretty)));
|
||||
let ret_def = !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty);
|
||||
let fn_ty = abi_info(ccx.sess.targ_cfg.arch).
|
||||
compute_info(llargtys, llretty, ret_def);
|
||||
return @c_stack_tys {
|
||||
arg_tys: llargtys,
|
||||
ret_ty: llretty,
|
||||
fn foreign_signature(ccx: @CrateContext,
|
||||
fn_sig: &ty::FnSig) -> LlvmSignature {
|
||||
/*!
|
||||
* The ForeignSignature is the LLVM types of the arguments/return type
|
||||
* of a function. Note that these LLVM types are not quite the same
|
||||
* as the LLVM types would be for a native Rust function because foreign
|
||||
* functions just plain ignore modes. They also don't pass aggregate
|
||||
* values by pointer like we do.
|
||||
*/
|
||||
|
||||
let llarg_tys = fn_sig.inputs.map(|arg| type_of(ccx, arg.ty));
|
||||
let llret_ty = type_of::type_of(ccx, fn_sig.output);
|
||||
LlvmSignature {llarg_tys: llarg_tys, llret_ty: llret_ty}
|
||||
}
|
||||
|
||||
fn shim_types(ccx: @CrateContext, id: ast::node_id) -> ShimTypes {
|
||||
let fn_sig = match ty::get(ty::node_id_to_type(ccx.tcx, id)).sty {
|
||||
ty::ty_bare_fn(ref fn_ty) => copy fn_ty.sig,
|
||||
_ => ccx.sess.bug(~"c_arg_and_ret_lltys called on non-function type")
|
||||
};
|
||||
let llsig = foreign_signature(ccx, &fn_sig);
|
||||
let bundle_ty = T_struct(vec::append_one(copy llsig.llarg_tys,
|
||||
T_ptr(llsig.llret_ty)));
|
||||
let ret_def =
|
||||
!ty::type_is_bot(fn_sig.output) &&
|
||||
!ty::type_is_nil(fn_sig.output);
|
||||
let fn_ty =
|
||||
abi_info(ccx.sess.targ_cfg.arch).compute_info(
|
||||
llsig.llarg_tys,
|
||||
llsig.llret_ty,
|
||||
ret_def);
|
||||
ShimTypes {
|
||||
fn_sig: fn_sig,
|
||||
llsig: llsig,
|
||||
ret_def: ret_def,
|
||||
bundle_ty: bundle_ty,
|
||||
shim_fn_ty: T_fn(~[T_ptr(bundle_ty)], T_void()),
|
||||
fn_ty: fn_ty
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
type shim_arg_builder = &self/fn(bcx: block, tys: @c_stack_tys,
|
||||
llargbundle: ValueRef) -> ~[ValueRef];
|
||||
type shim_arg_builder<'self> =
|
||||
&'self fn(bcx: block, tys: &ShimTypes,
|
||||
llargbundle: ValueRef) -> ~[ValueRef];
|
||||
|
||||
type shim_ret_builder = &self/fn(bcx: block, tys: @c_stack_tys,
|
||||
llargbundle: ValueRef, llretval: ValueRef);
|
||||
type shim_ret_builder<'self> =
|
||||
&'self fn(bcx: block, tys: &ShimTypes,
|
||||
llargbundle: ValueRef,
|
||||
llretval: ValueRef);
|
||||
|
||||
fn build_shim_fn_(ccx: @CrateContext,
|
||||
+shim_name: ~str,
|
||||
llbasefn: ValueRef,
|
||||
tys: @c_stack_tys,
|
||||
tys: &ShimTypes,
|
||||
cc: lib::llvm::CallConv,
|
||||
arg_builder: shim_arg_builder,
|
||||
ret_builder: shim_ret_builder) -> ValueRef {
|
||||
|
||||
ret_builder: shim_ret_builder) -> ValueRef
|
||||
{
|
||||
let llshimfn = decl_internal_cdecl_fn(
|
||||
ccx.llmod, shim_name, tys.shim_fn_ty);
|
||||
|
||||
@ -122,8 +153,7 @@ fn build_shim_fn_(ccx: @CrateContext,
|
||||
let llargvals = arg_builder(bcx, tys, llargbundle);
|
||||
|
||||
// Create the call itself and store the return value:
|
||||
let llretval = CallWithConv(bcx, llbasefn,
|
||||
llargvals, cc); // r
|
||||
let llretval = CallWithConv(bcx, llbasefn, llargvals, cc);
|
||||
|
||||
ret_builder(bcx, tys, llargbundle, llretval);
|
||||
|
||||
@ -133,21 +163,22 @@ fn build_shim_fn_(ccx: @CrateContext,
|
||||
return llshimfn;
|
||||
}
|
||||
|
||||
type wrap_arg_builder = &self/fn(bcx: block, tys: @c_stack_tys,
|
||||
llwrapfn: ValueRef,
|
||||
llargbundle: ValueRef);
|
||||
type wrap_arg_builder<'self> =
|
||||
&'self fn(bcx: block, tys: &ShimTypes,
|
||||
llwrapfn: ValueRef, llargbundle: ValueRef);
|
||||
|
||||
type wrap_ret_builder = &self/fn(bcx: block, tys: @c_stack_tys,
|
||||
llargbundle: ValueRef);
|
||||
type wrap_ret_builder<'self> =
|
||||
&'self fn(bcx: block, tys: &ShimTypes,
|
||||
llargbundle: ValueRef);
|
||||
|
||||
fn build_wrap_fn_(ccx: @CrateContext,
|
||||
tys: @c_stack_tys,
|
||||
tys: &ShimTypes,
|
||||
llshimfn: ValueRef,
|
||||
llwrapfn: ValueRef,
|
||||
shim_upcall: ValueRef,
|
||||
arg_builder: wrap_arg_builder,
|
||||
ret_builder: wrap_ret_builder) {
|
||||
|
||||
ret_builder: wrap_ret_builder)
|
||||
{
|
||||
let _icx = ccx.insn_ctxt("foreign::build_wrap_fn_");
|
||||
let fcx = new_fn_ctxt(ccx, ~[], llwrapfn, None);
|
||||
let bcx = top_scope_block(fcx, None);
|
||||
@ -199,36 +230,83 @@ fn build_wrap_fn_(ccx: @CrateContext,
|
||||
// F(args->z, args->x, args->y);
|
||||
// }
|
||||
//
|
||||
// Note: on i386, the layout of the args struct is generally the same as the
|
||||
// desired layout of the arguments on the C stack. Therefore, we could use
|
||||
// upcall_alloc_c_stack() to allocate the `args` structure and switch the
|
||||
// stack pointer appropriately to avoid a round of copies. (In fact, the shim
|
||||
// function itself is unnecessary). We used to do this, in fact, and will
|
||||
// perhaps do so in the future.
|
||||
// Note: on i386, the layout of the args struct is generally the same
|
||||
// as the desired layout of the arguments on the C stack. Therefore,
|
||||
// we could use upcall_alloc_c_stack() to allocate the `args`
|
||||
// structure and switch the stack pointer appropriately to avoid a
|
||||
// round of copies. (In fact, the shim function itself is
|
||||
// unnecessary). We used to do this, in fact, and will perhaps do so
|
||||
// in the future.
|
||||
pub fn trans_foreign_mod(ccx: @CrateContext,
|
||||
foreign_mod: &ast::foreign_mod,
|
||||
abi: ast::foreign_abi) {
|
||||
|
||||
abi: ast::foreign_abi)
|
||||
{
|
||||
let _icx = ccx.insn_ctxt("foreign::trans_foreign_mod");
|
||||
|
||||
let mut cc = match abi {
|
||||
ast::foreign_abi_rust_intrinsic |
|
||||
ast::foreign_abi_cdecl => lib::llvm::CCallConv,
|
||||
ast::foreign_abi_stdcall => lib::llvm::X86StdcallCallConv
|
||||
};
|
||||
|
||||
for vec::each(foreign_mod.items) |foreign_item| {
|
||||
match foreign_item.node {
|
||||
ast::foreign_item_fn(*) => {
|
||||
let id = foreign_item.id;
|
||||
if abi != ast::foreign_abi_rust_intrinsic {
|
||||
let llwrapfn = get_item_val(ccx, id);
|
||||
let tys = shim_types(ccx, id);
|
||||
if attr::attrs_contains_name(
|
||||
foreign_item.attrs, "rust_stack")
|
||||
{
|
||||
build_direct_fn(ccx, llwrapfn, *foreign_item,
|
||||
&tys, cc);
|
||||
} else {
|
||||
let llshimfn = build_shim_fn(ccx, *foreign_item,
|
||||
&tys, cc);
|
||||
build_wrap_fn(ccx, &tys, llshimfn, llwrapfn);
|
||||
}
|
||||
} else {
|
||||
// Intrinsics are emitted by monomorphic fn
|
||||
}
|
||||
}
|
||||
ast::foreign_item_const(*) => {
|
||||
let ident = ccx.sess.parse_sess.interner.get(
|
||||
foreign_item.ident);
|
||||
ccx.item_symbols.insert(foreign_item.id, copy *ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_shim_fn(ccx: @CrateContext,
|
||||
foreign_item: @ast::foreign_item,
|
||||
tys: @c_stack_tys,
|
||||
cc: lib::llvm::CallConv) -> ValueRef {
|
||||
tys: &ShimTypes,
|
||||
cc: lib::llvm::CallConv) -> ValueRef
|
||||
{
|
||||
/*!
|
||||
*
|
||||
* Build S, from comment above:
|
||||
*
|
||||
* void S(struct { X x; Y y; Z *z; } *args) {
|
||||
* F(args->z, args->x, args->y);
|
||||
* }
|
||||
*/
|
||||
|
||||
let _icx = ccx.insn_ctxt("foreign::build_shim_fn");
|
||||
|
||||
fn build_args(bcx: block, tys: @c_stack_tys,
|
||||
fn build_args(bcx: block, tys: &ShimTypes,
|
||||
llargbundle: ValueRef) -> ~[ValueRef] {
|
||||
let _icx = bcx.insn_ctxt("foreign::shim::build_args");
|
||||
return tys.fn_ty.build_shim_args(bcx, tys.arg_tys, llargbundle);
|
||||
tys.fn_ty.build_shim_args(
|
||||
bcx, tys.llsig.llarg_tys, llargbundle)
|
||||
}
|
||||
|
||||
fn build_ret(bcx: block, tys: @c_stack_tys,
|
||||
fn build_ret(bcx: block, tys: &ShimTypes,
|
||||
llargbundle: ValueRef, llretval: ValueRef) {
|
||||
let _icx = bcx.insn_ctxt("foreign::shim::build_ret");
|
||||
tys.fn_ty.build_shim_ret(bcx, tys.arg_tys, tys.ret_def,
|
||||
llargbundle, llretval);
|
||||
tys.fn_ty.build_shim_ret(
|
||||
bcx, tys.llsig.llarg_tys,
|
||||
tys.ret_def, llargbundle, llretval);
|
||||
}
|
||||
|
||||
let lname = link_name(ccx, foreign_item);
|
||||
@ -239,7 +317,7 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
|
||||
build_args, build_ret);
|
||||
}
|
||||
|
||||
fn base_fn(ccx: @CrateContext, lname: &str, tys: @c_stack_tys,
|
||||
fn base_fn(ccx: @CrateContext, lname: &str, tys: &ShimTypes,
|
||||
cc: lib::llvm::CallConv) -> ValueRef {
|
||||
// Declare the "prototype" for the base function F:
|
||||
do tys.fn_ty.decl_fn |fnty| {
|
||||
@ -250,7 +328,7 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
|
||||
// FIXME (#2535): this is very shaky and probably gets ABIs wrong all
|
||||
// over the place
|
||||
fn build_direct_fn(ccx: @CrateContext, decl: ValueRef,
|
||||
item: @ast::foreign_item, tys: @c_stack_tys,
|
||||
item: @ast::foreign_item, tys: &ShimTypes,
|
||||
cc: lib::llvm::CallConv) {
|
||||
let fcx = new_fn_ctxt(ccx, ~[], decl, None);
|
||||
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
|
||||
@ -269,66 +347,55 @@ pub fn trans_foreign_mod(ccx: @CrateContext,
|
||||
}
|
||||
|
||||
fn build_wrap_fn(ccx: @CrateContext,
|
||||
tys: @c_stack_tys,
|
||||
tys: &ShimTypes,
|
||||
llshimfn: ValueRef,
|
||||
llwrapfn: ValueRef) {
|
||||
/*!
|
||||
*
|
||||
* Build W, from comment above:
|
||||
*
|
||||
* void W(Z* dest, void *env, X x, Y y) {
|
||||
* struct { X x; Y y; Z *z; } args = { x, y, z };
|
||||
* call_on_c_stack_shim(S, &args);
|
||||
* }
|
||||
*
|
||||
* One thing we have to be very careful of is to
|
||||
* account for the Rust modes.
|
||||
*/
|
||||
|
||||
let _icx = ccx.insn_ctxt("foreign::build_wrap_fn");
|
||||
|
||||
fn build_args(bcx: block, tys: @c_stack_tys,
|
||||
build_wrap_fn_(ccx, tys, llshimfn, llwrapfn,
|
||||
ccx.upcalls.call_shim_on_c_stack,
|
||||
build_args, build_ret);
|
||||
|
||||
fn build_args(bcx: block, tys: &ShimTypes,
|
||||
llwrapfn: ValueRef, llargbundle: ValueRef) {
|
||||
let _icx = bcx.insn_ctxt("foreign::wrap::build_args");
|
||||
let mut i = 0u;
|
||||
let n = vec::len(tys.arg_tys);
|
||||
let ccx = bcx.ccx();
|
||||
let n = vec::len(tys.llsig.llarg_tys);
|
||||
let implicit_args = first_real_arg; // return + env
|
||||
while i < n {
|
||||
let llargval = get_param(llwrapfn, i + implicit_args);
|
||||
for uint::range(0, n) |i| {
|
||||
let mut llargval = get_param(llwrapfn, i + implicit_args);
|
||||
|
||||
// In some cases, Rust will pass a pointer which the
|
||||
// native C type doesn't have. In that case, just
|
||||
// load the value from the pointer.
|
||||
if type_of::arg_is_indirect(ccx, &tys.fn_sig.inputs[i]) {
|
||||
llargval = Load(bcx, llargval);
|
||||
}
|
||||
|
||||
store_inbounds(bcx, llargval, llargbundle, ~[0u, i]);
|
||||
i += 1u;
|
||||
}
|
||||
let llretptr = get_param(llwrapfn, 0u);
|
||||
store_inbounds(bcx, llretptr, llargbundle, ~[0u, n]);
|
||||
}
|
||||
|
||||
fn build_ret(bcx: block, _tys: @c_stack_tys,
|
||||
fn build_ret(bcx: block, _tys: &ShimTypes,
|
||||
_llargbundle: ValueRef) {
|
||||
let _icx = bcx.insn_ctxt("foreign::wrap::build_ret");
|
||||
RetVoid(bcx);
|
||||
}
|
||||
|
||||
build_wrap_fn_(ccx, tys, llshimfn, llwrapfn,
|
||||
ccx.upcalls.call_shim_on_c_stack,
|
||||
build_args, build_ret);
|
||||
}
|
||||
|
||||
let mut cc = match abi {
|
||||
ast::foreign_abi_rust_intrinsic |
|
||||
ast::foreign_abi_cdecl => lib::llvm::CCallConv,
|
||||
ast::foreign_abi_stdcall => lib::llvm::X86StdcallCallConv
|
||||
};
|
||||
|
||||
for vec::each(foreign_mod.items) |foreign_item| {
|
||||
match foreign_item.node {
|
||||
ast::foreign_item_fn(*) => {
|
||||
let id = foreign_item.id;
|
||||
if abi != ast::foreign_abi_rust_intrinsic {
|
||||
let llwrapfn = get_item_val(ccx, id);
|
||||
let tys = c_stack_tys(ccx, id);
|
||||
if attr::attrs_contains_name(foreign_item.attrs, "rust_stack") {
|
||||
build_direct_fn(ccx, llwrapfn, *foreign_item, tys, cc);
|
||||
} else {
|
||||
let llshimfn = build_shim_fn(ccx, *foreign_item, tys, cc);
|
||||
build_wrap_fn(ccx, tys, llshimfn, llwrapfn);
|
||||
}
|
||||
} else {
|
||||
// Intrinsics are emitted by monomorphic fn
|
||||
}
|
||||
}
|
||||
ast::foreign_item_const(*) => {
|
||||
let ident = ccx.sess.parse_sess.interner.get(foreign_item.ident);
|
||||
ccx.item_symbols.insert(foreign_item.id, copy *ident);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -842,6 +909,32 @@ pub fn trans_intrinsic(ccx: @CrateContext,
|
||||
finish_fn(fcx, lltop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a "crust" fn, meaning a Rust fn that can be called
|
||||
* from C code. In this case, we have to perform some adaptation
|
||||
* to (1) switch back to the Rust stack and (2) adapt the C calling
|
||||
* convention to our own.
|
||||
*
|
||||
* Example: Given a crust fn F(x: X, y: Y) -> Z, we generate a
|
||||
* Rust function R as normal:
|
||||
*
|
||||
* void R(Z* dest, void *env, X x, Y y) {...}
|
||||
*
|
||||
* and then we generate a wrapper function W that looks like:
|
||||
*
|
||||
* Z W(X x, Y y) {
|
||||
* struct { X x; Y y; Z *z; } args = { x, y, z };
|
||||
* call_on_c_stack_shim(S, &args);
|
||||
* }
|
||||
*
|
||||
* Note that the wrapper follows the foreign (typically "C") ABI.
|
||||
* The wrapper is the actual "value" of the foreign fn. Finally,
|
||||
* we generate a shim function S that looks like:
|
||||
*
|
||||
* void S(struct { X x; Y y; Z *z; } *args) {
|
||||
* R(args->z, NULL, args->x, args->y);
|
||||
* }
|
||||
*/
|
||||
pub fn trans_foreign_fn(ccx: @CrateContext,
|
||||
+path: ast_map::path,
|
||||
decl: &ast::fn_decl,
|
||||
@ -867,28 +960,51 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
|
||||
}
|
||||
|
||||
fn build_shim_fn(ccx: @CrateContext, +path: ast_map::path,
|
||||
llrustfn: ValueRef, tys: @c_stack_tys) -> ValueRef {
|
||||
llrustfn: ValueRef, tys: &ShimTypes) -> ValueRef {
|
||||
/*!
|
||||
*
|
||||
* Generate the shim S:
|
||||
*
|
||||
* void S(struct { X x; Y y; Z *z; } *args) {
|
||||
* R(args->z, NULL, &args->x, args->y);
|
||||
* }
|
||||
*
|
||||
* One complication is that we must adapt to the Rust
|
||||
* calling convention, which introduces indirection
|
||||
* in some cases. To demonstrate this, I wrote one of the
|
||||
* entries above as `&args->x`, because presumably `X` is
|
||||
* one of those types that is passed by pointer in Rust.
|
||||
*/
|
||||
|
||||
let _icx = ccx.insn_ctxt("foreign::foreign::build_shim_fn");
|
||||
|
||||
fn build_args(bcx: block, tys: @c_stack_tys,
|
||||
fn build_args(bcx: block, tys: &ShimTypes,
|
||||
llargbundle: ValueRef) -> ~[ValueRef] {
|
||||
let _icx = bcx.insn_ctxt("foreign::extern::shim::build_args");
|
||||
let ccx = bcx.ccx();
|
||||
let mut llargvals = ~[];
|
||||
let mut i = 0u;
|
||||
let n = vec::len(tys.arg_tys);
|
||||
let n = tys.fn_sig.inputs.len();
|
||||
let llretptr = load_inbounds(bcx, llargbundle, ~[0u, n]);
|
||||
llargvals.push(llretptr);
|
||||
let llenvptr = C_null(T_opaque_box_ptr(bcx.ccx()));
|
||||
llargvals.push(llenvptr);
|
||||
while i < n {
|
||||
let llargval = load_inbounds(bcx, llargbundle, ~[0u, i]);
|
||||
// Get a pointer to the argument:
|
||||
let mut llargval = GEPi(bcx, llargbundle, [0u, i]);
|
||||
|
||||
if !type_of::arg_is_indirect(ccx, &tys.fn_sig.inputs[i]) {
|
||||
// If Rust would pass this by value, load the value.
|
||||
llargval = Load(bcx, llargval);
|
||||
}
|
||||
|
||||
llargvals.push(llargval);
|
||||
i += 1u;
|
||||
}
|
||||
return llargvals;
|
||||
}
|
||||
|
||||
fn build_ret(_bcx: block, _tys: @c_stack_tys,
|
||||
fn build_ret(_bcx: block, _tys: &ShimTypes,
|
||||
_llargbundle: ValueRef, _llretval: ValueRef) {
|
||||
// Nop. The return pointer in the Rust ABI function
|
||||
// is wired directly into the return slot in the shim struct
|
||||
@ -904,36 +1020,48 @@ pub fn trans_foreign_fn(ccx: @CrateContext,
|
||||
}
|
||||
|
||||
fn build_wrap_fn(ccx: @CrateContext, llshimfn: ValueRef,
|
||||
llwrapfn: ValueRef, tys: @c_stack_tys) {
|
||||
llwrapfn: ValueRef, tys: &ShimTypes)
|
||||
{
|
||||
/*!
|
||||
*
|
||||
* Generate the wrapper W:
|
||||
*
|
||||
* Z W(X x, Y y) {
|
||||
* struct { X x; Y y; Z *z; } args = { x, y, z };
|
||||
* call_on_c_stack_shim(S, &args);
|
||||
* }
|
||||
*/
|
||||
|
||||
let _icx = ccx.insn_ctxt("foreign::foreign::build_wrap_fn");
|
||||
|
||||
fn build_args(bcx: block, tys: @c_stack_tys,
|
||||
llwrapfn: ValueRef, llargbundle: ValueRef) {
|
||||
let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_args");
|
||||
tys.fn_ty.build_wrap_args(bcx, tys.ret_ty,
|
||||
llwrapfn, llargbundle);
|
||||
}
|
||||
|
||||
fn build_ret(bcx: block, tys: @c_stack_tys,
|
||||
llargbundle: ValueRef) {
|
||||
let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_ret");
|
||||
tys.fn_ty.build_wrap_ret(bcx, tys.arg_tys, llargbundle);
|
||||
}
|
||||
|
||||
build_wrap_fn_(ccx, tys, llshimfn, llwrapfn,
|
||||
ccx.upcalls.call_shim_on_rust_stack,
|
||||
build_args, build_ret);
|
||||
|
||||
fn build_args(bcx: block, tys: &ShimTypes,
|
||||
llwrapfn: ValueRef, llargbundle: ValueRef) {
|
||||
let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_args");
|
||||
tys.fn_ty.build_wrap_args(
|
||||
bcx, tys.llsig.llret_ty,
|
||||
llwrapfn, llargbundle);
|
||||
}
|
||||
|
||||
fn build_ret(bcx: block, tys: &ShimTypes,
|
||||
llargbundle: ValueRef) {
|
||||
let _icx = bcx.insn_ctxt("foreign::foreign::wrap::build_ret");
|
||||
tys.fn_ty.build_wrap_ret(
|
||||
bcx, tys.llsig.llarg_tys, llargbundle);
|
||||
}
|
||||
}
|
||||
|
||||
let tys = c_stack_tys(ccx, id);
|
||||
let tys = shim_types(ccx, id);
|
||||
// The internal Rust ABI function - runs on the Rust stack
|
||||
// XXX: Bad copy.
|
||||
let llrustfn = build_rust_fn(ccx, copy path, decl, body, id);
|
||||
// The internal shim function - runs on the Rust stack
|
||||
let llshimfn = build_shim_fn(ccx, path, llrustfn, tys);
|
||||
let llshimfn = build_shim_fn(ccx, path, llrustfn, &tys);
|
||||
// The foreign C function - runs on the C stack
|
||||
build_wrap_fn(ccx, llshimfn, llwrapfn, tys)
|
||||
build_wrap_fn(ccx, llshimfn, llwrapfn, &tys)
|
||||
}
|
||||
|
||||
pub fn register_foreign_fn(ccx: @CrateContext,
|
||||
@ -944,11 +1072,8 @@ pub fn register_foreign_fn(ccx: @CrateContext,
|
||||
-> ValueRef {
|
||||
let _icx = ccx.insn_ctxt("foreign::register_foreign_fn");
|
||||
let t = ty::node_id_to_type(ccx.tcx, node_id);
|
||||
let (llargtys, llretty, ret_ty) = c_arg_and_ret_lltys(ccx, node_id);
|
||||
let ret_def = !ty::type_is_bot(ret_ty) && !ty::type_is_nil(ret_ty);
|
||||
let fn_ty = abi_info(ccx.sess.targ_cfg.arch).
|
||||
compute_info(llargtys, llretty, ret_def);
|
||||
do fn_ty.decl_fn |fnty| {
|
||||
let tys = shim_types(ccx, node_id);
|
||||
do tys.fn_ty.decl_fn |fnty| {
|
||||
register_fn_fuller(ccx, sp, /*bad*/copy path, node_id, attrs,
|
||||
t, lib::llvm::CCallConv, fnty)
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ be generated once they are invoked with specific type parameters,
|
||||
see `trans::base::lval_static_fn()` or `trans::base::monomorphic_fn()`.
|
||||
*/
|
||||
pub fn trans_impl(ccx: @CrateContext, +path: path, name: ast::ident,
|
||||
methods: ~[@ast::method], generics: &ast::Generics,
|
||||
methods: &[@ast::method], generics: &ast::Generics,
|
||||
self_ty: Option<ty::t>, id: ast::node_id) {
|
||||
let _icx = ccx.insn_ctxt("impl::trans_impl");
|
||||
if !generics.ty_params.is_empty() { return; }
|
||||
|
@ -313,7 +313,6 @@ pub impl Reflector {
|
||||
ast::infer(_) => 0u,
|
||||
ast::expl(e) => match e {
|
||||
ast::by_ref => 1u,
|
||||
ast::by_val => 2u,
|
||||
ast::by_copy => 5u
|
||||
}
|
||||
};
|
||||
|
@ -21,24 +21,21 @@ use util::ppaux;
|
||||
use core::option::None;
|
||||
use syntax::ast;
|
||||
|
||||
pub fn type_of_explicit_arg(ccx: @CrateContext, arg: ty::arg) -> TypeRef {
|
||||
let llty = type_of(ccx, arg.ty);
|
||||
pub fn arg_is_indirect(ccx: @CrateContext, arg: &ty::arg) -> bool {
|
||||
match ty::resolved_mode(ccx.tcx, arg.mode) {
|
||||
ast::by_val => llty,
|
||||
ast::by_copy => {
|
||||
if ty::type_is_immediate(arg.ty) {
|
||||
llty
|
||||
} else {
|
||||
T_ptr(llty)
|
||||
}
|
||||
}
|
||||
_ => T_ptr(llty)
|
||||
ast::by_copy => !ty::type_is_immediate(arg.ty),
|
||||
ast::by_ref => true
|
||||
}
|
||||
}
|
||||
|
||||
pub fn type_of_explicit_arg(ccx: @CrateContext, arg: &ty::arg) -> TypeRef {
|
||||
let llty = type_of(ccx, arg.ty);
|
||||
if arg_is_indirect(ccx, arg) {T_ptr(llty)} else {llty}
|
||||
}
|
||||
|
||||
pub fn type_of_explicit_args(ccx: @CrateContext,
|
||||
inputs: &[ty::arg]) -> ~[TypeRef] {
|
||||
inputs.map(|arg| type_of_explicit_arg(ccx, *arg))
|
||||
inputs.map(|arg| type_of_explicit_arg(ccx, arg))
|
||||
}
|
||||
|
||||
pub fn type_of_fn(cx: @CrateContext, inputs: &[ty::arg],
|
||||
|
@ -81,7 +81,7 @@ pub fn type_uses_for(ccx: @CrateContext, fn_id: def_id, n_tps: uint)
|
||||
ty::ty_closure(ty::ClosureTy {sig: ref sig, _}) => {
|
||||
for vec::each(sig.inputs) |arg| {
|
||||
match ty::resolved_mode(ccx.tcx, arg.mode) {
|
||||
by_val | by_copy => {
|
||||
by_copy => {
|
||||
type_needs(cx, use_repr, arg.ty);
|
||||
}
|
||||
by_ref => {}
|
||||
@ -326,7 +326,7 @@ pub fn mark_for_expr(cx: Context, e: @expr) {
|
||||
ty::ty_fn_args(ty::node_id_to_type(cx.ccx.tcx, f.id))
|
||||
) |a| {
|
||||
match a.mode {
|
||||
expl(by_copy) | expl(by_val) => {
|
||||
expl(by_copy) => {
|
||||
type_needs(cx, use_repr, a.ty);
|
||||
}
|
||||
_ => ()
|
||||
@ -340,7 +340,7 @@ pub fn mark_for_expr(cx: Context, e: @expr) {
|
||||
for ty::ty_fn_args(ty::node_id_to_type(cx.ccx.tcx,
|
||||
e.callee_id)).each |a| {
|
||||
match a.mode {
|
||||
expl(by_copy) | expl(by_val) => {
|
||||
expl(by_copy) => {
|
||||
type_needs(cx, use_repr, a.ty);
|
||||
}
|
||||
_ => ()
|
||||
|
@ -1110,7 +1110,7 @@ pub fn default_arg_mode_for_ty(tcx: ctxt, ty: ty::t) -> ast::rmode {
|
||||
// forward-compatible with non-legacy, we should use +
|
||||
ast::by_copy
|
||||
} else if ty::type_is_immediate(ty) {
|
||||
ast::by_val
|
||||
ast::by_copy
|
||||
} else {
|
||||
ast::by_ref
|
||||
}
|
||||
|
@ -3207,7 +3207,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
|
||||
let (_, visitor_trait) = tcx.intrinsic_defs.get(&ty_visitor_name);
|
||||
let td_ptr = ty::mk_ptr(ccx.tcx, ty::mt {ty: tydesc_ty,
|
||||
mutbl: ast::m_imm});
|
||||
(0u, ~[arg(ast::by_val, td_ptr),
|
||||
(0u, ~[arg(ast::by_copy, td_ptr),
|
||||
arg(ast::by_ref, visitor_trait)], ty::mk_nil(tcx))
|
||||
}
|
||||
~"frame_address" => {
|
||||
@ -3217,7 +3217,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
|
||||
onceness: ast::Once,
|
||||
region: ty::re_bound(ty::br_anon(0)),
|
||||
sig: ty::FnSig {
|
||||
inputs: ~[arg {mode: ast::expl(ast::by_val),
|
||||
inputs: ~[arg {mode: ast::expl(ast::by_copy),
|
||||
ty: ty::mk_imm_ptr(
|
||||
ccx.tcx,
|
||||
ty::mk_mach_uint(ccx.tcx, ast::ty_u8))}],
|
||||
|
@ -273,26 +273,6 @@ impl get_and_find_region for isr_alist {
|
||||
}
|
||||
}
|
||||
|
||||
fn arg_is_argv_ty(tcx: ty::ctxt, a: ty::arg) -> bool {
|
||||
match ty::resolved_mode(tcx, a.mode) {
|
||||
ast::by_val => { /*ok*/ }
|
||||
_ => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
match ty::get(a.ty).sty {
|
||||
ty::ty_evec(mt, vstore_uniq) => {
|
||||
if mt.mutbl != ast::m_imm { return false; }
|
||||
match ty::get(mt.ty).sty {
|
||||
ty::ty_estr(vstore_uniq) => return true,
|
||||
_ => return false
|
||||
}
|
||||
}
|
||||
_ => return false
|
||||
}
|
||||
}
|
||||
|
||||
fn check_main_fn_ty(ccx: @mut CrateCtxt,
|
||||
main_id: ast::node_id,
|
||||
main_span: span) {
|
||||
|
@ -49,7 +49,7 @@ use core::vec;
|
||||
pub mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
fn move_val_init<T>(dst: &mut T, -src: T);
|
||||
fn move_val_init<T>(dst: &mut T, +src: T);
|
||||
fn needs_drop<T>() -> bool;
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ use core::vec;
|
||||
|
||||
#[abi = "rust-intrinsic"]
|
||||
extern "C" mod rusti {
|
||||
fn move_val_init<T>(dst: &mut T, -src: T);
|
||||
fn move_val_init<T>(dst: &mut T, +src: T);
|
||||
fn init<T>() -> T;
|
||||
}
|
||||
|
||||
|
@ -30,10 +30,10 @@ pub mod rustrt {
|
||||
|
||||
pub unsafe fn rust_tzset();
|
||||
// FIXME: The i64 values can be passed by-val when #2064 is fixed.
|
||||
pub unsafe fn rust_gmtime(&&sec: i64, &&nsec: i32, &&result: Tm);
|
||||
pub unsafe fn rust_localtime(&&sec: i64, &&nsec: i32, &&result: Tm);
|
||||
pub unsafe fn rust_timegm(&&tm: Tm, sec: &mut i64);
|
||||
pub unsafe fn rust_mktime(&&tm: Tm, sec: &mut i64);
|
||||
pub unsafe fn rust_gmtime(sec: i64, nsec: i32, result: &mut Tm);
|
||||
pub unsafe fn rust_localtime(sec: i64, nsec: i32, result: &mut Tm);
|
||||
pub unsafe fn rust_timegm(tm: &Tm, sec: &mut i64);
|
||||
pub unsafe fn rust_mktime(tm: &Tm, sec: &mut i64);
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,7 +172,7 @@ pub fn at_utc(clock: Timespec) -> Tm {
|
||||
unsafe {
|
||||
let mut Timespec { sec, nsec } = clock;
|
||||
let mut tm = empty_tm();
|
||||
rustrt::rust_gmtime(sec, nsec, tm);
|
||||
rustrt::rust_gmtime(sec, nsec, &mut tm);
|
||||
tm
|
||||
}
|
||||
}
|
||||
@ -187,7 +187,7 @@ pub fn at(clock: Timespec) -> Tm {
|
||||
unsafe {
|
||||
let mut Timespec { sec, nsec } = clock;
|
||||
let mut tm = empty_tm();
|
||||
rustrt::rust_localtime(sec, nsec, tm);
|
||||
rustrt::rust_localtime(sec, nsec, &mut tm);
|
||||
tm
|
||||
}
|
||||
}
|
||||
@ -217,9 +217,9 @@ pub impl Tm {
|
||||
unsafe {
|
||||
let mut sec = 0i64;
|
||||
if self.tm_gmtoff == 0_i32 {
|
||||
rustrt::rust_timegm(*self, &mut sec);
|
||||
rustrt::rust_timegm(self, &mut sec);
|
||||
} else {
|
||||
rustrt::rust_mktime(*self, &mut sec);
|
||||
rustrt::rust_mktime(self, &mut sec);
|
||||
}
|
||||
Timespec::new(sec, self.tm_nsec)
|
||||
}
|
||||
|
@ -456,7 +456,7 @@ impl<T:to_bytes::IterBytes> to_bytes::IterBytes for inferable<T> {
|
||||
#[auto_encode]
|
||||
#[auto_decode]
|
||||
#[deriving_eq]
|
||||
pub enum rmode { by_ref, by_val, by_copy }
|
||||
pub enum rmode { by_ref, by_copy }
|
||||
|
||||
impl to_bytes::IterBytes for rmode {
|
||||
pure fn iter_bytes(&self, +lsb0: bool, f: to_bytes::Cb) {
|
||||
|
@ -148,7 +148,7 @@ pub fn map_crate(diag: span_handler, c: crate) -> map {
|
||||
// the item itself.
|
||||
pub fn map_decoded_item(diag: span_handler,
|
||||
map: map,
|
||||
path: path,
|
||||
+path: path,
|
||||
ii: inlined_item) {
|
||||
// I believe it is ok for the local IDs of inlined items from other crates
|
||||
// to overlap with the local ids from this crate, so just generate the ids
|
||||
@ -171,10 +171,10 @@ pub fn map_decoded_item(diag: span_handler,
|
||||
ii_item(*) | ii_dtor(*) => { /* fallthrough */ }
|
||||
ii_foreign(i) => {
|
||||
cx.map.insert(i.id, node_foreign_item(i, foreign_abi_rust_intrinsic,
|
||||
@/*bad*/ copy path));
|
||||
@path));
|
||||
}
|
||||
ii_method(impl_did, m) => {
|
||||
map_method(impl_did, @/*bad*/ copy path, m, cx);
|
||||
map_method(impl_did, @path, m, cx);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ pub fn attr_meta(attr: ast::attribute) -> @ast::meta_item {
|
||||
}
|
||||
|
||||
// Get the meta_items from inside a vector of attributes
|
||||
pub fn attr_metas(attrs: ~[ast::attribute]) -> ~[@ast::meta_item] {
|
||||
pub fn attr_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
|
||||
do attrs.map |a| { attr_meta(*a) }
|
||||
}
|
||||
|
||||
@ -214,7 +214,7 @@ pub fn attrs_contains_name(attrs: &[ast::attribute], name: &str) -> bool {
|
||||
!find_attrs_by_name(attrs, name).is_empty()
|
||||
}
|
||||
|
||||
pub fn first_attr_value_str_by_name(attrs: ~[ast::attribute], name: &str)
|
||||
pub fn first_attr_value_str_by_name(attrs: &[ast::attribute], name: &str)
|
||||
-> Option<@~str> {
|
||||
|
||||
let mattrs = find_attrs_by_name(attrs, name);
|
||||
@ -304,7 +304,7 @@ pub fn find_linkage_metas(attrs: &[ast::attribute]) -> ~[@ast::meta_item] {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn foreign_abi(attrs: ~[ast::attribute])
|
||||
pub fn foreign_abi(attrs: &[ast::attribute])
|
||||
-> Either<~str, ast::foreign_abi> {
|
||||
return match attr::first_attr_value_str_by_name(attrs, ~"abi") {
|
||||
None => {
|
||||
|
@ -55,6 +55,7 @@ pub enum ObsoleteSyntax {
|
||||
ObsoletePostFnTySigil,
|
||||
ObsoleteBareFnType,
|
||||
ObsoleteNewtypeEnum,
|
||||
ObsoleteMode,
|
||||
}
|
||||
|
||||
impl to_bytes::IterBytes for ObsoleteSyntax {
|
||||
@ -176,6 +177,10 @@ pub impl Parser {
|
||||
"newtype enum",
|
||||
"instead of `enum Foo = int`, write `struct Foo(int)`"
|
||||
),
|
||||
ObsoleteMode => (
|
||||
"obsolete argument mode",
|
||||
"replace `-` or `++` mode with `+`"
|
||||
),
|
||||
};
|
||||
|
||||
self.report(sp, kind, kind_str, desc);
|
||||
|
@ -17,7 +17,7 @@ use ast::{RegionTyParamBound, TraitTyParamBound};
|
||||
use ast::{provided, public, pure_fn, purity};
|
||||
use ast::{_mod, add, arg, arm, attribute, bind_by_ref, bind_infer};
|
||||
use ast::{bind_by_copy, bitand, bitor, bitxor, blk};
|
||||
use ast::{blk_check_mode, box, by_copy, by_ref, by_val};
|
||||
use ast::{blk_check_mode, box, by_copy, by_ref};
|
||||
use ast::{crate, crate_cfg, decl, decl_item};
|
||||
use ast::{decl_local, default_blk, deref, div, enum_def, enum_variant_kind};
|
||||
use ast::{expl, expr, expr_, expr_addr_of, expr_match, expr_again};
|
||||
@ -78,6 +78,7 @@ use parse::obsolete::{ObsoleteMutVector, ObsoleteTraitImplVisibility};
|
||||
use parse::obsolete::{ObsoleteRecordType, ObsoleteRecordPattern};
|
||||
use parse::obsolete::{ObsoleteAssertion, ObsoletePostFnTySigil};
|
||||
use parse::obsolete::{ObsoleteBareFnType, ObsoleteNewtypeEnum};
|
||||
use parse::obsolete::{ObsoleteMode};
|
||||
use parse::prec::{as_prec, token_to_binop};
|
||||
use parse::token::{can_begin_expr, is_ident, is_ident_or_path};
|
||||
use parse::token::{is_plain_ident, INTERPOLATED, special_idents};
|
||||
@ -716,12 +717,15 @@ pub impl Parser {
|
||||
|
||||
fn parse_arg_mode(&self) -> mode {
|
||||
if self.eat(&token::BINOP(token::MINUS)) {
|
||||
expl(by_copy) // NDM outdated syntax
|
||||
self.obsolete(*self.span, ObsoleteMode);
|
||||
expl(by_copy)
|
||||
} else if self.eat(&token::ANDAND) {
|
||||
expl(by_ref)
|
||||
} else if self.eat(&token::BINOP(token::PLUS)) {
|
||||
if self.eat(&token::BINOP(token::PLUS)) {
|
||||
expl(by_val)
|
||||
// ++ mode is obsolete, but we need a snapshot
|
||||
// to stop parsing it.
|
||||
expl(by_copy)
|
||||
} else {
|
||||
expl(by_copy)
|
||||
}
|
||||
|
@ -1710,7 +1710,6 @@ pub fn mode_to_str(m: ast::mode) -> ~str {
|
||||
match m {
|
||||
ast::expl(ast::by_ref) => ~"&&",
|
||||
ast::expl(ast::by_copy) => ~"+",
|
||||
ast::expl(ast::by_val) => ~"++",
|
||||
ast::infer(_) => ~""
|
||||
}
|
||||
}
|
||||
|
@ -434,18 +434,18 @@ rust_tzset() {
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
rust_gmtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
|
||||
rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
|
||||
tm tm;
|
||||
time_t s = *sec;
|
||||
time_t s = sec;
|
||||
GMTIME(&s, &tm);
|
||||
|
||||
tm_to_rust_tm(&tm, timeptr, 0, "UTC", *nsec);
|
||||
tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec);
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
rust_localtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
|
||||
rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
|
||||
tm tm;
|
||||
time_t s = *sec;
|
||||
time_t s = sec;
|
||||
LOCALTIME(&s, &tm);
|
||||
|
||||
#if defined(__WIN32__)
|
||||
@ -457,7 +457,7 @@ rust_localtime(int64_t *sec, int32_t *nsec, rust_tm *timeptr) {
|
||||
const char *zone = tm.tm_zone;
|
||||
#endif
|
||||
|
||||
tm_to_rust_tm(&tm, timeptr, gmtoff, zone, *nsec);
|
||||
tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec);
|
||||
}
|
||||
|
||||
extern "C" CDECL void
|
||||
@ -844,6 +844,38 @@ rust_readdir() {
|
||||
|
||||
#endif
|
||||
|
||||
// These functions are used in the unit tests for C ABI calls.
|
||||
|
||||
extern "C" CDECL uint32_t
|
||||
rust_dbg_extern_identity_u32(uint32_t u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
extern "C" CDECL uint64_t
|
||||
rust_dbg_extern_identity_u64(uint64_t u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
struct TwoU64s {
|
||||
uint64_t one;
|
||||
uint64_t two;
|
||||
};
|
||||
|
||||
extern "C" CDECL TwoU64s
|
||||
rust_dbg_extern_identity_TwoU64s(TwoU64s u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
extern "C" CDECL double
|
||||
rust_dbg_extern_identity_double(double u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
extern "C" CDECL char
|
||||
rust_dbg_extern_identity_u8(char u) {
|
||||
return u;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Local Variables:
|
||||
|
@ -195,4 +195,9 @@ rust_get_exchange_count_ptr
|
||||
rust_get_sched_tls_key
|
||||
swap_registers
|
||||
rust_readdir
|
||||
rust_opendir
|
||||
rust_opendir
|
||||
rust_dbg_extern_identity_u32
|
||||
rust_dbg_extern_identity_u64
|
||||
rust_dbg_extern_identity_TwoU64s
|
||||
rust_dbg_extern_identity_double
|
||||
rust_dbg_extern_identity_u8
|
||||
|
@ -546,8 +546,8 @@ extern "C" LLVMValueRef LLVMInlineAsm(LLVMTypeRef Ty,
|
||||
char *Constraints,
|
||||
LLVMBool HasSideEffects,
|
||||
LLVMBool IsAlignStack,
|
||||
InlineAsm::AsmDialect Dialect) {
|
||||
unsigned Dialect) {
|
||||
return wrap(InlineAsm::get(unwrap<FunctionType>(Ty), AsmString,
|
||||
Constraints, HasSideEffects,
|
||||
IsAlignStack, Dialect));
|
||||
IsAlignStack, (InlineAsm::AsmDialect) Dialect));
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ pub mod kitties {
|
||||
fn meow_count(&mut self) -> uint { self.meows }
|
||||
}
|
||||
|
||||
pub fn cat<U>(in_x : uint, in_y : int, -in_info: ~[U]) -> cat<U> {
|
||||
pub fn cat<U>(in_x : uint, in_y : int, +in_info: ~[U]) -> cat<U> {
|
||||
cat {
|
||||
meows: in_x,
|
||||
how_hungry: in_y,
|
||||
|
@ -100,7 +100,7 @@ fn make_graph(N: uint, edges: ~[(node_id, node_id)]) -> graph {
|
||||
}
|
||||
}
|
||||
|
||||
fn gen_search_keys(graph: graph, n: uint) -> ~[node_id] {
|
||||
fn gen_search_keys(graph: &[~[node_id]], n: uint) -> ~[node_id] {
|
||||
let keys = oldmap::HashMap::<node_id, ()>();
|
||||
let r = rand::Rng();
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
|
||||
use core::cell::Cell;
|
||||
|
||||
fn child_generation(gens_left: uint, -c: comm::Chan<()>) {
|
||||
fn child_generation(gens_left: uint, c: comm::Chan<()>) {
|
||||
// This used to be O(n^2) in the number of generations that ever existed.
|
||||
// With this code, only as many generations are alive at a time as tasks
|
||||
// alive at a time,
|
||||
|
@ -10,10 +10,6 @@
|
||||
|
||||
fn take(_x: ~int) { }
|
||||
|
||||
fn from_by_value_arg(++x: ~int) {
|
||||
take(x); //~ ERROR illegal move from argument `x`, which is not copy or move mode
|
||||
}
|
||||
|
||||
fn from_by_ref_arg(&&x: ~int) {
|
||||
take(x); //~ ERROR illegal move from argument `x`, which is not copy or move mode
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn send<T:Owned>(ch: _chan<T>, -data: T) {
|
||||
fn send<T:Owned>(ch: _chan<T>, +data: T) {
|
||||
debug!(ch);
|
||||
debug!(data);
|
||||
fail!();
|
||||
|
@ -19,18 +19,13 @@ fn mutate_by_ref(&&x: uint) {
|
||||
x = 0; //~ ERROR assigning to argument
|
||||
}
|
||||
|
||||
fn mutate_by_val(++x: uint) {
|
||||
//~^ WARNING unused variable: `x`
|
||||
x = 0; //~ ERROR assigning to argument
|
||||
}
|
||||
|
||||
fn mutate_by_copy(+x: uint) {
|
||||
//~^ WARNING unused variable: `x`
|
||||
x = 0; //~ ERROR assigning to argument
|
||||
//~^ WARNING value assigned to `x` is never read
|
||||
}
|
||||
|
||||
fn mutate_by_move(-x: uint) {
|
||||
fn mutate_by_move(+x: uint) {
|
||||
//~^ WARNING unused variable: `x`
|
||||
x = 0; //~ ERROR assigning to argument
|
||||
//~^ WARNING value assigned to `x` is never read
|
||||
|
@ -9,7 +9,7 @@
|
||||
// except according to those terms.
|
||||
|
||||
// error-pattern:fail
|
||||
fn f(-_a: @int) {
|
||||
fn f(+_a: @int) {
|
||||
fail!();
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
struct X { x: int }
|
||||
|
||||
fn f1(a: &mut X, b: &mut int, -c: int) -> int {
|
||||
fn f1(a: &mut X, b: &mut int, +c: int) -> int {
|
||||
let r = a.x + *b + c;
|
||||
a.x = 0;
|
||||
*b = 10;
|
||||
|
@ -18,17 +18,9 @@ fn borrow_from_arg_mut_ref(v: &mut ~int) {
|
||||
borrow(*v);
|
||||
}
|
||||
|
||||
fn borrow_from_arg_move(-v: ~int) {
|
||||
borrow(v);
|
||||
}
|
||||
|
||||
fn borrow_from_arg_copy(+v: ~int) {
|
||||
borrow(v);
|
||||
}
|
||||
|
||||
fn borrow_from_arg_val(++v: ~int) {
|
||||
borrow(v);
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ pub impl<U> cat<U> {
|
||||
fn meow_count(&mut self) -> uint { self.meows }
|
||||
}
|
||||
|
||||
fn cat<U>(in_x : uint, in_y : int, -in_info: ~[U]) -> cat<U> {
|
||||
fn cat<U>(in_x : uint, in_y : int, +in_info: ~[U]) -> cat<U> {
|
||||
cat {
|
||||
meows: in_x,
|
||||
how_hungry: in_y,
|
||||
|
31
src/test/run-pass/extern-pass-TwoU64s-ref.rs
Normal file
31
src/test/run-pass/extern-pass-TwoU64s-ref.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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 that we ignore modes when calling extern functions.
|
||||
|
||||
// xfail-test --- broken on 32-bit ABIs! (#5347)
|
||||
|
||||
#[deriving_eq]
|
||||
struct TwoU64s {
|
||||
one: u64, two: u64
|
||||
}
|
||||
|
||||
pub extern {
|
||||
pub fn rust_dbg_extern_identity_TwoU64s(&&u: TwoU64s) -> TwoU64s;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
let x = TwoU64s {one: 22, two: 23};
|
||||
let y = rust_dbg_extern_identity_TwoU64s(x);
|
||||
fail_unless!(x == y);
|
||||
}
|
||||
}
|
||||
|
32
src/test/run-pass/extern-pass-TwoU64s.rs
Normal file
32
src/test/run-pass/extern-pass-TwoU64s.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// 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 a foreign function that accepts and returns a struct
|
||||
// by value.
|
||||
|
||||
// xfail-test --- broken on 32-bit ABIs! (#5347)
|
||||
|
||||
#[deriving_eq]
|
||||
struct TwoU64s {
|
||||
one: u64, two: u64
|
||||
}
|
||||
|
||||
pub extern {
|
||||
pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
let x = TwoU64s {one: 22, two: 23};
|
||||
let y = rust_dbg_extern_identity_TwoU64s(x);
|
||||
fail_unless!(x == y);
|
||||
}
|
||||
}
|
||||
|
22
src/test/run-pass/extern-pass-char.rs
Normal file
22
src/test/run-pass/extern-pass-char.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// 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 a function that takes/returns a u8.
|
||||
|
||||
pub extern {
|
||||
pub fn rust_dbg_extern_identity_u8(v: u8) -> u8;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
fail_unless!(22_u8 == rust_dbg_extern_identity_u8(22_u8));
|
||||
}
|
||||
}
|
||||
|
20
src/test/run-pass/extern-pass-double.rs
Normal file
20
src/test/run-pass/extern-pass-double.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.
|
||||
|
||||
pub extern {
|
||||
pub fn rust_dbg_extern_identity_double(v: f64) -> f64;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
fail_unless!(22.0_f64 == rust_dbg_extern_identity_double(22.0_f64));
|
||||
}
|
||||
}
|
||||
|
22
src/test/run-pass/extern-pass-u32.rs
Normal file
22
src/test/run-pass/extern-pass-u32.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// 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 a function that takes/returns a u32.
|
||||
|
||||
pub extern {
|
||||
pub fn rust_dbg_extern_identity_u32(v: u32) -> u32;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
fail_unless!(22_u32 == rust_dbg_extern_identity_u32(22_u32));
|
||||
}
|
||||
}
|
||||
|
22
src/test/run-pass/extern-pass-u64.rs
Normal file
22
src/test/run-pass/extern-pass-u64.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// 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 a call to a function that takes/returns a u64.
|
||||
|
||||
pub extern {
|
||||
pub fn rust_dbg_extern_identity_u64(v: u64) -> u64;
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
fail_unless!(22_u64 == rust_dbg_extern_identity_u64(22_u64));
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,8 @@
|
||||
mod rusti {
|
||||
#[abi = "rust-intrinsic"]
|
||||
pub extern {
|
||||
pub fn move_val_init<T>(dst: &mut T, -src: T);
|
||||
pub fn move_val<T>(dst: &mut T, -src: T);
|
||||
pub fn move_val_init<T>(dst: &mut T, +src: T);
|
||||
pub fn move_val<T>(dst: &mut T, +src: T);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ pub mod pipes {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send<T:Owned>(mut p: send_packet<T>, -payload: T) {
|
||||
pub fn send<T:Owned>(mut p: send_packet<T>, +payload: T) {
|
||||
let mut p = p.unwrap();
|
||||
let mut p = unsafe { uniquify(p) };
|
||||
fail_unless!((*p).payload.is_none());
|
||||
@ -228,7 +228,7 @@ pub mod pingpong {
|
||||
pub struct ping(::pipes::send_packet<pong>);
|
||||
pub struct pong(::pipes::send_packet<ping>);
|
||||
|
||||
pub fn liberate_ping(-p: ping) -> ::pipes::send_packet<pong> {
|
||||
pub fn liberate_ping(+p: ping) -> ::pipes::send_packet<pong> {
|
||||
unsafe {
|
||||
let addr : *::pipes::send_packet<pong> = match &p {
|
||||
&ping(ref x) => { cast::transmute(ptr::addr_of(x)) }
|
||||
@ -239,7 +239,7 @@ pub mod pingpong {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn liberate_pong(-p: pong) -> ::pipes::send_packet<ping> {
|
||||
pub fn liberate_pong(+p: pong) -> ::pipes::send_packet<ping> {
|
||||
unsafe {
|
||||
let addr : *::pipes::send_packet<ping> = match &p {
|
||||
&pong(ref x) => { cast::transmute(ptr::addr_of(x)) }
|
||||
@ -261,14 +261,14 @@ pub mod pingpong {
|
||||
pub type ping = ::pipes::send_packet<pingpong::ping>;
|
||||
pub type pong = ::pipes::recv_packet<pingpong::pong>;
|
||||
|
||||
pub fn do_ping(-c: ping) -> pong {
|
||||
pub fn do_ping(+c: ping) -> pong {
|
||||
let (sp, rp) = ::pipes::entangle();
|
||||
|
||||
::pipes::send(c, pingpong::ping(sp));
|
||||
rp
|
||||
}
|
||||
|
||||
pub fn do_pong(-c: pong) -> (ping, ()) {
|
||||
pub fn do_pong(+c: pong) -> (ping, ()) {
|
||||
let packet = ::pipes::recv(c);
|
||||
if packet.is_none() {
|
||||
fail!(~"sender closed the connection")
|
||||
@ -283,7 +283,7 @@ pub mod pingpong {
|
||||
pub type ping = ::pipes::recv_packet<pingpong::ping>;
|
||||
pub type pong = ::pipes::send_packet<pingpong::pong>;
|
||||
|
||||
pub fn do_ping(-c: ping) -> (pong, ()) {
|
||||
pub fn do_ping(+c: ping) -> (pong, ()) {
|
||||
let packet = ::pipes::recv(c);
|
||||
if packet.is_none() {
|
||||
fail!(~"sender closed the connection")
|
||||
@ -291,7 +291,7 @@ pub mod pingpong {
|
||||
(pingpong::liberate_ping(option::unwrap(packet)), ())
|
||||
}
|
||||
|
||||
pub fn do_pong(-c: pong) -> ping {
|
||||
pub fn do_pong(+c: pong) -> ping {
|
||||
let (sp, rp) = ::pipes::entangle();
|
||||
::pipes::send(c, pingpong::pong(sp));
|
||||
rp
|
||||
@ -299,14 +299,14 @@ pub mod pingpong {
|
||||
}
|
||||
}
|
||||
|
||||
fn client(-chan: pingpong::client::ping) {
|
||||
fn client(+chan: pingpong::client::ping) {
|
||||
let chan = pingpong::client::do_ping(chan);
|
||||
error!(~"Sent ping");
|
||||
let (_chan, _data) = pingpong::client::do_pong(chan);
|
||||
error!(~"Received pong");
|
||||
}
|
||||
|
||||
fn server(-chan: pingpong::server::ping) {
|
||||
fn server(+chan: pingpong::server::ping) {
|
||||
let (chan, _data) = pingpong::server::do_ping(chan);
|
||||
error!(~"Received ping");
|
||||
let _chan = pingpong::server::do_pong(chan);
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn take(-x: int) -> int {x}
|
||||
fn take(+x: int) -> int {x}
|
||||
|
||||
fn the_loop() {
|
||||
let mut list = ~[];
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn test(-foo: ~~[int]) { fail_unless!((foo[0] == 10)); }
|
||||
fn test(+foo: ~~[int]) { fail_unless!((foo[0] == 10)); }
|
||||
|
||||
pub fn main() {
|
||||
let x = ~~[10];
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn test(-foo: @~[int]) { fail_unless!((foo[0] == 10)); }
|
||||
fn test(+foo: @~[int]) { fail_unless!((foo[0] == 10)); }
|
||||
|
||||
pub fn main() {
|
||||
let x = @~[10];
|
||||
|
@ -8,6 +8,6 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn test(-foo: int) { fail_unless!((foo == 10)); }
|
||||
fn test(+foo: int) { fail_unless!((foo == 10)); }
|
||||
|
||||
pub fn main() { let x = 10; test(x); }
|
||||
|
@ -9,9 +9,9 @@
|
||||
// except according to those terms.
|
||||
|
||||
// Issue #922
|
||||
fn f2(-thing: @fn()) { }
|
||||
fn f2(+thing: @fn()) { }
|
||||
|
||||
fn f(-thing: @fn()) {
|
||||
fn f(+thing: @fn()) {
|
||||
f2(thing);
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ fn switch<T:Owned,U>(+endp: pipes::RecvPacket<T>,
|
||||
f(pipes::try_recv(endp))
|
||||
}
|
||||
|
||||
fn move_it<T>(-x: T) -> T { x }
|
||||
fn move_it<T>(+x: T) -> T { x }
|
||||
|
||||
macro_rules! follow (
|
||||
{
|
||||
|
@ -91,7 +91,7 @@ mod test {
|
||||
use core::pipes::recv;
|
||||
use pingpong::{ping, pong};
|
||||
|
||||
pub fn client(-chan: ::pingpong::client::ping) {
|
||||
pub fn client(+chan: ::pingpong::client::ping) {
|
||||
use pingpong::client;
|
||||
|
||||
let chan = client::ping(chan); return;
|
||||
@ -100,7 +100,7 @@ mod test {
|
||||
error!("Received pong");
|
||||
}
|
||||
|
||||
pub fn server(-chan: ::pingpong::server::ping) {
|
||||
pub fn server(+chan: ::pingpong::server::ping) {
|
||||
use pingpong::server;
|
||||
|
||||
let ping(chan) = recv(chan); return;
|
||||
|
@ -29,7 +29,7 @@ mod test {
|
||||
use core::pipes::recv;
|
||||
use pingpong::{ping, pong};
|
||||
|
||||
pub fn client(-chan: ::pingpong::client::ping) {
|
||||
pub fn client(+chan: ::pingpong::client::ping) {
|
||||
use pingpong::client;
|
||||
|
||||
let chan = client::ping(chan);
|
||||
@ -38,7 +38,7 @@ mod test {
|
||||
error!(~"Received pong");
|
||||
}
|
||||
|
||||
pub fn server(-chan: ::pingpong::server::ping) {
|
||||
pub fn server(+chan: ::pingpong::server::ping) {
|
||||
use pingpong::server;
|
||||
|
||||
let ping(chan) = recv(chan);
|
||||
|
@ -8,7 +8,7 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
fn f(-i: ~int) {
|
||||
fn f(+i: ~int) {
|
||||
fail_unless!(*i == 100);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user