introduce an owned kind for data that contains no borrowed ptrs
This commit is contained in:
parent
d809336d0f
commit
0e42004bab
25 changed files with 245 additions and 142 deletions
|
@ -62,6 +62,7 @@ enum ty_param_bound {
|
||||||
bound_copy,
|
bound_copy,
|
||||||
bound_send,
|
bound_send,
|
||||||
bound_const,
|
bound_const,
|
||||||
|
bound_owned,
|
||||||
bound_trait(@ty),
|
bound_trait(@ty),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
fn fold_ty_param_bound(tpb: ty_param_bound, fld: ast_fold) -> ty_param_bound {
|
||||||
alt tpb {
|
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)) }
|
bound_trait(ty) { bound_trait(fld.fold_ty(ty)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,8 @@ import dvec::{dvec, extensions};
|
||||||
import vec::{push};
|
import vec::{push};
|
||||||
import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
|
import ast::{_mod, add, alt_check, alt_exhaustive, arg, arm, attribute,
|
||||||
bitand, bitor, bitxor, blk, blk_check_mode, bound_const,
|
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,
|
by_mutbl_ref, by_ref, by_val, capture_clause, capture_item,
|
||||||
carg_base, carg_ident, cdir_dir_mod, cdir_src_mod,
|
carg_base, carg_ident, cdir_dir_mod, cdir_src_mod,
|
||||||
cdir_view_item, checked_expr, claimed_expr, class_immutable,
|
cdir_view_item, checked_expr, claimed_expr, class_immutable,
|
||||||
|
@ -1935,12 +1936,16 @@ class parser {
|
||||||
let ident = self.parse_ident();
|
let ident = self.parse_ident();
|
||||||
if self.eat(token::COLON) {
|
if self.eat(token::COLON) {
|
||||||
while self.token != token::COMMA && self.token != token::GT {
|
while self.token != token::COMMA && self.token != token::GT {
|
||||||
if self.eat_keyword(~"send") { push(bounds, bound_send); }
|
if self.eat_keyword(~"send") {
|
||||||
else if self.eat_keyword(~"copy") { push(bounds, bound_copy) }
|
push(bounds, bound_send); }
|
||||||
|
else if self.eat_keyword(~"copy") {
|
||||||
|
push(bounds, bound_copy) }
|
||||||
else if self.eat_keyword(~"const") {
|
else if self.eat_keyword(~"const") {
|
||||||
push(bounds, bound_const)
|
push(bounds, bound_const);
|
||||||
}
|
} else if self.eat_keyword(~"owned") {
|
||||||
else { push(bounds, bound_trait(self.parse_ty(false))); }
|
push(bounds, bound_owned);
|
||||||
|
} else {
|
||||||
|
push(bounds, bound_trait(self.parse_ty(false))); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ret {ident: ident, id: self.get_id(), bounds: @bounds};
|
ret {ident: ident, id: self.get_id(), bounds: @bounds};
|
||||||
|
|
|
@ -313,7 +313,7 @@ fn restricted_keyword_table() -> hashmap<~str, ()> {
|
||||||
~"if", ~"iface", ~"impl", ~"import",
|
~"if", ~"iface", ~"impl", ~"import",
|
||||||
~"let", ~"log", ~"loop",
|
~"let", ~"log", ~"loop",
|
||||||
~"mod", ~"mut",
|
~"mod", ~"mut",
|
||||||
~"new",
|
~"new", ~"owned",
|
||||||
~"pure", ~"ret",
|
~"pure", ~"ret",
|
||||||
~"true", ~"trait", ~"type",
|
~"true", ~"trait", ~"type",
|
||||||
~"unchecked", ~"unsafe",
|
~"unchecked", ~"unsafe",
|
||||||
|
|
|
@ -1377,6 +1377,7 @@ fn print_bounds(s: ps, bounds: @~[ast::ty_param_bound]) {
|
||||||
ast::bound_copy { word(s.s, ~"copy"); }
|
ast::bound_copy { word(s.s, ~"copy"); }
|
||||||
ast::bound_send { word(s.s, ~"send"); }
|
ast::bound_send { word(s.s, ~"send"); }
|
||||||
ast::bound_const { word(s.s, ~"const"); }
|
ast::bound_const { word(s.s, ~"const"); }
|
||||||
|
ast::bound_owned { word(s.s, ~"owned"); }
|
||||||
ast::bound_trait(t) { print_type(s, t); }
|
ast::bound_trait(t) { print_type(s, t); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,7 +246,7 @@ fn visit_ty_params<E>(tps: ~[ty_param], e: E, v: vt<E>) {
|
||||||
for vec::each(*tp.bounds) |bound| {
|
for vec::each(*tp.bounds) |bound| {
|
||||||
alt bound {
|
alt bound {
|
||||||
bound_trait(t) { v.visit_ty(t, e, v); }
|
bound_trait(t) { v.visit_ty(t, e, v); }
|
||||||
bound_copy | bound_send | bound_const { }
|
bound_copy | bound_send | bound_const | bound_owned { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -417,6 +417,7 @@ fn parse_bounds(st: @pstate, conv: conv_did) -> @~[ty::param_bound] {
|
||||||
'S' { ty::bound_send }
|
'S' { ty::bound_send }
|
||||||
'C' { ty::bound_copy }
|
'C' { ty::bound_copy }
|
||||||
'K' { ty::bound_const }
|
'K' { ty::bound_const }
|
||||||
|
'O' { ty::bound_owned }
|
||||||
'I' { ty::bound_trait(parse_ty(st, conv)) }
|
'I' { ty::bound_trait(parse_ty(st, conv)) }
|
||||||
'.' { break; }
|
'.' { break; }
|
||||||
});
|
});
|
||||||
|
|
|
@ -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_send { w.write_char('S'); }
|
||||||
ty::bound_copy { w.write_char('C'); }
|
ty::bound_copy { w.write_char('C'); }
|
||||||
ty::bound_const { w.write_char('K'); }
|
ty::bound_const { w.write_char('K'); }
|
||||||
|
ty::bound_owned { w.write_char('O'); }
|
||||||
ty::bound_trait(tp) {
|
ty::bound_trait(tp) {
|
||||||
w.write_char('I');
|
w.write_char('I');
|
||||||
enc_ty(w, cx, tp);
|
enc_ty(w, cx, tp);
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import syntax::{visit, ast_util};
|
import syntax::{visit, ast_util};
|
||||||
import syntax::ast::*;
|
import syntax::ast::*;
|
||||||
import syntax::codemap::span;
|
import syntax::codemap::span;
|
||||||
import ty::{kind, kind_sendable, kind_copyable, kind_noncopyable, kind_const,
|
import ty::{kind, kind_copyable, kind_noncopyable, kind_const, operators};
|
||||||
operators};
|
|
||||||
import driver::session::session;
|
import driver::session::session;
|
||||||
import std::map::hashmap;
|
import std::map::hashmap;
|
||||||
import util::ppaux::{ty_to_str, tys_to_str};
|
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.
|
// copy: Things that can be copied.
|
||||||
// const: Things thare are deeply immutable. They are guaranteed never to
|
// const: Things thare are deeply immutable. They are guaranteed never to
|
||||||
// change, and can be safely shared without copying between tasks.
|
// 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
|
// Send includes scalar types as well as classes and unique types containing
|
||||||
// only sendable types.
|
// only sendable types.
|
||||||
|
@ -41,15 +41,21 @@ import lint::{non_implicitly_copyable_typarams,implicit_copies};
|
||||||
|
|
||||||
fn kind_to_str(k: kind) -> ~str {
|
fn kind_to_str(k: kind) -> ~str {
|
||||||
let mut kinds = ~[];
|
let mut kinds = ~[];
|
||||||
|
|
||||||
if ty::kind_lteq(kind_const(), k) {
|
if ty::kind_lteq(kind_const(), k) {
|
||||||
vec::push(kinds, ~"const");
|
vec::push(kinds, ~"const");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ty::kind_can_be_copied(k) {
|
if ty::kind_can_be_copied(k) {
|
||||||
vec::push(kinds, ~"copy");
|
vec::push(kinds, ~"copy");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ty::kind_can_be_sent(k) {
|
if ty::kind_can_be_sent(k) {
|
||||||
vec::push(kinds, ~"send");
|
vec::push(kinds, ~"send");
|
||||||
|
} else if ty::kind_is_owned(k) {
|
||||||
|
vec::push(kinds, ~"owned");
|
||||||
}
|
}
|
||||||
|
|
||||||
str::connect(kinds, ~" ")
|
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>,
|
fn check_for_uniq(cx: ctx, id: node_id, fv: option<@freevar_entry>,
|
||||||
is_move: bool, var_t: ty::t, sp: span) {
|
is_move: bool, var_t: ty::t, sp: span) {
|
||||||
// all captured data must be sendable, regardless of whether it is
|
// all captured data must be sendable, regardless of whether it is
|
||||||
// moved in or copied in
|
// moved in or copied in. Note that send implies owned.
|
||||||
check_send(cx, var_t, sp);
|
if !check_send(cx, var_t, sp) { ret; }
|
||||||
|
|
||||||
// copied in data must be copyable, but moved in data can be anything
|
// copied in data must be copyable, but moved in data can be anything
|
||||||
let is_implicit = fv.is_some();
|
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>,
|
fn check_for_box(cx: ctx, id: node_id, fv: option<@freevar_entry>,
|
||||||
is_move: bool, var_t: ty::t, sp: span) {
|
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
|
// copied in data must be copyable, but moved in data can be anything
|
||||||
let is_implicit = fv.is_some();
|
let is_implicit = fv.is_some();
|
||||||
if !is_move { check_copy(cx, id, var_t, sp, is_implicit); }
|
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)) {
|
if !ty::kind_can_be_sent(ty::type_kind(cx.tcx, ty)) {
|
||||||
cx.tcx.sess.span_err(sp, ~"not a sendable value");
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import metadata::cstore::find_use_stmt_cnum;
|
||||||
import metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
|
import metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
|
||||||
import middle::lint::{error, ignore, level, unused_imports, warn};
|
import middle::lint::{error, ignore, level, unused_imports, warn};
|
||||||
import syntax::ast::{_mod, arm, blk, bound_const, bound_copy, bound_trait};
|
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::{bound_send, capture_clause, class_ctor, class_dtor};
|
||||||
import syntax::ast::{class_member, class_method, crate, crate_num, decl_item};
|
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};
|
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_parameters.each |type_parameter| {
|
||||||
for (*type_parameter.bounds).each |bound| {
|
for (*type_parameter.bounds).each |bound| {
|
||||||
alt bound {
|
alt bound {
|
||||||
bound_copy | bound_send | bound_const {
|
bound_copy | bound_send | bound_const | bound_owned {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
}
|
}
|
||||||
bound_trait(interface_type) {
|
bound_trait(interface_type) {
|
||||||
|
|
|
@ -1373,23 +1373,23 @@ fn move_val(cx: block, action: copy_action, dst: ValueRef,
|
||||||
let tcx = cx.tcx();
|
let tcx = cx.tcx();
|
||||||
let mut cx = cx;
|
let mut cx = cx;
|
||||||
if ty::type_is_scalar(t) {
|
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);
|
Store(cx, src_val, dst);
|
||||||
ret cx;
|
ret cx;
|
||||||
} else if ty::type_is_nil(t) || ty::type_is_bot(t) {
|
} else if ty::type_is_nil(t) || ty::type_is_bot(t) {
|
||||||
ret cx;
|
ret cx;
|
||||||
} else if ty::type_is_boxed(t) || ty::type_is_unique(t) {
|
} 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); }
|
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
|
||||||
Store(cx, src_val, dst);
|
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.
|
// If we're here, it must be a temporary.
|
||||||
revoke_clean(cx, src_val);
|
revoke_clean(cx, src_val);
|
||||||
ret cx;
|
ret cx;
|
||||||
} else if type_is_structural_or_param(t) {
|
} else if type_is_structural_or_param(t) {
|
||||||
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
|
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
|
||||||
memmove_ty(cx, dst, src_val, 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.
|
// If we're here, it must be a temporary.
|
||||||
revoke_clean(cx, src_val);
|
revoke_clean(cx, src_val);
|
||||||
ret cx;
|
ret cx;
|
||||||
|
@ -1403,8 +1403,8 @@ fn store_temp_expr(cx: block, action: copy_action, dst: ValueRef,
|
||||||
-> block {
|
-> block {
|
||||||
let _icx = cx.insn_ctxt(~"trans_temp_expr");
|
let _icx = cx.insn_ctxt(~"trans_temp_expr");
|
||||||
// Lvals in memory are not temporaries. Copy them.
|
// Lvals in memory are not temporaries. Copy them.
|
||||||
if src.kind != temporary && !last_use {
|
if src.kind != lv_temporary && !last_use {
|
||||||
let v = if src.kind == owned {
|
let v = if src.kind == lv_owned {
|
||||||
load_if_immediate(cx, src.val, t)
|
load_if_immediate(cx, src.val, t)
|
||||||
} else {
|
} else {
|
||||||
src.val
|
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 mut {bcx, val, kind} = trans_temp_lval(cx, e);
|
||||||
let ety = expr_ty(cx, e);
|
let ety = expr_ty(cx, e);
|
||||||
let is_immediate = ty::type_is_immediate(ety);
|
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);
|
val = do_spill(bcx, val, ety);
|
||||||
}
|
}
|
||||||
ret store_in_dest(bcx, val, dest);
|
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 _icx = bcx.insn_ctxt(~"trans_assign_op");
|
||||||
let t = expr_ty(bcx, src);
|
let t = expr_ty(bcx, src);
|
||||||
let lhs_res = trans_lval(bcx, dst);
|
let lhs_res = trans_lval(bcx, dst);
|
||||||
assert (lhs_res.kind == owned);
|
assert (lhs_res.kind == lv_owned);
|
||||||
|
|
||||||
// A user-defined operator method
|
// A user-defined operator method
|
||||||
alt bcx.ccx().maps.method_map.find(ex.id) {
|
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));
|
arg_exprs(~[src]), save_in(target));
|
||||||
|
|
||||||
ret move_val(bcx, DROP_EXISTING, lhs_res.val,
|
ret move_val(bcx, DROP_EXISTING, lhs_res.val,
|
||||||
{bcx: bcx, val: target, kind: owned},
|
{bcx: bcx, val: target, kind: lv_owned},
|
||||||
dty);
|
dty);
|
||||||
}
|
}
|
||||||
_ {}
|
_ {}
|
||||||
|
@ -1947,9 +1947,9 @@ fn trans_loop(cx:block, body: ast::blk) -> block {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum lval_kind {
|
enum lval_kind {
|
||||||
temporary, //< Temporary value passed by value if of immediate type
|
lv_temporary, //< Temporary value passed by value if of immediate type
|
||||||
owned, //< Non-temporary value passed by pointer
|
lv_owned, //< Non-temporary value passed by pointer
|
||||||
owned_imm, //< Non-temporary value passed by value
|
lv_owned_imm, //< Non-temporary value passed by value
|
||||||
}
|
}
|
||||||
type local_var_result = {val: ValueRef, kind: lval_kind};
|
type local_var_result = {val: ValueRef, kind: lval_kind};
|
||||||
type lval_result = {bcx: block, 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 {
|
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 {
|
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)
|
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(
|
val = PointerCast(bcx, val, T_ptr(type_of_fn_from_ty(
|
||||||
ccx, node_id_type(bcx, id))));
|
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 {
|
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 {
|
ast::extern_fn {
|
||||||
// Extern functions are just opaque pointers
|
// Extern functions are just opaque pointers
|
||||||
let val = PointerCast(bcx, val, T_ptr(T_i8()));
|
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 */ }
|
_ { /* fall through */ }
|
||||||
}
|
}
|
||||||
|
@ -2384,7 +2384,7 @@ fn lval_static_fn_inner(bcx: block, fn_id: ast::def_id, id: ast::node_id,
|
||||||
_ { /* fall through */ }
|
_ { /* 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 {
|
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>,
|
fn take_local(table: hashmap<ast::node_id, local_val>,
|
||||||
id: ast::node_id) -> local_var_result {
|
id: ast::node_id) -> local_var_result {
|
||||||
alt table.find(id) {
|
alt table.find(id) {
|
||||||
some(local_mem(v)) { {val: v, kind: owned} }
|
some(local_mem(v)) { {val: v, kind: lv_owned} }
|
||||||
some(local_imm(v)) { {val: v, kind: owned_imm} }
|
some(local_imm(v)) { {val: v, kind: lv_owned_imm} }
|
||||||
r { fail(~"take_local: internal error"); }
|
r { fail(~"take_local: internal error"); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alt def {
|
alt def {
|
||||||
ast::def_upvar(nid, _, _) {
|
ast::def_upvar(nid, _, _) {
|
||||||
assert (cx.fcx.llupvars.contains_key(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, _) {
|
ast::def_arg(nid, _) {
|
||||||
assert (cx.fcx.llargs.contains_key(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 \
|
none { cx.sess().bug(~"trans_local_var: reference to self \
|
||||||
out of context"); }
|
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: %?",
|
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_gv = lookup_discriminant(ccx, vid);
|
||||||
let lldiscrim = Load(cx, lldiscrim_gv);
|
let lldiscrim = Load(cx, lldiscrim_gv);
|
||||||
Store(cx, lldiscrim, lldiscrimptr);
|
Store(cx, lldiscrim, lldiscrimptr);
|
||||||
ret lval_no_env(cx, llenumptr, temporary);
|
ret lval_no_env(cx, llenumptr, lv_temporary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::def_const(did) {
|
ast::def_const(did) {
|
||||||
if did.crate == ast::local_crate {
|
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 {
|
} else {
|
||||||
let tp = node_id_type(cx, id);
|
let tp = node_id_type(cx, id);
|
||||||
let val = trans_external_path(ccx, did, tp);
|
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]) };
|
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 llfnty = llvm::LLVMGetElementType(val_ty(c.val));
|
||||||
let llfn = create_real_fn_pair(c.bcx, llfnty, c.val,
|
let llfn = create_real_fn_pair(c.bcx, llfnty, c.val,
|
||||||
null_env_ptr(c.bcx));
|
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) {
|
ast::expr_loop_body(blk) {
|
||||||
let scratch = alloc_ty(cx, expr_ty(cx, blk));
|
let scratch = alloc_ty(cx, expr_ty(cx, blk));
|
||||||
let bcx = trans_loop_body(cx, e, ret_flag, save_in(scratch));
|
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} = lval_result_to_result(lv, e_ty);
|
||||||
let {bcx, val, ty: e_ty} =
|
let {bcx, val, ty: e_ty} =
|
||||||
autoderef(bcx, e.id, val, e_ty, derefs);
|
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}
|
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 {
|
alt arg_mode {
|
||||||
ast::by_ref | ast::by_mutbl_ref {
|
ast::by_ref | ast::by_mutbl_ref {
|
||||||
// Ensure that the value is spilled into memory:
|
// 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);
|
val = do_spill_noroot(bcx, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ast::by_val {
|
ast::by_val {
|
||||||
// Ensure that the value is not spilled into memory:
|
// 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);
|
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 alloc = alloc_ty(bcx, arg.ty);
|
||||||
let move_out = arg_mode == ast::by_move ||
|
let move_out = arg_mode == ast::by_move ||
|
||||||
ccx.maps.last_use_map.contains_key(e.id);
|
ccx.maps.last_use_map.contains_key(e.id);
|
||||||
if lv.kind == temporary { revoke_clean(bcx, val); }
|
if lv.kind == lv_temporary { revoke_clean(bcx, val); }
|
||||||
if lv.kind == owned || !ty::type_is_immediate(arg.ty) {
|
if lv.kind == lv_owned || !ty::type_is_immediate(arg.ty) {
|
||||||
memmove_ty(bcx, alloc, val, arg.ty);
|
memmove_ty(bcx, alloc, val, arg.ty);
|
||||||
if move_out && ty::type_needs_drop(ccx.tcx, arg.ty) {
|
if move_out && ty::type_needs_drop(ccx.tcx, arg.ty) {
|
||||||
bcx = zero_mem(bcx, val, arg.ty);
|
bcx = zero_mem(bcx, val, arg.ty);
|
||||||
}
|
}
|
||||||
} else { Store(bcx, val, alloc); }
|
} else { Store(bcx, val, alloc); }
|
||||||
val = alloc;
|
val = alloc;
|
||||||
if lv.kind != temporary && !move_out {
|
if lv.kind != lv_temporary && !move_out {
|
||||||
bcx = take_ty(bcx, val, arg.ty);
|
bcx = take_ty(bcx, val, arg.ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2977,9 +2978,9 @@ fn adapt_borrowed_value(lv: lval_result,
|
||||||
ty::ty_estr(_) | ty::ty_evec(_, _) {
|
ty::ty_estr(_) | ty::ty_evec(_, _) {
|
||||||
let ccx = bcx.ccx();
|
let ccx = bcx.ccx();
|
||||||
let val = alt lv.kind {
|
let val = alt lv.kind {
|
||||||
temporary { lv.val }
|
lv_temporary { lv.val }
|
||||||
owned { load_if_immediate(bcx, lv.val, e_ty) }
|
lv_owned { load_if_immediate(bcx, lv.val, e_ty) }
|
||||||
owned_imm { lv.val }
|
lv_owned_imm { lv.val }
|
||||||
};
|
};
|
||||||
|
|
||||||
let unit_ty = ty::sequence_element_type(ccx.tcx, e_ty);
|
let unit_ty = ty::sequence_element_type(ccx.tcx, e_ty);
|
||||||
|
@ -3150,7 +3151,7 @@ fn trans_call_inner(
|
||||||
}
|
}
|
||||||
is_closure {
|
is_closure {
|
||||||
// It's a closure. Have to fetch the elements
|
// 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);
|
faddr = load_if_immediate(bcx, faddr, fn_expr_ty);
|
||||||
}
|
}
|
||||||
let pair = faddr;
|
let pair = faddr;
|
||||||
|
@ -3418,17 +3419,17 @@ fn trans_temp_lval(bcx: block, e: @ast::expr) -> lval_result {
|
||||||
let ty = expr_ty(bcx, e);
|
let ty = expr_ty(bcx, e);
|
||||||
if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
|
if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
|
||||||
bcx = trans_expr(bcx, e, ignore);
|
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) {
|
} else if ty::type_is_immediate(ty) {
|
||||||
let cell = empty_dest_cell();
|
let cell = empty_dest_cell();
|
||||||
bcx = trans_expr(bcx, e, by_val(cell));
|
bcx = trans_expr(bcx, e, by_val(cell));
|
||||||
add_clean_temp(bcx, *cell, ty);
|
add_clean_temp(bcx, *cell, ty);
|
||||||
ret {bcx: bcx, val: *cell, kind: temporary};
|
ret {bcx: bcx, val: *cell, kind: lv_temporary};
|
||||||
} else {
|
} else {
|
||||||
let scratch = alloc_ty(bcx, ty);
|
let scratch = alloc_ty(bcx, ty);
|
||||||
let bcx = trans_expr_save_in(bcx, e, scratch);
|
let bcx = trans_expr_save_in(bcx, e, scratch);
|
||||||
add_clean_temp(bcx, scratch, ty);
|
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 {
|
fn load_value_from_lval_result(lv: lval_result, ty: ty::t) -> ValueRef {
|
||||||
alt lv.kind {
|
alt lv.kind {
|
||||||
temporary { lv.val }
|
lv_temporary { lv.val }
|
||||||
owned { load_if_immediate(lv.bcx, lv.val, ty) }
|
lv_owned { load_if_immediate(lv.bcx, lv.val, ty) }
|
||||||
owned_imm { lv.val }
|
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");
|
let _icx = bcx.insn_ctxt(~"root_value_expr");
|
||||||
add_root_cleanup(bcx, scope_id, root_loc, ty);
|
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)
|
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;
|
assert dest == ignore;
|
||||||
let src_r = trans_temp_lval(bcx, src);
|
let src_r = trans_temp_lval(bcx, src);
|
||||||
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
|
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
|
||||||
assert kind == owned;
|
assert kind == lv_owned;
|
||||||
let is_last_use =
|
let is_last_use =
|
||||||
bcx.ccx().maps.last_use_map.contains_key(src.id);
|
bcx.ccx().maps.last_use_map.contains_key(src.id);
|
||||||
ret store_temp_expr(bcx, DROP_EXISTING, addr, src_r,
|
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;
|
assert dest == ignore;
|
||||||
let src_r = trans_temp_lval(bcx, src);
|
let src_r = trans_temp_lval(bcx, src);
|
||||||
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
|
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,
|
ret move_val(bcx, DROP_EXISTING, addr, src_r,
|
||||||
expr_ty(bcx, src));
|
expr_ty(bcx, src));
|
||||||
}
|
}
|
||||||
ast::expr_swap(dst, src) {
|
ast::expr_swap(dst, src) {
|
||||||
assert dest == ignore;
|
assert dest == ignore;
|
||||||
let lhs_res = trans_lval(bcx, dst);
|
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 rhs_res = trans_lval(lhs_res.bcx, src);
|
||||||
let t = expr_ty(bcx, src);
|
let t = expr_ty(bcx, src);
|
||||||
let tmp_alloc = alloc_ty(rhs_res.bcx, t);
|
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 last_use_map = bcx.ccx().maps.last_use_map;
|
||||||
let ty = expr_ty(bcx, e);
|
let ty = expr_ty(bcx, e);
|
||||||
let lv = trans_lval(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,
|
#debug["is last use (%s) = %b, %d", expr_to_str(e), last_use,
|
||||||
lv.kind as int];
|
lv.kind as int];
|
||||||
lval_result_to_dps(lv, ty, last_use, dest)
|
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();
|
let ccx = bcx.ccx();
|
||||||
alt dest {
|
alt dest {
|
||||||
by_val(cell) {
|
by_val(cell) {
|
||||||
if kind == temporary {
|
if kind == lv_temporary {
|
||||||
revoke_clean(bcx, val);
|
revoke_clean(bcx, val);
|
||||||
*cell = val;
|
*cell = val;
|
||||||
} else if last_use {
|
} 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);
|
bcx = zero_mem(bcx, val, ty);
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
let {bcx: cx, val} = take_ty_immediate(bcx, val, ty);
|
||||||
*cell = val;
|
*cell = val;
|
||||||
bcx = cx;
|
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
|
// Translate the body of the ctor
|
||||||
bcx = trans_block(bcx_top, body, ignore);
|
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
|
// Generate the return expression
|
||||||
bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res,
|
bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res,
|
||||||
rslt_ty, true);
|
rslt_ty, true);
|
||||||
|
|
|
@ -216,31 +216,31 @@ fn store_environment(bcx: block,
|
||||||
let bound_data = GEPi(bcx, llbox,
|
let bound_data = GEPi(bcx, llbox,
|
||||||
~[0u, abi::box_field_body, i]);
|
~[0u, abi::box_field_body, i]);
|
||||||
alt bv {
|
alt bv {
|
||||||
env_copy(val, ty, owned) {
|
env_copy(val, ty, lv_owned) {
|
||||||
let val1 = load_if_immediate(bcx, val, ty);
|
let val1 = load_if_immediate(bcx, val, ty);
|
||||||
bcx = base::copy_val(bcx, INIT, bound_data, val1, 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);
|
bcx = base::copy_val(bcx, INIT, bound_data, val, ty);
|
||||||
}
|
}
|
||||||
env_copy(_, _, temporary) {
|
env_copy(_, _, lv_temporary) {
|
||||||
fail ~"cannot capture temporary upvar";
|
fail ~"cannot capture temporary upvar";
|
||||||
}
|
}
|
||||||
env_move(val, ty, kind) {
|
env_move(val, ty, kind) {
|
||||||
let src = {bcx:bcx, val:val, kind:kind};
|
let src = {bcx:bcx, val:val, kind:kind};
|
||||||
bcx = move_val(bcx, INIT, bound_data, src, ty);
|
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",
|
#debug["> storing %s into %s",
|
||||||
val_str(bcx.ccx().tn, val),
|
val_str(bcx.ccx().tn, val),
|
||||||
val_str(bcx.ccx().tn, bound_data)];
|
val_str(bcx.ccx().tn, bound_data)];
|
||||||
Store(bcx, val, 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);
|
let addr = do_spill_noroot(bcx, val);
|
||||||
Store(bcx, addr, bound_data);
|
Store(bcx, addr, bound_data);
|
||||||
}
|
}
|
||||||
env_ref(_, _, temporary) {
|
env_ref(_, _, lv_temporary) {
|
||||||
fail ~"cannot capture temporary upvar";
|
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));
|
vec::push(env_vals, env_move(lv.val, ty, lv.kind));
|
||||||
}
|
}
|
||||||
capture::cap_drop {
|
capture::cap_drop {
|
||||||
assert lv.kind == owned;
|
assert lv.kind == lv_owned;
|
||||||
bcx = drop_ty(bcx, lv.val, ty);
|
bcx = drop_ty(bcx, lv.val, ty);
|
||||||
bcx = zero_mem(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()));
|
let nil_ret = PointerCast(bcx, our_ret, T_ptr(T_nil()));
|
||||||
vec::push(env_vals,
|
vec::push(env_vals,
|
||||||
env_ref(flagptr,
|
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,
|
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);
|
ret store_environment(bcx, env_vals, ck);
|
||||||
}
|
}
|
||||||
|
|
|
@ -881,7 +881,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
|
||||||
let tp_ty = substs.tys[0];
|
let tp_ty = substs.tys[0];
|
||||||
let src = {bcx: bcx,
|
let src = {bcx: bcx,
|
||||||
val: get_param(decl, first_real_arg + 1u),
|
val: get_param(decl, first_real_arg + 1u),
|
||||||
kind: owned };
|
kind: lv_owned};
|
||||||
bcx = move_val(bcx, DROP_EXISTING,
|
bcx = move_val(bcx, DROP_EXISTING,
|
||||||
get_param(decl, first_real_arg),
|
get_param(decl, first_real_arg),
|
||||||
src,
|
src,
|
||||||
|
@ -891,7 +891,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
|
||||||
let tp_ty = substs.tys[0];
|
let tp_ty = substs.tys[0];
|
||||||
let src = {bcx: bcx,
|
let src = {bcx: bcx,
|
||||||
val: get_param(decl, first_real_arg + 1u),
|
val: get_param(decl, first_real_arg + 1u),
|
||||||
kind: owned };
|
kind: lv_owned};
|
||||||
bcx = move_val(bcx, INIT,
|
bcx = move_val(bcx, INIT,
|
||||||
get_param(decl, first_real_arg),
|
get_param(decl, first_real_arg),
|
||||||
src,
|
src,
|
||||||
|
@ -982,7 +982,7 @@ fn trans_intrinsic(ccx: @crate_ctxt, decl: ValueRef, item: @ast::foreign_item,
|
||||||
|bcx| lval_no_env(
|
|bcx| lval_no_env(
|
||||||
bcx,
|
bcx,
|
||||||
get_param(decl, first_real_arg),
|
get_param(decl, first_real_arg),
|
||||||
temporary),
|
lv_temporary),
|
||||||
arg_vals(~[frameaddress_val]), ignore);
|
arg_vals(~[frameaddress_val]), ignore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -162,7 +162,7 @@ fn trans_trait_callee(bcx: block, val: ValueRef,
|
||||||
let vtable = PointerCast(bcx, vtable,
|
let vtable = PointerCast(bcx, vtable,
|
||||||
T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
|
T_ptr(T_array(T_ptr(llfty), n_method + 1u)));
|
||||||
let mptr = Load(bcx, GEPi(bcx, vtable, ~[0u, n_method]));
|
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)
|
fn find_vtable_in_fn_ctxt(ps: param_substs, n_param: uint, n_bound: uint)
|
||||||
|
|
|
@ -107,9 +107,10 @@ export tbox_has_flag;
|
||||||
export ty_var_id;
|
export ty_var_id;
|
||||||
export ty_to_def_id;
|
export ty_to_def_id;
|
||||||
export ty_fn_args;
|
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_noncopyable, kind_const;
|
||||||
export kind_can_be_copied, kind_can_be_sent, kind_can_be_implicitly_copied;
|
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 proto_kind, kind_lteq, type_kind;
|
||||||
export operators;
|
export operators;
|
||||||
export type_err, terr_vstore_kind;
|
export type_err, terr_vstore_kind;
|
||||||
|
@ -144,7 +145,8 @@ export closure_kind;
|
||||||
export ck_block;
|
export ck_block;
|
||||||
export ck_box;
|
export ck_box;
|
||||||
export ck_uniq;
|
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 param_bounds_to_kind;
|
||||||
export default_arg_mode_for_ty;
|
export default_arg_mode_for_ty;
|
||||||
export item_path;
|
export item_path;
|
||||||
|
@ -409,6 +411,7 @@ enum type_err {
|
||||||
|
|
||||||
enum param_bound {
|
enum param_bound {
|
||||||
bound_copy,
|
bound_copy,
|
||||||
|
bound_owned,
|
||||||
bound_send,
|
bound_send,
|
||||||
bound_const,
|
bound_const,
|
||||||
bound_trait(t),
|
bound_trait(t),
|
||||||
|
@ -451,8 +454,15 @@ fn param_bounds_to_kind(bounds: param_bounds) -> kind {
|
||||||
bound_copy {
|
bound_copy {
|
||||||
kind = raise_kind(kind, kind_implicitly_copyable());
|
kind = raise_kind(kind, kind_implicitly_copyable());
|
||||||
}
|
}
|
||||||
bound_send { kind = raise_kind(kind, kind_send_only()); }
|
bound_owned {
|
||||||
bound_const { kind = raise_kind(kind, kind_const()); }
|
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(_) {}
|
bound_trait(_) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1303,11 +1313,20 @@ fn type_needs_unwind_cleanup_(cx: ctxt, ty: t,
|
||||||
|
|
||||||
enum kind { kind_(u32) }
|
enum kind { kind_(u32) }
|
||||||
|
|
||||||
// *ALL* implicitly copiable things must be copiable
|
/// can be copied (implicitly or explicitly)
|
||||||
const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001u32;
|
const KIND_MASK_COPY : u32 = 0b00000000000000000000000000000001_u32;
|
||||||
const KIND_MASK_SEND : u32 = 0b00000000000000000000000000000010u32;
|
|
||||||
const KIND_MASK_CONST : u32 = 0b00000000000000000000000000000100u32;
|
/// can be sent: no shared box, borrowed ptr (must imply OWNED)
|
||||||
const KIND_MASK_IMPLICIT : u32 = 0b00000000000000000000000000001000u32;
|
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 {
|
fn kind_noncopyable() -> kind {
|
||||||
kind_(0u32)
|
kind_(0u32)
|
||||||
|
@ -1325,7 +1344,7 @@ fn kind_implicitly_sendable() -> kind {
|
||||||
kind_(KIND_MASK_IMPLICIT | KIND_MASK_COPY | KIND_MASK_SEND)
|
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)
|
kind_(KIND_MASK_COPY | KIND_MASK_SEND)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1337,6 +1356,10 @@ fn kind_const() -> kind {
|
||||||
kind_(KIND_MASK_CONST)
|
kind_(KIND_MASK_CONST)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn kind_owned() -> kind {
|
||||||
|
kind_(KIND_MASK_OWNED)
|
||||||
|
}
|
||||||
|
|
||||||
fn kind_top() -> kind {
|
fn kind_top() -> kind {
|
||||||
kind_(0xffffffffu32)
|
kind_(0xffffffffu32)
|
||||||
}
|
}
|
||||||
|
@ -1349,6 +1372,14 @@ fn remove_implicit(k: kind) -> kind {
|
||||||
k - kind_(KIND_MASK_IMPLICIT)
|
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 {
|
fn remove_copyable(k: kind) -> kind {
|
||||||
k - kind_(KIND_MASK_COPY)
|
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
|
// against the kind constants, as we may modify the kind hierarchy in the
|
||||||
// future.
|
// future.
|
||||||
pure fn kind_can_be_implicitly_copied(k: kind) -> bool {
|
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 {
|
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 {
|
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 {
|
fn proto_kind(p: proto) -> kind {
|
||||||
alt p {
|
alt p {
|
||||||
ast::proto_any { kind_noncopyable() }
|
ast::proto_any { kind_noncopyable() }
|
||||||
ast::proto_block { kind_noncopyable() }
|
ast::proto_block { kind_noncopyable() }
|
||||||
ast::proto_box { kind_implicitly_copyable() }
|
ast::proto_box { kind_implicitly_copyable() | kind_owned() }
|
||||||
ast::proto_uniq { kind_sendable() }
|
ast::proto_uniq { kind_send_copy() | kind_owned() }
|
||||||
ast::proto_bare { kind_implicitly_sendable() | kind_const() }
|
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() {
|
fn test_kinds() {
|
||||||
// The kind "lattice" is defined by the subset operation on the
|
// The kind "lattice" is defined by the subset operation on the
|
||||||
// set of permitted operations.
|
// set of permitted operations.
|
||||||
assert kind_lteq(kind_sendable(), kind_sendable());
|
assert kind_lteq(kind_send_copy(), kind_send_copy());
|
||||||
assert kind_lteq(kind_copyable(), kind_sendable());
|
assert kind_lteq(kind_copyable(), kind_send_copy());
|
||||||
assert kind_lteq(kind_copyable(), kind_copyable());
|
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_copyable());
|
||||||
assert kind_lteq(kind_noncopyable(), kind_noncopyable());
|
assert kind_lteq(kind_noncopyable(), kind_noncopyable());
|
||||||
assert kind_lteq(kind_copyable(), kind_implicitly_copyable());
|
assert kind_lteq(kind_copyable(), kind_implicitly_copyable());
|
||||||
assert kind_lteq(kind_copyable(), kind_implicitly_sendable());
|
assert kind_lteq(kind_copyable(), kind_implicitly_sendable());
|
||||||
assert kind_lteq(kind_sendable(), kind_implicitly_sendable());
|
assert kind_lteq(kind_send_copy(), kind_implicitly_sendable());
|
||||||
assert !kind_lteq(kind_sendable(), kind_implicitly_copyable());
|
assert !kind_lteq(kind_send_copy(), kind_implicitly_copyable());
|
||||||
assert !kind_lteq(kind_copyable(), kind_send_only());
|
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());
|
cx.kind_cache.insert(ty, kind_top());
|
||||||
|
|
||||||
let result = alt get(ty).struct {
|
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_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
|
// Implicit copyability of strs is configurable
|
||||||
ty_estr(vstore_uniq) {
|
ty_estr(vstore_uniq) {
|
||||||
if cx.vecs_implicitly_copyable {
|
if cx.vecs_implicitly_copyable {
|
||||||
kind_implicitly_sendable() | kind_const()
|
kind_implicitly_sendable() | kind_const() | kind_owned()
|
||||||
} else { kind_sendable() | kind_const() }
|
} else {
|
||||||
|
kind_send_copy() | kind_const() | kind_owned()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// functions depend on the protocol
|
||||||
ty_fn(f) { proto_kind(f.proto) }
|
ty_fn(f) { proto_kind(f.proto) }
|
||||||
|
|
||||||
// Those with refcounts raise noncopyable to copyable,
|
// Those with refcounts raise noncopyable to copyable,
|
||||||
// lower sendable to copyable. Therefore just set result to copyable.
|
// lower sendable to copyable. Therefore just set result to copyable.
|
||||||
ty_box(tm) {
|
ty_box(tm) {
|
||||||
if tm.mutbl == ast::m_mutbl {
|
remove_send(mutable_type_kind(cx, tm) | kind_implicitly_copyable())
|
||||||
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() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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() }
|
ty_rptr(_, _) { kind_implicitly_copyable() }
|
||||||
|
|
||||||
// Unique boxes and vecs have the kind of their contained type,
|
// Unique boxes and vecs have the kind of their contained type,
|
||||||
// but unique boxes can't be implicitly copyable.
|
// but unique boxes can't be implicitly copyable.
|
||||||
ty_uniq(tm) {
|
ty_uniq(tm) { remove_implicit(mutable_type_kind(cx, tm)) }
|
||||||
remove_implicit(mutable_type_kind(cx, tm))
|
|
||||||
}
|
|
||||||
// Implicit copyability of vecs is configurable
|
// Implicit copyability of vecs is configurable
|
||||||
ty_evec(tm, vstore_uniq) {
|
ty_evec(tm, vstore_uniq) {
|
||||||
if cx.vecs_implicitly_copyable {
|
if cx.vecs_implicitly_copyable {
|
||||||
mutable_type_kind(cx, tm)
|
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
|
// Slices, refcounted evecs are copyable; uniques depend on the their
|
||||||
// contained type, but aren't implicitly copyable. Fixed vectors have
|
// contained type, but aren't implicitly copyable. Fixed vectors have
|
||||||
// the kind of the element they contain, taking mutability into account.
|
// 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(_)) {
|
ty_evec(tm, vstore_slice(_)) {
|
||||||
if kind_lteq(kind_const(), type_kind(cx, tm.ty)) {
|
remove_owned_send(kind_implicitly_copyable() |
|
||||||
kind_implicitly_copyable() | kind_const()
|
mutable_type_kind(cx, tm))
|
||||||
}
|
|
||||||
else {
|
|
||||||
kind_implicitly_copyable()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ty_evec(tm, vstore_fixed(_)) {
|
ty_evec(tm, vstore_fixed(_)) {
|
||||||
mutable_type_kind(cx, tm)
|
mutable_type_kind(cx, tm)
|
||||||
}
|
}
|
||||||
|
|
||||||
// All estrs are copyable; uniques and interiors are sendable.
|
// All estrs are copyable; uniques and interiors are sendable.
|
||||||
ty_estr(vstore_box) |
|
ty_estr(vstore_box) {
|
||||||
ty_estr(vstore_slice(_)) { kind_implicitly_copyable() | kind_const() }
|
kind_implicitly_copyable() | kind_const() | kind_owned()
|
||||||
ty_estr(vstore_fixed(_)) { kind_implicitly_sendable() | kind_const() }
|
}
|
||||||
|
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.
|
// Records lower to the lowest of their members.
|
||||||
ty_rec(flds) {
|
ty_rec(flds) {
|
||||||
|
@ -1516,6 +1559,7 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
|
||||||
}
|
}
|
||||||
lowest
|
lowest
|
||||||
}
|
}
|
||||||
|
|
||||||
ty_class(did, substs) {
|
ty_class(did, substs) {
|
||||||
// Classes are sendable if all their fields are sendable,
|
// Classes are sendable if all their fields are sendable,
|
||||||
// likewise for copyable...
|
// likewise for copyable...
|
||||||
|
@ -1532,18 +1576,20 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
|
||||||
}
|
}
|
||||||
lowest
|
lowest
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tuples lower to the lowest of their members.
|
// Tuples lower to the lowest of their members.
|
||||||
ty_tup(tys) {
|
ty_tup(tys) {
|
||||||
let mut lowest = kind_top();
|
let mut lowest = kind_top();
|
||||||
for tys.each |ty| { lowest = lower_kind(lowest, type_kind(cx, ty)); }
|
for tys.each |ty| { lowest = lower_kind(lowest, type_kind(cx, ty)); }
|
||||||
lowest
|
lowest
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enums lower to the lowest of their variants.
|
// Enums lower to the lowest of their variants.
|
||||||
ty_enum(did, substs) {
|
ty_enum(did, substs) {
|
||||||
let mut lowest = kind_top();
|
let mut lowest = kind_top();
|
||||||
let variants = enum_variants(cx, did);
|
let variants = enum_variants(cx, did);
|
||||||
if vec::len(*variants) == 0u {
|
if vec::len(*variants) == 0u {
|
||||||
lowest = kind_send_only();
|
lowest = kind_send_only() | kind_owned();
|
||||||
} else {
|
} else {
|
||||||
for vec::each(*variants) |variant| {
|
for vec::each(*variants) |variant| {
|
||||||
for variant.args.each |aty| {
|
for variant.args.each |aty| {
|
||||||
|
@ -1556,11 +1602,15 @@ fn type_kind(cx: ctxt, ty: t) -> kind {
|
||||||
}
|
}
|
||||||
lowest
|
lowest
|
||||||
}
|
}
|
||||||
|
|
||||||
ty_param(_, did) {
|
ty_param(_, did) {
|
||||||
param_bounds_to_kind(cx.ty_param_bounds.get(did.node))
|
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_self { kind_noncopyable() }
|
||||||
|
|
||||||
ty_var(_) | ty_var_integral(_) {
|
ty_var(_) | ty_var_integral(_) {
|
||||||
cx.sess.bug(~"Asked to compute kind of a type variable");
|
cx.sess.bug(~"Asked to compute kind of a type variable");
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,7 +169,8 @@ class lookup {
|
||||||
let bounds = tcx.ty_param_bounds.get(did.node);
|
let bounds = tcx.ty_param_bounds.get(did.node);
|
||||||
for vec::each(*bounds) |bound| {
|
for vec::each(*bounds) |bound| {
|
||||||
let (iid, bound_substs) = alt 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 */
|
again; /* ok */
|
||||||
}
|
}
|
||||||
ty::bound_trait(bound_t) {
|
ty::bound_trait(bound_t) {
|
||||||
|
|
|
@ -68,7 +68,8 @@ fn lookup_vtable(fcx: @fn_ctxt, isc: resolve::iscopes, sp: span,
|
||||||
let mut n_bound = 0u;
|
let mut n_bound = 0u;
|
||||||
for vec::each(*tcx.ty_param_bounds.get(did.node)) |bound| {
|
for vec::each(*tcx.ty_param_bounds.get(did.node)) |bound| {
|
||||||
alt 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 */
|
/* ignore */
|
||||||
}
|
}
|
||||||
ty::bound_trait(ity) {
|
ty::bound_trait(ity) {
|
||||||
|
|
|
@ -572,6 +572,7 @@ fn ty_param_bounds(ccx: @crate_ctxt,
|
||||||
ast::bound_send { ~[ty::bound_send] }
|
ast::bound_send { ~[ty::bound_send] }
|
||||||
ast::bound_copy { ~[ty::bound_copy] }
|
ast::bound_copy { ~[ty::bound_copy] }
|
||||||
ast::bound_const { ~[ty::bound_const] }
|
ast::bound_const { ~[ty::bound_const] }
|
||||||
|
ast::bound_owned { ~[ty::bound_owned] }
|
||||||
ast::bound_trait(t) {
|
ast::bound_trait(t) {
|
||||||
let ity = ast_ty_to_ty(ccx, empty_rscope, t);
|
let ity = ast_ty_to_ty(ccx, empty_rscope, t);
|
||||||
alt ty::get(ity).struct {
|
alt ty::get(ity).struct {
|
||||||
|
|
|
@ -57,7 +57,6 @@ fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> ~str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
none {
|
none {
|
||||||
// FIXME(#2586)
|
|
||||||
#fmt["<unknown-%d>", node_id]
|
#fmt["<unknown-%d>", node_id]
|
||||||
}
|
}
|
||||||
_ { cx.sess.bug(
|
_ { cx.sess.bug(
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
// error-pattern: copying a noncopyable value
|
|
||||||
|
|
||||||
fn to_lambda1(f: fn@(uint) -> uint) -> fn@(uint) -> uint {
|
fn to_lambda1(f: fn@(uint) -> uint) -> fn@(uint) -> uint {
|
||||||
ret f;
|
ret f;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_lambda2(b: fn(uint) -> uint) -> fn@(uint) -> uint {
|
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() {
|
fn main() {
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
// error-pattern: copying a noncopyable value
|
// 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
|
// test case where copy clause specifies a value that is not used
|
||||||
// in fn@ body, but value is illegal to copy:
|
// in fn@ body, but value is illegal to copy:
|
||||||
ret fn@(u: uint, copy b) -> uint { 22u };
|
ret fn@(u: uint, copy b) -> uint { 22u };
|
||||||
|
|
19
src/test/compile-fail/kindck-owned.rs
Normal file
19
src/test/compile-fail/kindck-owned.rs
Normal 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
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ type pair<A,B> = {
|
||||||
a: A, b: 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) }
|
fn@() -> (A, u16) { (a, b) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ type pair<A,B> = {
|
||||||
a: A, b: 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) }
|
fn@() -> (A, u16) { (a, b) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
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)};
|
ret {|a|fix_help(f, a)};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue