From 0e42004babc7b965a10056084a8ae76c72140a44 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 16 Jul 2012 20:17:57 -0700 Subject: [PATCH] introduce an owned kind for data that contains no borrowed ptrs --- src/libsyntax/ast.rs | 1 + src/libsyntax/fold.rs | 2 +- src/libsyntax/parse/parser.rs | 17 +- src/libsyntax/parse/token.rs | 2 +- src/libsyntax/print/pprust.rs | 1 + src/libsyntax/visit.rs | 2 +- src/rustc/metadata/tydecode.rs | 1 + src/rustc/metadata/tyencode.rs | 1 + src/rustc/middle/kind.rs | 31 +++- src/rustc/middle/resolve3.rs | 3 +- src/rustc/middle/trans/base.rs | 103 ++++++------ src/rustc/middle/trans/closure.rs | 18 +- src/rustc/middle/trans/foreign.rs | 6 +- src/rustc/middle/trans/impl.rs | 2 +- src/rustc/middle/ty.rs | 154 ++++++++++++------ src/rustc/middle/typeck/check/method.rs | 3 +- src/rustc/middle/typeck/check/vtable.rs | 3 +- src/rustc/middle/typeck/collect.rs | 1 + src/rustc/util/ppaux.rs | 1 - ...ock-arg-used-as-lambda-with-illegal-cap.rs | 4 +- .../compile-fail/cap-clause-illegal-cap.rs | 4 +- src/test/compile-fail/kindck-owned.rs | 19 +++ src/test/run-pass/alignment-gep-tup-like-1.rs | 2 +- .../close-over-big-then-small-data.rs | 2 +- src/test/run-pass/fixed-point-bind-unique.rs | 4 +- 25 files changed, 245 insertions(+), 142 deletions(-) create mode 100644 src/test/compile-fail/kindck-owned.rs diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index db70ad12b6e..0e70a58b33b 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -62,6 +62,7 @@ enum ty_param_bound { bound_copy, bound_send, bound_const, + bound_owned, bound_trait(@ty), } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 965caacf07a..53bb9510acd 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -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)) } } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index fa0361e797b..dcc8f7430ca 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -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}; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index eb8c5b65fa5..949b078d8f0 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -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", diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 1b9b0ce7f96..937a46a05d3 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -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); } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 3e61f3706f9..b6822186b25 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -246,7 +246,7 @@ fn visit_ty_params(tps: ~[ty_param], e: E, v: vt) { 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 { } } } } diff --git a/src/rustc/metadata/tydecode.rs b/src/rustc/metadata/tydecode.rs index 28056838a7a..d6084d308d3 100644 --- a/src/rustc/metadata/tydecode.rs +++ b/src/rustc/metadata/tydecode.rs @@ -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; } }); diff --git a/src/rustc/metadata/tyencode.rs b/src/rustc/metadata/tyencode.rs index 9a6ddaf7c59..99e8f1cb611 100644 --- a/src/rustc/metadata/tyencode.rs +++ b/src/rustc/metadata/tyencode.rs @@ -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); diff --git a/src/rustc/middle/kind.rs b/src/rustc/middle/kind.rs index 7d89b4c701a..7c7b5eb49f7 100644 --- a/src/rustc/middle/kind.rs +++ b/src/rustc/middle/kind.rs @@ -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 } } diff --git a/src/rustc/middle/resolve3.rs b/src/rustc/middle/resolve3.rs index 9e742f38bac..7a021549b92 100644 --- a/src/rustc/middle/resolve3.rs +++ b/src/rustc/middle/resolve3.rs @@ -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) { diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 212ba14a516..256c3b0dd11 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -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, 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); diff --git a/src/rustc/middle/trans/closure.rs b/src/rustc/middle/trans/closure.rs index 22d16efbae5..dfeecabeb10 100644 --- a/src/rustc/middle/trans/closure.rs +++ b/src/rustc/middle/trans/closure.rs @@ -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); } diff --git a/src/rustc/middle/trans/foreign.rs b/src/rustc/middle/trans/foreign.rs index fca21eb3a8e..21ffefc5456 100644 --- a/src/rustc/middle/trans/foreign.rs +++ b/src/rustc/middle/trans/foreign.rs @@ -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); } } diff --git a/src/rustc/middle/trans/impl.rs b/src/rustc/middle/trans/impl.rs index 8ea0583b81b..5fc1b204e0e 100644 --- a/src/rustc/middle/trans/impl.rs +++ b/src/rustc/middle/trans/impl.rs @@ -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) diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index 0e724321b3e..0ff07554505 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -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"); } diff --git a/src/rustc/middle/typeck/check/method.rs b/src/rustc/middle/typeck/check/method.rs index 5627625daa3..05290d176ae 100644 --- a/src/rustc/middle/typeck/check/method.rs +++ b/src/rustc/middle/typeck/check/method.rs @@ -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) { diff --git a/src/rustc/middle/typeck/check/vtable.rs b/src/rustc/middle/typeck/check/vtable.rs index a4dd6bae933..e38b1a39e13 100644 --- a/src/rustc/middle/typeck/check/vtable.rs +++ b/src/rustc/middle/typeck/check/vtable.rs @@ -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) { diff --git a/src/rustc/middle/typeck/collect.rs b/src/rustc/middle/typeck/collect.rs index 68253a51ba6..0f4eb6d2e82 100644 --- a/src/rustc/middle/typeck/collect.rs +++ b/src/rustc/middle/typeck/collect.rs @@ -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 { diff --git a/src/rustc/util/ppaux.rs b/src/rustc/util/ppaux.rs index cbcd4b31e53..4d433939b37 100644 --- a/src/rustc/util/ppaux.rs +++ b/src/rustc/util/ppaux.rs @@ -57,7 +57,6 @@ fn re_scope_id_to_str(cx: ctxt, node_id: ast::node_id) -> ~str { } } none { - // FIXME(#2586) #fmt["", node_id] } _ { cx.sess.bug( diff --git a/src/test/compile-fail/block-arg-used-as-lambda-with-illegal-cap.rs b/src/test/compile-fail/block-arg-used-as-lambda-with-illegal-cap.rs index 2abaabc3ef8..f8688ee2bd2 100644 --- a/src/test/compile-fail/block-arg-used-as-lambda-with-illegal-cap.rs +++ b/src/test/compile-fail/block-arg-used-as-lambda-with-illegal-cap.rs @@ -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() { diff --git a/src/test/compile-fail/cap-clause-illegal-cap.rs b/src/test/compile-fail/cap-clause-illegal-cap.rs index 89a19cb89db..c13cc37f4b7 100644 --- a/src/test/compile-fail/cap-clause-illegal-cap.rs +++ b/src/test/compile-fail/cap-clause-illegal-cap.rs @@ -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 }; diff --git a/src/test/compile-fail/kindck-owned.rs b/src/test/compile-fail/kindck-owned.rs new file mode 100644 index 00000000000..7392d3183fe --- /dev/null +++ b/src/test/compile-fail/kindck-owned.rs @@ -0,0 +1,19 @@ +fn copy1(t: T) -> fn@() -> T { + fn@() -> T { t } //~ ERROR not an owned value +} + +fn copy2(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 +} diff --git a/src/test/run-pass/alignment-gep-tup-like-1.rs b/src/test/run-pass/alignment-gep-tup-like-1.rs index 0e25b86c90d..04f07001810 100644 --- a/src/test/run-pass/alignment-gep-tup-like-1.rs +++ b/src/test/run-pass/alignment-gep-tup-like-1.rs @@ -2,7 +2,7 @@ type pair = { a: A, b: B }; -fn f(a: A, b: u16) -> fn@() -> (A, u16) { +fn f(a: A, b: u16) -> fn@() -> (A, u16) { fn@() -> (A, u16) { (a, b) } } diff --git a/src/test/run-pass/close-over-big-then-small-data.rs b/src/test/run-pass/close-over-big-then-small-data.rs index 5fa3f7facc6..20f4a8055e8 100644 --- a/src/test/run-pass/close-over-big-then-small-data.rs +++ b/src/test/run-pass/close-over-big-then-small-data.rs @@ -6,7 +6,7 @@ type pair = { a: A, b: B }; -fn f(a: A, b: u16) -> fn@() -> (A, u16) { +fn f(a: A, b: u16) -> fn@() -> (A, u16) { fn@() -> (A, u16) { (a, b) } } diff --git a/src/test/run-pass/fixed-point-bind-unique.rs b/src/test/run-pass/fixed-point-bind-unique.rs index be9354d015a..029af017f65 100644 --- a/src/test/run-pass/fixed-point-bind-unique.rs +++ b/src/test/run-pass/fixed-point-bind-unique.rs @@ -1,8 +1,8 @@ -fn fix_help(f: extern fn(fn@(A) -> B, A) -> B, x: A) -> B { +fn fix_help(f: extern fn(fn@(A) -> B, A) -> B, x: A) -> B { ret f({|a|fix_help(f, a)}, x); } -fn fix(f: extern fn(fn@(A) -> B, A) -> B) -> fn@(A) -> B { +fn fix(f: extern fn(fn@(A) -> B, A) -> B) -> fn@(A) -> B { ret {|a|fix_help(f, a)}; }