introduce an owned kind for data that contains no borrowed ptrs

This commit is contained in:
Niko Matsakis 2012-07-16 20:17:57 -07:00
parent d809336d0f
commit 0e42004bab
25 changed files with 245 additions and 142 deletions

View file

@ -62,6 +62,7 @@ enum ty_param_bound {
bound_copy,
bound_send,
bound_const,
bound_owned,
bound_trait(@ty),
}

View file

@ -135,7 +135,7 @@ fn fold_fn_decl(decl: ast::fn_decl, fld: ast_fold) -> ast::fn_decl {
fn fold_ty_param_bound(tpb: ty_param_bound, fld: ast_fold) -> ty_param_bound {
alt tpb {
bound_copy | bound_send | bound_const { tpb }
bound_copy | bound_send | bound_const | bound_owned { tpb }
bound_trait(ty) { bound_trait(fld.fold_ty(ty)) }
}
}

View file

@ -16,7 +16,8 @@ import dvec::{dvec, extensions};
import vec::{push};
import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
bitand, bitor, bitxor, blk, blk_check_mode, bound_const,
bound_copy, bound_send, bound_trait, box, by_copy, by_move,
bound_copy, bound_send, bound_trait, bound_owned,
box, by_copy, by_move,
by_mutbl_ref, by_ref, by_val, capture_clause, capture_item,
carg_base, carg_ident, cdir_dir_mod, cdir_src_mod,
cdir_view_item, checked_expr, claimed_expr, class_immutable,
@ -1935,12 +1936,16 @@ class parser {
let ident = self.parse_ident();
if self.eat(token::COLON) {
while self.token != token::COMMA && self.token != token::GT {
if self.eat_keyword(~"send") { push(bounds, bound_send); }
else if self.eat_keyword(~"copy") { push(bounds, bound_copy) }
if self.eat_keyword(~"send") {
push(bounds, bound_send); }
else if self.eat_keyword(~"copy") {
push(bounds, bound_copy) }
else if self.eat_keyword(~"const") {
push(bounds, bound_const)
}
else { push(bounds, bound_trait(self.parse_ty(false))); }
push(bounds, bound_const);
} else if self.eat_keyword(~"owned") {
push(bounds, bound_owned);
} else {
push(bounds, bound_trait(self.parse_ty(false))); }
}
}
ret {ident: ident, id: self.get_id(), bounds: @bounds};

View file

@ -313,7 +313,7 @@ fn restricted_keyword_table() -> hashmap<~str, ()> {
~"if", ~"iface", ~"impl", ~"import",
~"let", ~"log", ~"loop",
~"mod", ~"mut",
~"new",
~"new", ~"owned",
~"pure", ~"ret",
~"true", ~"trait", ~"type",
~"unchecked", ~"unsafe",

View file

@ -1377,6 +1377,7 @@ fn print_bounds(s: ps, bounds: @~[ast::ty_param_bound]) {
ast::bound_copy { word(s.s, ~"copy"); }
ast::bound_send { word(s.s, ~"send"); }
ast::bound_const { word(s.s, ~"const"); }
ast::bound_owned { word(s.s, ~"owned"); }
ast::bound_trait(t) { print_type(s, t); }
}
}

View file

@ -246,7 +246,7 @@ fn visit_ty_params<E>(tps: ~[ty_param], e: E, v: vt<E>) {
for vec::each(*tp.bounds) |bound| {
alt bound {
bound_trait(t) { v.visit_ty(t, e, v); }
bound_copy | bound_send | bound_const { }
bound_copy | bound_send | bound_const | bound_owned { }
}
}
}

View file

@ -417,6 +417,7 @@ fn parse_bounds(st: @pstate, conv: conv_did) -> @~[ty::param_bound] {
'S' { ty::bound_send }
'C' { ty::bound_copy }
'K' { ty::bound_const }
'O' { ty::bound_owned }
'I' { ty::bound_trait(parse_ty(st, conv)) }
'.' { break; }
});

View file

@ -350,6 +350,7 @@ fn enc_bounds(w: io::writer, cx: @ctxt, bs: @~[ty::param_bound]) {
ty::bound_send { w.write_char('S'); }
ty::bound_copy { w.write_char('C'); }
ty::bound_const { w.write_char('K'); }
ty::bound_owned { w.write_char('O'); }
ty::bound_trait(tp) {
w.write_char('I');
enc_ty(w, cx, tp);

View file

@ -1,8 +1,7 @@
import syntax::{visit, ast_util};
import syntax::ast::*;
import syntax::codemap::span;
import ty::{kind, kind_sendable, kind_copyable, kind_noncopyable, kind_const,
operators};
import ty::{kind, kind_copyable, kind_noncopyable, kind_const, operators};
import driver::session::session;
import std::map::hashmap;
import util::ppaux::{ty_to_str, tys_to_str};
@ -21,6 +20,7 @@ import lint::{non_implicitly_copyable_typarams,implicit_copies};
// copy: Things that can be copied.
// const: Things thare are deeply immutable. They are guaranteed never to
// change, and can be safely shared without copying between tasks.
// owned: Things that do not contain borrowed pointers.
//
// Send includes scalar types as well as classes and unique types containing
// only sendable types.
@ -41,15 +41,21 @@ import lint::{non_implicitly_copyable_typarams,implicit_copies};
fn kind_to_str(k: kind) -> ~str {
let mut kinds = ~[];
if ty::kind_lteq(kind_const(), k) {
vec::push(kinds, ~"const");
}
if ty::kind_can_be_copied(k) {
vec::push(kinds, ~"copy");
}
if ty::kind_can_be_sent(k) {
vec::push(kinds, ~"send");
} else if ty::kind_is_owned(k) {
vec::push(kinds, ~"owned");
}
str::connect(kinds, ~" ")
}
@ -93,8 +99,8 @@ fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
fn check_for_uniq(cx: ctx, id: node_id, fv: option<@freevar_entry>,
is_move: bool, var_t: ty::t, sp: span) {
// all captured data must be sendable, regardless of whether it is
// moved in or copied in
check_send(cx, var_t, sp);
// moved in or copied in. Note that send implies owned.
if !check_send(cx, var_t, sp) { ret; }
// copied in data must be copyable, but moved in data can be anything
let is_implicit = fv.is_some();
@ -108,6 +114,9 @@ fn with_appropriate_checker(cx: ctx, id: node_id, b: fn(check_fn)) {
fn check_for_box(cx: ctx, id: node_id, fv: option<@freevar_entry>,
is_move: bool, var_t: ty::t, sp: span) {
// all captured data must be owned
if !check_owned(cx, var_t, sp) { ret; }
// copied in data must be copyable, but moved in data can be anything
let is_implicit = fv.is_some();
if !is_move { check_copy(cx, id, var_t, sp, is_implicit); }
@ -422,9 +431,21 @@ fn check_copy(cx: ctx, id: node_id, ty: ty::t, sp: span,
}
}
fn check_send(cx: ctx, ty: ty::t, sp: span) {
fn check_send(cx: ctx, ty: ty::t, sp: span) -> bool {
if !ty::kind_can_be_sent(ty::type_kind(cx.tcx, ty)) {
cx.tcx.sess.span_err(sp, ~"not a sendable value");
false
} else {
true
}
}
fn check_owned(cx: ctx, ty: ty::t, sp: span) -> bool {
if !ty::kind_is_owned(ty::type_kind(cx.tcx, ty)) {
cx.tcx.sess.span_err(sp, ~"not an owned value");
false
} else {
true
}
}

View file

@ -4,6 +4,7 @@ import metadata::cstore::find_use_stmt_cnum;
import metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
import middle::lint::{error, ignore, level, unused_imports, warn};
import syntax::ast::{_mod, arm, blk, bound_const, bound_copy, bound_trait};
import syntax::ast::{bound_owned};
import syntax::ast::{bound_send, capture_clause, class_ctor, class_dtor};
import syntax::ast::{class_member, class_method, crate, crate_num, decl_item};
import syntax::ast::{def, def_arg, def_binding, def_class, def_const, def_fn};
@ -3181,7 +3182,7 @@ class Resolver {
for type_parameters.each |type_parameter| {
for (*type_parameter.bounds).each |bound| {
alt bound {
bound_copy | bound_send | bound_const {
bound_copy | bound_send | bound_const | bound_owned {
// Nothing to do.
}
bound_trait(interface_type) {

View file

@ -1373,23 +1373,23 @@ fn move_val(cx: block, action: copy_action, dst: ValueRef,
let tcx = cx.tcx();
let mut cx = cx;
if ty::type_is_scalar(t) {
if src.kind == owned { src_val = Load(cx, src_val); }
if src.kind == lv_owned { src_val = Load(cx, src_val); }
Store(cx, src_val, dst);
ret cx;
} else if ty::type_is_nil(t) || ty::type_is_bot(t) {
ret cx;
} else if ty::type_is_boxed(t) || ty::type_is_unique(t) {
if src.kind == owned { src_val = Load(cx, src_val); }
if src.kind == lv_owned { src_val = Load(cx, src_val); }
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
Store(cx, src_val, dst);
if src.kind == owned { ret zero_mem(cx, src.val, t); }
if src.kind == lv_owned { ret zero_mem(cx, src.val, t); }
// If we're here, it must be a temporary.
revoke_clean(cx, src_val);
ret cx;
} else if type_is_structural_or_param(t) {
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
memmove_ty(cx, dst, src_val, t);
if src.kind == owned { ret zero_mem(cx, src_val, t); }
if src.kind == lv_owned { ret zero_mem(cx, src_val, t); }
// If we're here, it must be a temporary.
revoke_clean(cx, src_val);
ret cx;
@ -1403,8 +1403,8 @@ fn store_temp_expr(cx: block, action: copy_action, dst: ValueRef,
-> block {
let _icx = cx.insn_ctxt(~"trans_temp_expr");
// Lvals in memory are not temporaries. Copy them.
if src.kind != temporary && !last_use {
let v = if src.kind == owned {
if src.kind != lv_temporary && !last_use {
let v = if src.kind == lv_owned {
load_if_immediate(cx, src.val, t)
} else {
src.val
@ -1518,7 +1518,7 @@ fn trans_addr_of(cx: block, e: @ast::expr, dest: dest) -> block {
let mut {bcx, val, kind} = trans_temp_lval(cx, e);
let ety = expr_ty(cx, e);
let is_immediate = ty::type_is_immediate(ety);
if (kind == temporary && is_immediate) || kind == owned_imm {
if (kind == lv_temporary && is_immediate) || kind == lv_owned_imm {
val = do_spill(bcx, val, ety);
}
ret store_in_dest(bcx, val, dest);
@ -1696,7 +1696,7 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
let _icx = bcx.insn_ctxt(~"trans_assign_op");
let t = expr_ty(bcx, src);
let lhs_res = trans_lval(bcx, dst);
assert (lhs_res.kind == owned);
assert (lhs_res.kind == lv_owned);
// A user-defined operator method
alt bcx.ccx().maps.method_map.find(ex.id) {
@ -1720,7 +1720,7 @@ fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
arg_exprs(~[src]), save_in(target));
ret move_val(bcx, DROP_EXISTING, lhs_res.val,
{bcx: bcx, val: target, kind: owned},
{bcx: bcx, val: target, kind: lv_owned},
dty);
}
_ {}
@ -1947,9 +1947,9 @@ fn trans_loop(cx:block, body: ast::blk) -> block {
}
enum lval_kind {
temporary, //< Temporary value passed by value if of immediate type
owned, //< Non-temporary value passed by pointer
owned_imm, //< Non-temporary value passed by value
lv_temporary, //< Temporary value passed by value if of immediate type
lv_owned, //< Non-temporary value passed by pointer
lv_owned_imm, //< Non-temporary value passed by value
}
type local_var_result = {val: ValueRef, kind: lval_kind};
type lval_result = {bcx: block, val: ValueRef, kind: lval_kind};
@ -1972,10 +1972,10 @@ fn lval_from_local_var(bcx: block, r: local_var_result) -> lval_result {
}
fn lval_owned(bcx: block, val: ValueRef) -> lval_result {
ret {bcx: bcx, val: val, kind: owned};
ret {bcx: bcx, val: val, kind: lv_owned};
}
fn lval_temp(bcx: block, val: ValueRef) -> lval_result {
ret {bcx: bcx, val: val, kind: temporary};
ret {bcx: bcx, val: val, kind: lv_temporary};
}
fn lval_no_env(bcx: block, val: ValueRef, kind: lval_kind)
@ -2355,7 +2355,7 @@ fn lval_static_fn_inner(bcx: block, fn_id: ast::def_id, id: ast::node_id,
val = PointerCast(bcx, val, T_ptr(type_of_fn_from_ty(
ccx, node_id_type(bcx, id))));
}
ret {bcx: bcx, val: val, kind: owned, env: null_env};
ret {bcx: bcx, val: val, kind: lv_owned, env: null_env};
}
let mut val = if fn_id.crate == ast::local_crate {
@ -2376,7 +2376,7 @@ fn lval_static_fn_inner(bcx: block, fn_id: ast::def_id, id: ast::node_id,
ast::extern_fn {
// Extern functions are just opaque pointers
let val = PointerCast(bcx, val, T_ptr(T_i8()));
ret lval_no_env(bcx, val, owned_imm);
ret lval_no_env(bcx, val, lv_owned_imm);
}
_ { /* fall through */ }
}
@ -2384,7 +2384,7 @@ fn lval_static_fn_inner(bcx: block, fn_id: ast::def_id, id: ast::node_id,
_ { /* fall through */ }
}
ret {bcx: bcx, val: val, kind: owned, env: null_env};
ret {bcx: bcx, val: val, kind: lv_owned, env: null_env};
}
fn lookup_discriminant(ccx: @crate_ctxt, vid: ast::def_id) -> ValueRef {
@ -2415,15 +2415,15 @@ fn trans_local_var(cx: block, def: ast::def) -> local_var_result {
fn take_local(table: hashmap<ast::node_id, local_val>,
id: ast::node_id) -> local_var_result {
alt table.find(id) {
some(local_mem(v)) { {val: v, kind: owned} }
some(local_imm(v)) { {val: v, kind: owned_imm} }
some(local_mem(v)) { {val: v, kind: lv_owned} }
some(local_imm(v)) { {val: v, kind: lv_owned_imm} }
r { fail(~"take_local: internal error"); }
}
}
alt def {
ast::def_upvar(nid, _, _) {
assert (cx.fcx.llupvars.contains_key(nid));
ret { val: cx.fcx.llupvars.get(nid), kind: owned };
ret { val: cx.fcx.llupvars.get(nid), kind: lv_owned };
}
ast::def_arg(nid, _) {
assert (cx.fcx.llargs.contains_key(nid));
@ -2439,7 +2439,7 @@ fn trans_local_var(cx: block, def: ast::def) -> local_var_result {
none { cx.sess().bug(~"trans_local_var: reference to self \
out of context"); }
};
ret {val: slf, kind: owned};
ret {val: slf, kind: lv_owned};
}
_ {
cx.sess().unimpl(#fmt("unsupported def type in trans_local_def: %?",
@ -2478,16 +2478,17 @@ fn trans_var(cx: block, def: ast::def, id: ast::node_id)-> lval_maybe_callee {
let lldiscrim_gv = lookup_discriminant(ccx, vid);
let lldiscrim = Load(cx, lldiscrim_gv);
Store(cx, lldiscrim, lldiscrimptr);
ret lval_no_env(cx, llenumptr, temporary);
ret lval_no_env(cx, llenumptr, lv_temporary);
}
}
ast::def_const(did) {
if did.crate == ast::local_crate {
ret lval_no_env(cx, get_item_val(ccx, did.node), owned);
ret lval_no_env(cx, get_item_val(ccx, did.node), lv_owned);
} else {
let tp = node_id_type(cx, id);
let val = trans_external_path(ccx, did, tp);
ret lval_no_env(cx, load_if_immediate(cx, val, tp), owned_imm);
ret lval_no_env(cx, load_if_immediate(cx, val, tp),
lv_owned_imm);
}
}
_ {
@ -2538,7 +2539,7 @@ fn trans_rec_field_inner(bcx: block, val: ValueRef, ty: ty::t,
}
else { GEPi(bcx, val, ~[0u, ix]) };
ret {bcx: bcx, val: val, kind: owned};
ret {bcx: bcx, val: val, kind: lv_owned};
}
@ -2717,7 +2718,7 @@ fn lval_maybe_callee_to_lval(c: lval_maybe_callee, sp: span) -> lval_result {
let llfnty = llvm::LLVMGetElementType(val_ty(c.val));
let llfn = create_real_fn_pair(c.bcx, llfnty, c.val,
null_env_ptr(c.bcx));
{bcx: c.bcx, val: llfn, kind: temporary}
{bcx: c.bcx, val: llfn, kind: lv_temporary}
}
}
}
@ -2863,7 +2864,7 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
ast::expr_loop_body(blk) {
let scratch = alloc_ty(cx, expr_ty(cx, blk));
let bcx = trans_loop_body(cx, e, ret_flag, save_in(scratch));
{bcx: bcx, val: scratch, kind: temporary}
{bcx: bcx, val: scratch, kind: lv_temporary}
}
}
}
@ -2881,7 +2882,7 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
let {bcx, val} = lval_result_to_result(lv, e_ty);
let {bcx, val, ty: e_ty} =
autoderef(bcx, e.id, val, e_ty, derefs);
{lv: {bcx: bcx, val: val, kind: temporary},
{lv: {bcx: bcx, val: val, kind: lv_temporary},
e_ty: e_ty}
};
@ -2904,14 +2905,14 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
alt arg_mode {
ast::by_ref | ast::by_mutbl_ref {
// Ensure that the value is spilled into memory:
if lv.kind != owned && ty::type_is_immediate(e_ty) {
if lv.kind != lv_owned && ty::type_is_immediate(e_ty) {
val = do_spill_noroot(bcx, val);
}
}
ast::by_val {
// Ensure that the value is not spilled into memory:
if lv.kind == owned || !ty::type_is_immediate(e_ty) {
if lv.kind == lv_owned || !ty::type_is_immediate(e_ty) {
val = Load(bcx, val);
}
}
@ -2921,15 +2922,15 @@ fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
let alloc = alloc_ty(bcx, arg.ty);
let move_out = arg_mode == ast::by_move ||
ccx.maps.last_use_map.contains_key(e.id);
if lv.kind == temporary { revoke_clean(bcx, val); }
if lv.kind == owned || !ty::type_is_immediate(arg.ty) {
if lv.kind == lv_temporary { revoke_clean(bcx, val); }
if lv.kind == lv_owned || !ty::type_is_immediate(arg.ty) {
memmove_ty(bcx, alloc, val, arg.ty);
if move_out && ty::type_needs_drop(ccx.tcx, arg.ty) {
bcx = zero_mem(bcx, val, arg.ty);
}
} else { Store(bcx, val, alloc); }
val = alloc;
if lv.kind != temporary && !move_out {
if lv.kind != lv_temporary && !move_out {
bcx = take_ty(bcx, val, arg.ty);
}
@ -2977,9 +2978,9 @@ fn adapt_borrowed_value(lv: lval_result,
ty::ty_estr(_) | ty::ty_evec(_, _) {
let ccx = bcx.ccx();
let val = alt lv.kind {
temporary { lv.val }
owned { load_if_immediate(bcx, lv.val, e_ty) }
owned_imm { lv.val }
lv_temporary { lv.val }
lv_owned { load_if_immediate(bcx, lv.val, e_ty) }
lv_owned_imm { lv.val }
};
let unit_ty = ty::sequence_element_type(ccx.tcx, e_ty);
@ -3150,7 +3151,7 @@ fn trans_call_inner(
}
is_closure {
// It's a closure. Have to fetch the elements
if f_res.kind == owned {
if f_res.kind == lv_owned {
faddr = load_if_immediate(bcx, faddr, fn_expr_ty);
}
let pair = faddr;
@ -3418,17 +3419,17 @@ fn trans_temp_lval(bcx: block, e: @ast::expr) -> lval_result {
let ty = expr_ty(bcx, e);
if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
bcx = trans_expr(bcx, e, ignore);
ret {bcx: bcx, val: C_nil(), kind: temporary};
ret {bcx: bcx, val: C_nil(), kind: lv_temporary};
} else if ty::type_is_immediate(ty) {
let cell = empty_dest_cell();
bcx = trans_expr(bcx, e, by_val(cell));
add_clean_temp(bcx, *cell, ty);
ret {bcx: bcx, val: *cell, kind: temporary};
ret {bcx: bcx, val: *cell, kind: lv_temporary};
} else {
let scratch = alloc_ty(bcx, ty);
let bcx = trans_expr_save_in(bcx, e, scratch);
add_clean_temp(bcx, scratch, ty);
ret {bcx: bcx, val: scratch, kind: temporary};
ret {bcx: bcx, val: scratch, kind: lv_temporary};
}
}
}
@ -3442,9 +3443,9 @@ fn trans_temp_expr(bcx: block, e: @ast::expr) -> result {
fn load_value_from_lval_result(lv: lval_result, ty: ty::t) -> ValueRef {
alt lv.kind {
temporary { lv.val }
owned { load_if_immediate(lv.bcx, lv.val, ty) }
owned_imm { lv.val }
lv_temporary { lv.val }
lv_owned { load_if_immediate(lv.bcx, lv.val, ty) }
lv_owned_imm { lv.val }
}
}
@ -3521,7 +3522,7 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
let _icx = bcx.insn_ctxt(~"root_value_expr");
add_root_cleanup(bcx, scope_id, root_loc, ty);
let lv = {bcx: bcx, val: root_loc, kind: owned};
let lv = {bcx: bcx, val: root_loc, kind: lv_owned};
lval_result_to_dps(lv, ty, false, dest)
}
};
@ -3647,7 +3648,7 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
assert dest == ignore;
let src_r = trans_temp_lval(bcx, src);
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
assert kind == owned;
assert kind == lv_owned;
let is_last_use =
bcx.ccx().maps.last_use_map.contains_key(src.id);
ret store_temp_expr(bcx, DROP_EXISTING, addr, src_r,
@ -3658,14 +3659,14 @@ fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
assert dest == ignore;
let src_r = trans_temp_lval(bcx, src);
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
assert kind == owned;
assert kind == lv_owned;
ret move_val(bcx, DROP_EXISTING, addr, src_r,
expr_ty(bcx, src));
}
ast::expr_swap(dst, src) {
assert dest == ignore;
let lhs_res = trans_lval(bcx, dst);
assert lhs_res.kind == owned;
assert lhs_res.kind == lv_owned;
let rhs_res = trans_lval(lhs_res.bcx, src);
let t = expr_ty(bcx, src);
let tmp_alloc = alloc_ty(rhs_res.bcx, t);
@ -3728,7 +3729,7 @@ fn lval_to_dps(bcx: block, e: @ast::expr, dest: dest) -> block {
let last_use_map = bcx.ccx().maps.last_use_map;
let ty = expr_ty(bcx, e);
let lv = trans_lval(bcx, e);
let last_use = (lv.kind == owned && last_use_map.contains_key(e.id));
let last_use = (lv.kind == lv_owned && last_use_map.contains_key(e.id));
#debug["is last use (%s) = %b, %d", expr_to_str(e), last_use,
lv.kind as int];
lval_result_to_dps(lv, ty, last_use, dest)
@ -3740,7 +3741,7 @@ fn lval_result_to_dps(lv: lval_result, ty: ty::t,
let ccx = bcx.ccx();
alt dest {
by_val(cell) {
if kind == temporary {
if kind == lv_temporary {
revoke_clean(bcx, val);
*cell = val;
} else if last_use {
@ -3749,7 +3750,7 @@ fn lval_result_to_dps(lv: lval_result, ty: ty::t,
bcx = zero_mem(bcx, val, ty);
}
} else {
if kind == owned { val = Load(bcx, val); }
if kind == lv_owned { val = Load(bcx, val); }
let {bcx: cx, val} = take_ty_immediate(bcx, val, ty);
*cell = val;
bcx = cx;
@ -4788,7 +4789,7 @@ fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
// Translate the body of the ctor
bcx = trans_block(bcx_top, body, ignore);
let lval_res = {bcx: bcx, val: selfptr, kind: owned};
let lval_res = {bcx: bcx, val: selfptr, kind: lv_owned};
// Generate the return expression
bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res,
rslt_ty, true);

View file

@ -216,31 +216,31 @@ fn store_environment(bcx: block,
let bound_data = GEPi(bcx, llbox,
~[0u, abi::box_field_body, i]);
alt bv {
env_copy(val, ty, owned) {
env_copy(val, ty, lv_owned) {
let val1 = load_if_immediate(bcx, val, ty);
bcx = base::copy_val(bcx, INIT, bound_data, val1, ty);
}
env_copy(val, ty, owned_imm) {
env_copy(val, ty, lv_owned_imm) {
bcx = base::copy_val(bcx, INIT, bound_data, val, ty);
}
env_copy(_, _, temporary) {
env_copy(_, _, lv_temporary) {
fail ~"cannot capture temporary upvar";
}
env_move(val, ty, kind) {
let src = {bcx:bcx, val:val, kind:kind};
bcx = move_val(bcx, INIT, bound_data, src, ty);
}
env_ref(val, ty, owned) {
env_ref(val, ty, lv_owned) {
#debug["> storing %s into %s",
val_str(bcx.ccx().tn, val),
val_str(bcx.ccx().tn, bound_data)];
Store(bcx, val, bound_data);
}
env_ref(val, ty, owned_imm) {
env_ref(val, ty, lv_owned_imm) {
let addr = do_spill_noroot(bcx, val);
Store(bcx, addr, bound_data);
}
env_ref(_, _, temporary) {
env_ref(_, _, lv_temporary) {
fail ~"cannot capture temporary upvar";
}
}
@ -289,7 +289,7 @@ fn build_closure(bcx0: block,
vec::push(env_vals, env_move(lv.val, ty, lv.kind));
}
capture::cap_drop {
assert lv.kind == owned;
assert lv.kind == lv_owned;
bcx = drop_ty(bcx, lv.val, ty);
bcx = zero_mem(bcx, lv.val, ty);
}
@ -303,9 +303,9 @@ fn build_closure(bcx0: block,
let nil_ret = PointerCast(bcx, our_ret, T_ptr(T_nil()));
vec::push(env_vals,
env_ref(flagptr,
ty::mk_mut_ptr(tcx, ty::mk_bool(tcx)), owned));
ty::mk_mut_ptr(tcx, ty::mk_bool(tcx)), lv_owned));
vec::push(env_vals,
env_ref(nil_ret, ty::mk_nil_ptr(tcx), owned));
env_ref(nil_ret, ty::mk_nil_ptr(tcx), lv_owned));
}
ret store_environment(bcx, env_vals, ck);
}

View file

@ -881,7 +881,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
let tp_ty = substs.tys[0];
let src = {bcx: bcx,
val: get_param(decl, first_real_arg + 1u),
kind: owned };
kind: lv_owned};
bcx = move_val(bcx, DROP_EXISTING,
get_param(decl, first_real_arg),
src,
@ -891,7 +891,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
let tp_ty = substs.tys[0];
let src = {bcx: bcx,
val: get_param(decl, first_real_arg + 1u),
kind: owned };
kind: lv_owned};
bcx = move_val(bcx, INIT,
get_param(decl, first_real_arg),
src,
@ -982,7 +982,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
|bcx| lval_no_env(
bcx,
get_param(decl, first_real_arg),
temporary),
lv_temporary),
arg_vals(~[frameaddress_val]), ignore);
}
}

View file

@ -162,7 +162,7 @@ fn trans_trait_callee(bcx: block, val: ValueRef,
let vtable = PointerCast(bcx, vtable,
T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
let mptr = Load(bcx, GEPi(bcx, vtable, ~[0u, n_method]));
{bcx: bcx, val: mptr, kind: owned, env: env}
{bcx: bcx, val: mptr, kind: lv_owned, env: env}
}
fn find_vtable_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)

View file

@ -107,9 +107,10 @@ export tbox_has_flag;
export ty_var_id;
export ty_to_def_id;
export ty_fn_args;
export kind, kind_implicitly_copyable, kind_sendable, kind_copyable;
export kind, kind_implicitly_copyable, kind_send_copy, kind_copyable;
export kind_noncopyable, kind_const;
export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied;
export kind_is_owned;
export proto_kind, kind_lteq, type_kind;
export operators;
export type_err, terr_vstore_kind;
@ -144,7 +145,8 @@ export closure_kind;
export ck_block;
export ck_box;
export ck_uniq;
export param_bound, param_bounds, bound_copy, bound_send, bound_trait;
export param_bound, param_bounds, bound_copy, bound_owned;
export bound_send, bound_trait;
export param_bounds_to_kind;
export default_arg_mode_for_ty;
export item_path;
@ -409,6 +411,7 @@ enum type_err {
enum param_bound {
bound_copy,
bound_owned,
bound_send,
bound_const,
bound_trait(t),
@ -451,8 +454,15 @@ fn param_bounds_to_kind(bounds: param_bounds) -> kind {
bound_copy {
kind = raise_kind(kind, kind_implicitly_copyable());
}
bound_send { kind = raise_kind(kind, kind_send_only()); }
bound_const { kind = raise_kind(kind, kind_const()); }
bound_owned {
kind = raise_kind(kind, kind_owned());
}
bound_send {
kind = raise_kind(kind, kind_send_only() | kind_owned());
}
bound_const {
kind = raise_kind(kind, kind_const());
}
bound_trait(_) {}
}
}
@ -1303,11 +1313,20 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t,
enum kind { kind_(u32) }
// *ALL* implicitly copiable things must be copiable
const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001u32;
const KIND_MASK_SEND : u32 = 0b00000000000000000000000000000010u32;
const KIND_MASK_CONST : u32 = 0b00000000000000000000000000000100u32;
const KIND_MASK_IMPLICIT : u32 = 0b00000000000000000000000000001000u32;
/// can be copied (implicitly or explicitly)
const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001_u32;
/// can be sent: no shared box, borrowed ptr (must imply OWNED)
const KIND_MASK_SEND : u32 = 0b00000000000000000000000000000010_u32;
/// is owned (no borrowed ptrs)
const KIND_MASK_OWNED : u32 = 0b00000000000000000000000000000100_u32;
/// is deeply immutable
const KIND_MASK_CONST : u32 = 0b00000000000000000000000000001000_u32;
/// can be implicitly copied (must imply COPY)
const KIND_MASK_IMPLICIT : u32 = 0b00000000000000000000000000010000_u32;
fn kind_noncopyable() -> kind {
kind_(0u32)
@ -1325,7 +1344,7 @@ fn kind_implicitly_sendable() -> kind {
kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY | KIND_MASK_SEND)
}
fn kind_sendable() -> kind {
fn kind_send_copy() -> kind {
kind_(KIND_MASK_COPY | KIND_MASK_SEND)
}
@ -1337,6 +1356,10 @@ fn kind_const() -> kind {
kind_(KIND_MASK_CONST)
}
fn kind_owned() -> kind {
kind_(KIND_MASK_OWNED)
}
fn kind_top() -> kind {
kind_(0xffffffffu32)
}
@ -1349,6 +1372,14 @@ fn remove_implicit(k: kind) -> kind {
k - kind_(KIND_MASK_IMPLICIT)
}
fn remove_send(k: kind) -> kind {
k - kind_(KIND_MASK_SEND)
}
fn remove_owned_send(k: kind) -> kind {
k - kind_(KIND_MASK_OWNED) - kind_(KIND_MASK_SEND)
}
fn remove_copyable(k: kind) -> kind {
k - kind_(KIND_MASK_COPY)
}
@ -1371,24 +1402,29 @@ impl operators for kind {
// against the kind constants, as we may modify the kind hierarchy in the
// future.
pure fn kind_can_be_implicitly_copied(k: kind) -> bool {
*k & KIND_MASK_IMPLICIT != 0u32
*k & KIND_MASK_IMPLICIT == KIND_MASK_IMPLICIT
}
pure fn kind_can_be_copied(k: kind) -> bool {
*k & KIND_MASK_COPY != 0u32
*k & KIND_MASK_COPY == KIND_MASK_COPY
}
pure fn kind_can_be_sent(k: kind) -> bool {
*k & KIND_MASK_SEND != 0u32
*k & KIND_MASK_SEND == KIND_MASK_SEND
}
pure fn kind_is_owned(k: kind) -> bool {
*k & KIND_MASK_OWNED == KIND_MASK_OWNED
}
fn proto_kind(p: proto) -> kind {
alt p {
ast::proto_any { kind_noncopyable() }
ast::proto_block { kind_noncopyable() }
ast::proto_box { kind_implicitly_copyable() }
ast::proto_uniq { kind_sendable() }
ast::proto_bare { kind_implicitly_sendable() | kind_const() }
ast::proto_box { kind_implicitly_copyable() | kind_owned() }
ast::proto_uniq { kind_send_copy() | kind_owned() }
ast::proto_bare { kind_implicitly_sendable() | kind_const() |
kind_owned() }
}
}
@ -1408,16 +1444,16 @@ fn raise_kind(a: kind, b: kind) -> kind {
fn test_kinds() {
// The kind "lattice" is defined by the subset operation on the
// set of permitted operations.
assert kind_lteq(kind_sendable(), kind_sendable());
assert kind_lteq(kind_copyable(), kind_sendable());
assert kind_lteq(kind_send_copy(), kind_send_copy());
assert kind_lteq(kind_copyable(), kind_send_copy());
assert kind_lteq(kind_copyable(), kind_copyable());
assert kind_lteq(kind_noncopyable(), kind_sendable());
assert kind_lteq(kind_noncopyable(), kind_send_copy());
assert kind_lteq(kind_noncopyable(), kind_copyable());
assert kind_lteq(kind_noncopyable(), kind_noncopyable());
assert kind_lteq(kind_copyable(), kind_implicitly_copyable());
assert kind_lteq(kind_copyable(), kind_implicitly_sendable());
assert kind_lteq(kind_sendable(), kind_implicitly_sendable());
assert !kind_lteq(kind_sendable(), kind_implicitly_copyable());
assert kind_lteq(kind_send_copy(), kind_implicitly_sendable());
assert !kind_lteq(kind_send_copy(), kind_implicitly_copyable());
assert !kind_lteq(kind_copyable(), kind_send_only());
}
@ -1447,66 +1483,73 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
cx.kind_cache.insert(ty, kind_top());
let result = alt get(ty).struct {
// Scalar and unique types are sendable
// Scalar and unique types are sendable, constant, and owned
ty_nil | ty_bot | ty_bool | ty_int(_) | ty_uint(_) | ty_float(_) |
ty_ptr(_) { kind_implicitly_sendable() | kind_const() }
ty_ptr(_) {
kind_implicitly_sendable() | kind_const() | kind_owned()
}
// Implicit copyability of strs is configurable
ty_estr(vstore_uniq) {
if cx.vecs_implicitly_copyable {
kind_implicitly_sendable() | kind_const()
} else { kind_sendable() | kind_const() }
kind_implicitly_sendable() | kind_const() | kind_owned()
} else {
kind_send_copy() | kind_const() | kind_owned()
}
}
// functions depend on the protocol
ty_fn(f) { proto_kind(f.proto) }
// Those with refcounts raise noncopyable to copyable,
// lower sendable to copyable. Therefore just set result to copyable.
ty_box(tm) {
if tm.mutbl == ast::m_mutbl {
kind_implicitly_copyable()
}
else {
let k = type_kind(cx, tm.ty);
if kind_lteq(kind_const(), k) {
kind_implicitly_copyable() | kind_const()
}
else { kind_implicitly_copyable() }
}
remove_send(mutable_type_kind(cx, tm) | kind_implicitly_copyable())
}
ty_trait(_, _) { kind_implicitly_copyable() }
// Iface instances are (for now) like shared boxes, basically
ty_trait(_, _) { kind_implicitly_copyable() | kind_owned() }
// Region pointers are copyable but NOT owned nor sendable
ty_rptr(_, _) { kind_implicitly_copyable() }
// Unique boxes and vecs have the kind of their contained type,
// but unique boxes can't be implicitly copyable.
ty_uniq(tm) {
remove_implicit(mutable_type_kind(cx, tm))
}
ty_uniq(tm) { remove_implicit(mutable_type_kind(cx, tm)) }
// Implicit copyability of vecs is configurable
ty_evec(tm, vstore_uniq) {
if cx.vecs_implicitly_copyable {
mutable_type_kind(cx, tm)
} else { remove_implicit(mutable_type_kind(cx, tm)) }
} else {
remove_implicit(mutable_type_kind(cx, tm))
}
}
// Slices, refcounted evecs are copyable; uniques depend on the their
// contained type, but aren't implicitly copyable. Fixed vectors have
// the kind of the element they contain, taking mutability into account.
ty_evec(tm, vstore_box) |
ty_evec(tm, vstore_box) {
remove_send(kind_implicitly_copyable() | mutable_type_kind(cx, tm))
}
ty_evec(tm, vstore_slice(_)) {
if kind_lteq(kind_const(), type_kind(cx, tm.ty)) {
kind_implicitly_copyable() | kind_const()
}
else {
kind_implicitly_copyable()
}
remove_owned_send(kind_implicitly_copyable() |
mutable_type_kind(cx, tm))
}
ty_evec(tm, vstore_fixed(_)) {
mutable_type_kind(cx, tm)
}
// All estrs are copyable; uniques and interiors are sendable.
ty_estr(vstore_box) |
ty_estr(vstore_slice(_)) { kind_implicitly_copyable() | kind_const() }
ty_estr(vstore_fixed(_)) { kind_implicitly_sendable() | kind_const() }
ty_estr(vstore_box) {
kind_implicitly_copyable() | kind_const() | kind_owned()
}
ty_estr(vstore_slice(_)) {
kind_implicitly_copyable() | kind_const()
}
ty_estr(vstore_fixed(_)) {
kind_implicitly_sendable() | kind_const() | kind_owned()
}
// Records lower to the lowest of their members.
ty_rec(flds) {
@ -1516,6 +1559,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
}
lowest
}
ty_class(did, substs) {
// Classes are sendable if all their fields are sendable,
// likewise for copyable...
@ -1532,18 +1576,20 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
}
lowest
}
// Tuples lower to the lowest of their members.
ty_tup(tys) {
let mut lowest = kind_top();
for tys.each |ty| { lowest = lower_kind(lowest, type_kind(cx, ty)); }
lowest
}
// Enums lower to the lowest of their variants.
ty_enum(did, substs) {
let mut lowest = kind_top();
let variants = enum_variants(cx, did);
if vec::len(*variants) == 0u {
lowest = kind_send_only();
lowest = kind_send_only() | kind_owned();
} else {
for vec::each(*variants) |variant| {
for variant.args.each |aty| {
@ -1556,11 +1602,15 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
}
lowest
}
ty_param(_, did) {
param_bounds_to_kind(cx.ty_param_bounds.get(did.node))
}
// FIXME (#2663): is self ever const?
// self is a special type parameter that can only appear in ifaces; it
// is never bounded in any way, hence it has the bottom kind.
ty_self { kind_noncopyable() }
ty_var(_) | ty_var_integral(_) {
cx.sess.bug(~"Asked to compute kind of a type variable");
}

View file

@ -169,7 +169,8 @@ class lookup {
let bounds = tcx.ty_param_bounds.get(did.node);
for vec::each(*bounds) |bound| {
let (iid, bound_substs) = alt bound {
ty::bound_copy | ty::bound_send | ty::bound_const {
ty::bound_copy | ty::bound_send | ty::bound_const |
ty::bound_owned {
again; /* ok */
}
ty::bound_trait(bound_t) {

View file

@ -68,7 +68,8 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
let mut n_bound = 0u;
for vec::each(*tcx.ty_param_bounds.get(did.node)) |bound| {
alt bound {
ty::bound_send | ty::bound_copy | ty::bound_const {
ty::bound_send | ty::bound_copy | ty::bound_const |
ty::bound_owned {
/* ignore */
}
ty::bound_trait(ity) {

View file

@ -572,6 +572,7 @@ fn ty_param_bounds(ccx: @crate_ctxt,
ast::bound_send { ~[ty::bound_send] }
ast::bound_copy { ~[ty::bound_copy] }
ast::bound_const { ~[ty::bound_const] }
ast::bound_owned { ~[ty::bound_owned] }
ast::bound_trait(t) {
let ity = ast_ty_to_ty(ccx, empty_rscope, t);
alt ty::get(ity).struct {

View file

@ -57,7 +57,6 @@ fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> ~str {
}
}
none {
// FIXME(#2586)
#fmt["<unknown-%d>", node_id]
}
_ { cx.sess.bug(

View file

@ -1,11 +1,9 @@
// error-pattern: copying a noncopyable value
fn to_lambda1(f: fn@(uint) -> uint) -> fn@(uint) -> uint {
ret f;
}
fn to_lambda2(b: fn(uint) -> uint) -> fn@(uint) -> uint {
ret to_lambda1({|x| b(x)});
ret to_lambda1({|x| b(x)}); //~ ERROR not an owned value
}
fn main() {

View file

@ -1,6 +1,8 @@
// error-pattern: copying a noncopyable value
fn to_lambda2(b: fn(uint) -> uint) -> fn@(uint) -> uint {
class foo { let x: int; new(x: int) { self.x = x; } drop { } }
fn to_lambda2(b: foo) -> fn@(uint) -> uint {
// test case where copy clause specifies a value that is not used
// in fn@ body, but value is illegal to copy:
ret fn@(u: uint, copy b) -> uint { 22u };

View file

@ -0,0 +1,19 @@
fn copy1<T: copy>(t: T) -> fn@() -> T {
fn@() -> T { t } //~ ERROR not an owned value
}
fn copy2<T: copy owned>(t: T) -> fn@() -> T {
fn@() -> T { t }
}
fn main() {
let x = &3;
copy2(&x); //~ ERROR instantiating a type parameter with an incompatible type
copy2(@3);
copy2(@&x); //~ ERROR instantiating a type parameter with an incompatible type
copy2(fn@() {});
copy2(fn~() {}); //~ WARNING instantiating copy type parameter with a not implicitly copyable type
copy2(fn&() {}); //~ ERROR instantiating a type parameter with an incompatible type
}

View file

@ -2,7 +2,7 @@ type pair<A,B> = {
a: A, b: B
};
fn f<A:copy>(a: A, b: u16) -> fn@() -> (A, u16) {
fn f<A:copy owned>(a: A, b: u16) -> fn@() -> (A, u16) {
fn@() -> (A, u16) { (a, b) }
}

View file

@ -6,7 +6,7 @@ type pair<A,B> = {
a: A, b: B
};
fn f<A:copy>(a: A, b: u16) -> fn@() -> (A, u16) {
fn f<A:copy owned>(a: A, b: u16) -> fn@() -> (A, u16) {
fn@() -> (A, u16) { (a, b) }
}

View file

@ -1,8 +1,8 @@
fn fix_help<A, B: send>(f: extern fn(fn@(A) -> B, A) -> B, x: A) -> B {
fn fix_help<A: owned, B: send>(f: extern fn(fn@(A) -> B, A) -> B, x: A) -> B {
ret f({|a|fix_help(f, a)}, x);
}
fn fix<A, B: send>(f: extern fn(fn@(A) -> B, A) -> B) -> fn@(A) -> B {
fn fix<A: owned, B: send>(f: extern fn(fn@(A) -> B, A) -> B) -> fn@(A) -> B {
ret {|a|fix_help(f, a)};
}