Allow moving out of mutable unsafe pointers

This makes it possible to de-initialize values anywhere in
memory, which is needed, for example, for a fast imlementation
of vec::pop.
This commit is contained in:
Marijn Haverbeke 2012-01-27 17:15:31 +01:00
parent dc55c06aa3
commit 362625008a
2 changed files with 20 additions and 10 deletions

View file

@ -5,7 +5,7 @@ import syntax::visit;
import syntax::ast_util; import syntax::ast_util;
import driver::session::session; import driver::session::session;
enum deref_t { unbox, field, index, } enum deref_t { unbox(bool), field, index, }
type deref = @{mut: bool, kind: deref_t, outer_t: ty::t}; type deref = @{mut: bool, kind: deref_t, outer_t: ty::t};
@ -20,15 +20,15 @@ fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) ->
while true { while true {
alt ty::struct(tcx, t) { alt ty::struct(tcx, t) {
ty::ty_box(mt) { ty::ty_box(mt) {
ds += [@{mut: mt.mut == mut, kind: unbox, outer_t: t}]; ds += [@{mut: mt.mut == mut, kind: unbox(false), outer_t: t}];
t = mt.ty; t = mt.ty;
} }
ty::ty_uniq(mt) { ty::ty_uniq(mt) {
ds += [@{mut: mt.mut == mut, kind: unbox, outer_t: t}]; ds += [@{mut: mt.mut == mut, kind: unbox(false), outer_t: t}];
t = mt.ty; t = mt.ty;
} }
ty::ty_res(_, inner, tps) { ty::ty_res(_, inner, tps) {
ds += [@{mut: false, kind: unbox, outer_t: t}]; ds += [@{mut: false, kind: unbox(false), outer_t: t}];
t = ty::substitute_type_params(tcx, tps, inner); t = ty::substitute_type_params(tcx, tps, inner);
} }
ty::ty_enum(did, tps) { ty::ty_enum(did, tps) {
@ -37,7 +37,7 @@ fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) ->
vec::len(variants[0].args) != 1u { vec::len(variants[0].args) != 1u {
break; break;
} }
ds += [@{mut: false, kind: unbox, outer_t: t}]; ds += [@{mut: false, kind: unbox(false), outer_t: t}];
t = ty::substitute_type_params(tcx, tps, variants[0].args[0]); t = ty::substitute_type_params(tcx, tps, variants[0].args[0]);
} }
_ { break; } _ { break; }
@ -85,15 +85,16 @@ fn expr_root(tcx: ty::ctxt, ex: @expr, autoderef: bool) ->
expr_unary(op, base) { expr_unary(op, base) {
if op == deref { if op == deref {
let base_t = ty::expr_ty(tcx, base); let base_t = ty::expr_ty(tcx, base);
let is_mut = false; let is_mut = false, ptr = false;
alt ty::struct(tcx, base_t) { alt ty::struct(tcx, base_t) {
ty::ty_box(mt) { is_mut = mt.mut == mut; } ty::ty_box(mt) { is_mut = mt.mut == mut; }
ty::ty_uniq(mt) { is_mut = mt.mut == mut; } ty::ty_uniq(mt) { is_mut = mt.mut == mut; }
ty::ty_res(_, _, _) { } ty::ty_res(_, _, _) { }
ty::ty_enum(_, _) { } ty::ty_enum(_, _) { }
ty::ty_ptr(mt) { is_mut = mt.mut == mut; } ty::ty_ptr(mt) { is_mut = mt.mut == mut; ptr = true; }
} }
ds += [@{mut: is_mut, kind: unbox, outer_t: base_t}]; ds += [@{mut: is_mut, kind: unbox(ptr && is_mut),
outer_t: base_t}];
ex = base; ex = base;
} else { break; } } else { break; }
} }
@ -187,7 +188,7 @@ fn check_lval(cx: @ctx, dest: @expr, msg: msg) {
} else if !root.ds[0].mut { } else if !root.ds[0].mut {
let name = let name =
alt root.ds[0].kind { alt root.ds[0].kind {
mut::unbox { "immutable box" } mut::unbox(_) { "immutable box" }
mut::field { "immutable field" } mut::field { "immutable field" }
mut::index { "immutable vec content" } mut::index { "immutable vec content" }
}; };
@ -212,7 +213,8 @@ fn check_move_rhs(cx: @ctx, src: @expr) {
let root = expr_root(cx.tcx, src, false); let root = expr_root(cx.tcx, src, false);
// Not a path and no-derefs means this is a temporary. // Not a path and no-derefs means this is a temporary.
if vec::len(*root.ds) != 0u { if vec::len(*root.ds) != 0u &&
root.ds[vec::len(*root.ds) - 1u].kind != unbox(true) {
cx.tcx.sess.span_err(src.span, "moving out of a data structure"); cx.tcx.sess.span_err(src.span, "moving out of a data structure");
} }
} }

View file

@ -307,6 +307,14 @@ fn pop<T: copy>(&v: [const T]) -> T {
let e = v[ln]; let e = v[ln];
v = slice(v, 0u, ln); v = slice(v, 0u, ln);
ret e; ret e;
// FIXME use this implementation after the next snapshot (27.01.2012)
/* let new_ln = len(v) - 1u;
assert (new_ln > 0u);
let valptr = ptr::mut_addr_of(v[new_ln]);
let val <- *valptr;
unsafe::set_len(v, new_ln);
val
*/
} }
/* /*