librustc: Allow moves out of self
. r=nmatsakis
This commit is contained in:
parent
45848b2040
commit
cd120736cb
@ -346,7 +346,8 @@ impl ast::def: tr {
|
||||
did2_opt.map(|did2| did2.tr(xcx)),
|
||||
p)
|
||||
}
|
||||
ast::def_self(nid) => { ast::def_self(xcx.tr_id(nid)) }
|
||||
ast::def_self_ty(nid) => { ast::def_self_ty(xcx.tr_id(nid)) }
|
||||
ast::def_self(nid, i) => { ast::def_self(xcx.tr_id(nid), i) }
|
||||
ast::def_mod(did) => { ast::def_mod(did.tr(xcx)) }
|
||||
ast::def_foreign_mod(did) => { ast::def_foreign_mod(did.tr(xcx)) }
|
||||
ast::def_const(did) => { ast::def_const(did.tr(xcx)) }
|
||||
|
@ -471,6 +471,9 @@ impl check_loan_ctxt {
|
||||
// rvalues, I guess.
|
||||
cat_special(sk_static_item) => {}
|
||||
|
||||
// We allow moving out of explicit self only.
|
||||
cat_special(sk_self) => {}
|
||||
|
||||
cat_deref(_, _, unsafe_ptr) => {}
|
||||
|
||||
// Nothing else.
|
||||
|
@ -74,7 +74,9 @@ priv impl &preserve_ctxt {
|
||||
let _i = indenter();
|
||||
|
||||
match cmt.cat {
|
||||
cat_special(sk_self) | cat_special(sk_heap_upvar) => {
|
||||
cat_special(sk_self) |
|
||||
cat_special(sk_implicit_self) |
|
||||
cat_special(sk_heap_upvar) => {
|
||||
self.compare_scope(cmt, ty::re_scope(self.item_ub))
|
||||
}
|
||||
cat_special(sk_static_item) | cat_special(sk_method) => {
|
||||
|
@ -110,8 +110,10 @@ use core::io::WriterUtil;
|
||||
use std::map::HashMap;
|
||||
use syntax::ast::*;
|
||||
use syntax::codemap::span;
|
||||
use syntax::parse::token::special_idents;
|
||||
use syntax::print::pprust::{expr_to_str, block_to_str};
|
||||
use syntax::visit::vt;
|
||||
use syntax::visit::{fk_anon, fk_dtor, fk_fn_block, fk_item_fn, fk_method};
|
||||
use syntax::visit::{vt};
|
||||
use syntax::{visit, ast_util};
|
||||
|
||||
export check_crate;
|
||||
@ -265,7 +267,6 @@ struct LocalInfo {
|
||||
enum VarKind {
|
||||
Arg(node_id, ident, rmode),
|
||||
Local(LocalInfo),
|
||||
Self,
|
||||
ImplicitRet
|
||||
}
|
||||
|
||||
@ -273,7 +274,8 @@ fn relevant_def(def: def) -> Option<node_id> {
|
||||
match def {
|
||||
def_binding(nid, _) |
|
||||
def_arg(nid, _) |
|
||||
def_local(nid, _) => Some(nid),
|
||||
def_local(nid, _) |
|
||||
def_self(nid, _) => Some(nid),
|
||||
|
||||
_ => None
|
||||
}
|
||||
@ -338,8 +340,7 @@ impl IrMaps {
|
||||
Arg(node_id, _, _) => {
|
||||
self.variable_map.insert(node_id, v);
|
||||
}
|
||||
Self | ImplicitRet => {
|
||||
}
|
||||
ImplicitRet => {}
|
||||
}
|
||||
|
||||
debug!("%s is %?", v.to_str(), vk);
|
||||
@ -361,7 +362,6 @@ impl IrMaps {
|
||||
match copy self.var_kinds[*var] {
|
||||
Local(LocalInfo {ident: nm, _}) |
|
||||
Arg(_, nm, _) => self.tcx.sess.str_of(nm),
|
||||
Self => ~"self",
|
||||
ImplicitRet => ~"<implicit-ret>"
|
||||
}
|
||||
}
|
||||
@ -404,7 +404,7 @@ impl IrMaps {
|
||||
(*v).push(id);
|
||||
}
|
||||
Arg(_, _, by_ref) |
|
||||
Arg(_, _, by_val) | Self | ImplicitRet => {
|
||||
Arg(_, _, by_val) | ImplicitRet => {
|
||||
debug!("--but it is not owned");
|
||||
}
|
||||
}
|
||||
@ -432,6 +432,31 @@ fn visit_fn(fk: visit::fn_kind, decl: fn_decl, body: blk,
|
||||
}
|
||||
};
|
||||
|
||||
// Add `self`, whether explicit or implicit.
|
||||
match fk {
|
||||
fk_method(_, _, method) => {
|
||||
match method.self_ty.node {
|
||||
sty_by_ref => {
|
||||
fn_maps.add_variable(Arg(method.self_id,
|
||||
special_idents::self_,
|
||||
by_ref));
|
||||
}
|
||||
sty_value | sty_region(_) | sty_box(_) | sty_uniq(_) => {
|
||||
fn_maps.add_variable(Arg(method.self_id,
|
||||
special_idents::self_,
|
||||
by_copy));
|
||||
}
|
||||
sty_static => {}
|
||||
}
|
||||
}
|
||||
fk_dtor(_, _, self_id, _) => {
|
||||
fn_maps.add_variable(Arg(self_id,
|
||||
special_idents::self_,
|
||||
by_copy));
|
||||
}
|
||||
fk_item_fn(*) | fk_anon(*) | fk_fn_block(*) => {}
|
||||
}
|
||||
|
||||
// gather up the various local variables, significant expressions,
|
||||
// and so forth:
|
||||
visit::visit_fn(fk, decl, body, sp, id, fn_maps, v);
|
||||
@ -1790,13 +1815,6 @@ impl @Liveness {
|
||||
copy or move mode", self.tcx.sess.str_of(name)));
|
||||
return;
|
||||
}
|
||||
Self => {
|
||||
self.tcx.sess.span_err(
|
||||
move_span,
|
||||
~"illegal move from self (cannot move out of a field of \
|
||||
self)");
|
||||
return;
|
||||
}
|
||||
Local(*) | ImplicitRet => {
|
||||
self.tcx.sess.span_bug(
|
||||
move_span,
|
||||
|
@ -224,6 +224,7 @@ enum special_kind {
|
||||
sk_method,
|
||||
sk_static_item,
|
||||
sk_self,
|
||||
sk_implicit_self, // old by-reference `self`
|
||||
sk_heap_upvar
|
||||
}
|
||||
|
||||
@ -566,7 +567,7 @@ impl &mem_categorization_ctxt {
|
||||
ast::def_ty(_) | ast::def_prim_ty(_) |
|
||||
ast::def_ty_param(*) | ast::def_struct(*) |
|
||||
ast::def_typaram_binder(*) | ast::def_region(_) |
|
||||
ast::def_label(_) => {
|
||||
ast::def_label(_) | ast::def_self_ty(*) => {
|
||||
@{id:id, span:span,
|
||||
cat:cat_special(sk_static_item), lp:None,
|
||||
mutbl:m_imm, ty:expr_ty}
|
||||
@ -599,9 +600,15 @@ impl &mem_categorization_ctxt {
|
||||
mutbl:m, ty:expr_ty}
|
||||
}
|
||||
|
||||
ast::def_self(_) => {
|
||||
ast::def_self(_, is_implicit) => {
|
||||
let special_kind = if is_implicit {
|
||||
sk_implicit_self
|
||||
} else {
|
||||
sk_self
|
||||
};
|
||||
|
||||
@{id:id, span:span,
|
||||
cat:cat_special(sk_self), lp:None,
|
||||
cat:cat_special(special_kind), lp:None,
|
||||
mutbl:m_imm, ty:expr_ty}
|
||||
}
|
||||
|
||||
@ -975,6 +982,7 @@ impl &mem_categorization_ctxt {
|
||||
match cat {
|
||||
cat_special(sk_method) => ~"method",
|
||||
cat_special(sk_static_item) => ~"static_item",
|
||||
cat_special(sk_implicit_self) => ~"implicit-self",
|
||||
cat_special(sk_self) => ~"self",
|
||||
cat_special(sk_heap_upvar) => ~"heap-upvar",
|
||||
cat_stack_upvar(_) => ~"stack-upvar",
|
||||
@ -1053,7 +1061,8 @@ impl &mem_categorization_ctxt {
|
||||
match cmt.cat {
|
||||
cat_special(sk_method) => ~"method",
|
||||
cat_special(sk_static_item) => ~"static item",
|
||||
cat_special(sk_self) => ~"self reference",
|
||||
cat_special(sk_implicit_self) => ~"self reference",
|
||||
cat_special(sk_self) => ~"self value",
|
||||
cat_special(sk_heap_upvar) => {
|
||||
~"captured outer variable in a heap closure"
|
||||
}
|
||||
|
@ -16,14 +16,13 @@ use metadata::decoder::{def_like, dl_def, dl_field, dl_impl};
|
||||
use middle::lang_items::LanguageItems;
|
||||
use middle::lint::{deny, allow, forbid, level, unused_imports, warn};
|
||||
use middle::pat_util::{pat_bindings};
|
||||
use syntax::ast::{_mod, add, arm};
|
||||
use syntax::ast::{bitand, bitor, bitxor};
|
||||
use syntax::ast::{binding_mode, blk, capture_clause, struct_dtor};
|
||||
use syntax::ast::{crate, crate_num, decl_item};
|
||||
use syntax::ast::{def, def_arg, def_binding, def_struct, def_const, def_fn};
|
||||
use syntax::ast::{def_foreign_mod, def_id, def_label, def_local, def_mod};
|
||||
use syntax::ast::{def_prim_ty, def_region, def_self, def_ty, def_ty_param};
|
||||
use syntax::ast::{def_typaram_binder, def_static_method};
|
||||
use syntax::ast::{_mod, add, arm, binding_mode, bitand, bitor, bitxor, blk};
|
||||
use syntax::ast::{capture_clause};
|
||||
use syntax::ast::{crate, crate_num, decl_item, def, def_arg, def_binding};
|
||||
use syntax::ast::{def_const, def_foreign_mod, def_fn, def_id, def_label};
|
||||
use syntax::ast::{def_local, def_mod, def_prim_ty, def_region, def_self};
|
||||
use syntax::ast::{def_self_ty, def_static_method, def_struct, def_ty};
|
||||
use syntax::ast::{def_ty_param, def_typaram_binder};
|
||||
use syntax::ast::{def_upvar, def_use, def_variant, expr, expr_assign_op};
|
||||
use syntax::ast::{expr_binary, expr_break, expr_cast, expr_field, expr_fn};
|
||||
use syntax::ast::{expr_fn_block, expr_index, expr_method_call, expr_path};
|
||||
@ -40,13 +39,13 @@ use syntax::ast::{local, local_crate, lt, method, mode, module_ns, mul, ne};
|
||||
use syntax::ast::{neg, node_id, pat, pat_enum, pat_ident, path, prim_ty};
|
||||
use syntax::ast::{pat_box, pat_lit, pat_range, pat_rec, pat_struct};
|
||||
use syntax::ast::{pat_tup, pat_uniq, pat_wild, private, provided, public};
|
||||
use syntax::ast::{required, rem, self_ty_, shl, shr, stmt_decl};
|
||||
use syntax::ast::{struct_field, struct_variant_kind, sty_static, subtract};
|
||||
use syntax::ast::{trait_ref, tuple_variant_kind, Ty, ty_bool, ty_char};
|
||||
use syntax::ast::{ty_f, ty_f32, ty_f64, ty_float, ty_i, ty_i16, ty_i32};
|
||||
use syntax::ast::{ty_i64, ty_i8, ty_int, ty_param, ty_path, ty_str, ty_u};
|
||||
use syntax::ast::{ty_u16, ty_u32, ty_u64, ty_u8, ty_uint, type_value_ns};
|
||||
use syntax::ast::{ty_param_bound, unnamed_field};
|
||||
use syntax::ast::{required, rem, self_ty_, shl, shr, stmt_decl, struct_dtor};
|
||||
use syntax::ast::{struct_field, struct_variant_kind, sty_by_ref, sty_static};
|
||||
use syntax::ast::{subtract, trait_ref, tuple_variant_kind, Ty, ty_bool};
|
||||
use syntax::ast::{ty_char, ty_f, ty_f32, ty_f64, ty_float, ty_i, ty_i16};
|
||||
use syntax::ast::{ty_i32, ty_i64, ty_i8, ty_int, ty_param, ty_path, ty_str};
|
||||
use syntax::ast::{ty_u, ty_u16, ty_u32, ty_u64, ty_u8, ty_uint};
|
||||
use syntax::ast::{type_value_ns, ty_param_bound, unnamed_field};
|
||||
use syntax::ast::{variant, view_item, view_item_export, view_item_import};
|
||||
use syntax::ast::{view_item_use, view_path_glob, view_path_list};
|
||||
use syntax::ast::{view_path_simple, visibility, anonymous, named};
|
||||
@ -197,7 +196,7 @@ impl Mutability : cmp::Eq {
|
||||
|
||||
enum SelfBinding {
|
||||
NoSelfBinding,
|
||||
HasSelfBinding(node_id)
|
||||
HasSelfBinding(node_id, bool /* is implicit */)
|
||||
}
|
||||
|
||||
enum CaptureClause {
|
||||
@ -1753,7 +1752,7 @@ impl Resolver {
|
||||
def_self(*) | def_arg(*) | def_local(*) |
|
||||
def_prim_ty(*) | def_ty_param(*) | def_binding(*) |
|
||||
def_use(*) | def_upvar(*) | def_region(*) |
|
||||
def_typaram_binder(*) | def_label(*) => {
|
||||
def_typaram_binder(*) | def_label(*) | def_self_ty(*) => {
|
||||
fail fmt!("didn't expect `%?`", def);
|
||||
}
|
||||
}
|
||||
@ -3724,7 +3723,7 @@ impl Resolver {
|
||||
let self_type_rib = @Rib(NormalRibKind);
|
||||
(*self.type_ribs).push(self_type_rib);
|
||||
self_type_rib.bindings.insert(self.self_ident,
|
||||
dl_def(def_self(item.id)));
|
||||
dl_def(def_self_ty(item.id)));
|
||||
|
||||
// Create a new rib for the trait-wide type parameters.
|
||||
do self.with_type_parameter_rib
|
||||
@ -3985,8 +3984,9 @@ impl Resolver {
|
||||
NoSelfBinding => {
|
||||
// Nothing to do.
|
||||
}
|
||||
HasSelfBinding(self_node_id) => {
|
||||
let def_like = dl_def(def_self(self_node_id));
|
||||
HasSelfBinding(self_node_id, is_implicit) => {
|
||||
let def_like = dl_def(def_self(self_node_id,
|
||||
is_implicit));
|
||||
(*function_value_rib).bindings.insert(self.self_ident,
|
||||
def_like);
|
||||
}
|
||||
@ -4065,7 +4065,8 @@ impl Resolver {
|
||||
NoTypeParameters,
|
||||
(*destructor).node.body,
|
||||
HasSelfBinding
|
||||
((*destructor).node.self_id),
|
||||
((*destructor).node.self_id,
|
||||
true),
|
||||
NoCaptureClause,
|
||||
visitor);
|
||||
}
|
||||
@ -4088,7 +4089,8 @@ impl Resolver {
|
||||
// we only have self ty if it is a non static method
|
||||
let self_binding = match method.self_ty.node {
|
||||
sty_static => { NoSelfBinding }
|
||||
_ => { HasSelfBinding(method.self_id) }
|
||||
sty_by_ref => { HasSelfBinding(method.self_id, true) }
|
||||
_ => { HasSelfBinding(method.self_id, false) }
|
||||
};
|
||||
|
||||
self.resolve_function(rib_kind,
|
||||
|
@ -114,7 +114,8 @@ fn trans(bcx: block, expr: @ast::expr) -> Callee {
|
||||
ast::def_mod(*) | ast::def_foreign_mod(*) |
|
||||
ast::def_const(*) | ast::def_ty(*) | ast::def_prim_ty(*) |
|
||||
ast::def_use(*) | ast::def_typaram_binder(*) |
|
||||
ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) => {
|
||||
ast::def_region(*) | ast::def_label(*) | ast::def_ty_param(*) |
|
||||
ast::def_self_ty(*) => {
|
||||
bcx.tcx().sess.span_bug(
|
||||
ref_expr.span,
|
||||
fmt!("Cannot translate def %? \
|
||||
|
@ -828,7 +828,7 @@ fn trans_local_var(bcx: block,
|
||||
ast::def_local(nid, _) | ast::def_binding(nid, _) => {
|
||||
take_local(bcx, bcx.fcx.lllocals, nid, expr_id_opt)
|
||||
}
|
||||
ast::def_self(nid) => {
|
||||
ast::def_self(nid, _) => {
|
||||
let self_info: ValSelfData = match bcx.fcx.llself {
|
||||
Some(ref self_info) => *self_info,
|
||||
None => {
|
||||
|
@ -354,7 +354,7 @@ fn ast_ty_to_ty<AC: ast_conv, RS: region_scope Copy Owned>(
|
||||
check_path_args(tcx, path, NO_TPS | NO_REGIONS);
|
||||
ty::mk_param(tcx, n, id)
|
||||
}
|
||||
ast::def_self(_) => {
|
||||
ast::def_self_ty(_) => {
|
||||
// n.b.: resolve guarantees that the self type only appears in a
|
||||
// trait, which we rely upon in various places when creating
|
||||
// substs
|
||||
|
@ -2721,7 +2721,7 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
|
||||
|
||||
match defn {
|
||||
ast::def_arg(nid, _) | ast::def_local(nid, _) |
|
||||
ast::def_self(nid) | ast::def_binding(nid, _) => {
|
||||
ast::def_self(nid, _) | ast::def_binding(nid, _) => {
|
||||
assert (fcx.inh.locals.contains_key(nid));
|
||||
let typ = ty::mk_var(fcx.ccx.tcx, lookup_local(fcx, sp, nid));
|
||||
return no_params(typ);
|
||||
@ -2774,6 +2774,9 @@ fn ty_param_bounds_and_ty_for_def(fcx: @fn_ctxt, sp: span, defn: ast::def) ->
|
||||
ast::def_label(*) => {
|
||||
fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found label");
|
||||
}
|
||||
ast::def_self_ty(*) => {
|
||||
fcx.ccx.tcx.sess.span_bug(sp, ~"expected value but found self ty");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ type rvt = visit::vt<@rcx>;
|
||||
fn encl_region_of_def(fcx: @fn_ctxt, def: ast::def) -> ty::Region {
|
||||
let tcx = fcx.tcx();
|
||||
match def {
|
||||
def_local(node_id, _) | def_arg(node_id, _) | def_self(node_id) |
|
||||
def_local(node_id, _) | def_arg(node_id, _) | def_self(node_id, _) |
|
||||
def_binding(node_id, _) =>
|
||||
return encl_region(tcx, node_id),
|
||||
def_upvar(_, subdef, closure_id, body_id) => {
|
||||
|
@ -118,7 +118,8 @@ enum def {
|
||||
def_static_method(/* method */ def_id,
|
||||
/* trait */ Option<def_id>,
|
||||
purity),
|
||||
def_self(node_id),
|
||||
def_self(node_id, bool /* is_implicit */),
|
||||
def_self_ty(node_id),
|
||||
def_mod(def_id),
|
||||
def_foreign_mod(def_id),
|
||||
def_const(def_id),
|
||||
@ -156,9 +157,15 @@ impl def : cmp::Eq {
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
def_self(e0a) => {
|
||||
def_self(e0a, e1a) => {
|
||||
match (*other) {
|
||||
def_self(e0b) => e0a == e0b,
|
||||
def_self(e0b, e1b) => e0a == e0b && e1a == e1b,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
def_self_ty(e0a) => {
|
||||
match (*other) {
|
||||
def_self_ty(e0b) => e0a == e0b,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
@ -71,8 +71,8 @@ pure fn def_id_of_def(d: def) -> def_id {
|
||||
def_use(id) | def_struct(id) => {
|
||||
id
|
||||
}
|
||||
def_arg(id, _) | def_local(id, _) | def_self(id) |
|
||||
def_upvar(id, _, _, _) | def_binding(id, _) | def_region(id)
|
||||
def_arg(id, _) | def_local(id, _) | def_self(id, _) | def_self_ty(id)
|
||||
| def_upvar(id, _, _, _) | def_binding(id, _) | def_region(id)
|
||||
| def_typaram_binder(id) | def_label(id) => {
|
||||
local_def(id)
|
||||
}
|
||||
@ -384,7 +384,7 @@ impl inlined_item: inlined_item_utils {
|
||||
referring to a def_self */
|
||||
fn is_self(d: ast::def) -> bool {
|
||||
match d {
|
||||
def_self(_) => true,
|
||||
def_self(*) => true,
|
||||
def_upvar(_, d, _, _) => is_self(*d),
|
||||
_ => false
|
||||
}
|
||||
|
19
src/test/compile-fail/use-after-move-self-based-on-type.rs
Normal file
19
src/test/compile-fail/use-after-move-self-based-on-type.rs
Normal file
@ -0,0 +1,19 @@
|
||||
struct S {
|
||||
x: int,
|
||||
drop {}
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn foo(self) -> int {
|
||||
self.bar();
|
||||
return self.x; //~ ERROR use of moved variable
|
||||
}
|
||||
|
||||
fn bar(self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = S { x: 1 };
|
||||
io::println(x.foo().to_str());
|
||||
}
|
||||
|
18
src/test/compile-fail/use-after-move-self.rs
Normal file
18
src/test/compile-fail/use-after-move-self.rs
Normal file
@ -0,0 +1,18 @@
|
||||
struct S {
|
||||
x: int
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn foo(self) -> int {
|
||||
(move self).bar();
|
||||
return self.x; //~ ERROR use of moved variable
|
||||
}
|
||||
|
||||
fn bar(self) {}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = S { x: 1 };
|
||||
io::println(x.foo().to_str());
|
||||
}
|
||||
|
19
src/test/run-pass/move-self.rs
Normal file
19
src/test/run-pass/move-self.rs
Normal file
@ -0,0 +1,19 @@
|
||||
struct S {
|
||||
x: ~str
|
||||
}
|
||||
|
||||
impl S {
|
||||
fn foo(self) {
|
||||
(move self).bar();
|
||||
}
|
||||
|
||||
fn bar(self) {
|
||||
io::println(self.x);
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = S { x: ~"Hello!" };
|
||||
x.foo();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user