Issue #2657: track mutability of bindings, also prevent move from bindings

This commit is contained in:
Niko Matsakis 2012-06-21 09:41:33 -07:00
parent c3d384b18f
commit 287f163136
8 changed files with 50 additions and 8 deletions

View File

@ -154,7 +154,7 @@ fn tt_next_token(&&r: tt_reader) -> {tok: token::token, sp: span} {
ret ret_val;
}
tt_frame_up(option::some(tt_f)) {
r.cur <- tt_f;
r.cur = tt_f;
/* the above `if` would need to be a `while` if we didn't know
that the last thing in a `tt_delim` is always a `tt_flat` */
r.cur.idx += 1u;

View File

@ -175,6 +175,7 @@ fn check_crate(tcx: ty::ctxt,
let bccx = @{tcx: tcx,
method_map: method_map,
last_use_map: last_use_map,
binding_map: int_hash(),
root_map: root_map(),
mutbl_map: int_hash()};
@ -189,6 +190,7 @@ fn check_crate(tcx: ty::ctxt,
type borrowck_ctxt = @{tcx: ty::ctxt,
method_map: typeck::method_map,
last_use_map: liveness::last_use_map,
binding_map: binding_map,
root_map: root_map,
mutbl_map: mutbl_map};
@ -208,6 +210,10 @@ type root_map_key = {id: ast::node_id, derefs: uint};
// this is used in trans for optimization purposes.
type mutbl_map = std::map::hashmap<ast::node_id, ()>;
// maps from each binding's id to the mutability of the location it
// points at. See gather_loan.rs for more detail (search for binding_map)
type binding_map = std::map::hashmap<ast::node_id, ast::mutability>;
// Errors that can occur"]
enum bckerr_code {
err_mut_uniq,
@ -228,6 +234,7 @@ enum categorization {
cat_rvalue, // result of eval'ing some misc expr
cat_special(special_kind), //
cat_local(ast::node_id), // local variable
cat_binding(ast::node_id), // pattern binding
cat_arg(ast::node_id), // formal argument
cat_stack_upvar(cmt), // upvar in stack closure
cat_deref(cmt, uint, ptr_kind), // deref of a ptr
@ -381,6 +388,7 @@ impl to_str_methods for borrowck_ctxt {
cat_stack_upvar(_) { "stack-upvar" }
cat_rvalue { "rvalue" }
cat_local(node_id) { #fmt["local(%d)", node_id] }
cat_binding(node_id) { #fmt["binding(%d)", node_id] }
cat_arg(node_id) { #fmt["arg(%d)", node_id] }
cat_deref(cmt, derefs, ptr) {
#fmt["%s->(%s, %u)", self.cat_to_repr(cmt.cat),
@ -466,6 +474,7 @@ impl to_str_methods for borrowck_ctxt {
cat_special(sk_heap_upvar) { "variable declared in an outer block" }
cat_rvalue { "non-lvalue" }
cat_local(_) { mut_str + " local variable" }
cat_binding(_) { "pattern binding" }
cat_arg(_) { "argument" }
cat_deref(_, _, pk) { #fmt["dereference of %s %s pointer",
mut_str, self.pk_to_sigil(pk)] }

View File

@ -265,12 +265,16 @@ impl public_methods for borrowck_ctxt {
mutbl:m, ty:expr_ty}
}
ast::def_binding(vid) {
// no difference between a binding and any other local variable
// from out point of view, except that they are always immutable
ast::def_binding(pid) {
// bindings are "special" since they are implicit pointers.
// lookup the mutability for this binding that we found in
// gather_loans when we categorized it
let mutbl = self.binding_map.get(pid);
@{id:id, span:span,
cat:cat_local(vid), lp:some(@lp_local(vid)),
mutbl:m_imm, ty:expr_ty}
cat:cat_binding(pid), lp:none,
mutbl:mutbl, ty:expr_ty}
}
}
}

View File

@ -364,6 +364,16 @@ impl methods for gather_loan_ctxt {
// cat_discr in the method preserve():
let cmt1 = self.bccx.cat_discr(cmt, alt_id);
let arm_scope = ty::re_scope(arm_id);
// Remember the mutability of the location that this
// binding refers to. This will be used later when
// categorizing the binding. This is a bit of a hack that
// would be better fixed by #2329; in that case we could
// allow the user to specify if they want an imm, const,
// or mut binding, or else just reflect the mutability
// through the type of the region pointer.
self.bccx.binding_map.insert(pat.id, cmt1.mutbl);
self.guarantee_valid(cmt1, m_const, arm_scope);
for o_pat.each { |p|

View File

@ -43,7 +43,7 @@ impl loan_methods for loan_ctxt {
}
alt cmt.cat {
cat_rvalue | cat_special(_) {
cat_binding(_) | cat_rvalue | cat_special(_) {
// should never be loanable
self.bccx.tcx.sess.span_bug(
cmt.span,

View File

@ -29,6 +29,12 @@ impl public_methods for borrowck_ctxt {
}
ok(())
}
cat_binding(_) {
// Bindings are these kind of weird implicit pointers (cc
// #2329). We require (in gather_loans) that they be
// rooted in an immutable location.
ok(())
}
cat_arg(_) {
// This can happen as not all args are lendable (e.g., &&
// modes). In that case, the caller guarantees stability.

View File

@ -3335,7 +3335,7 @@ fn need_invoke(bcx: block) -> bool {
loop {
alt cur.kind {
block_scope(inf) {
for inf.cleanups.each {|cleanup|
for vec::each(inf.cleanups) {|cleanup|
alt cleanup {
clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) {
if cleanup_type == normal_exit_and_unwind {

View File

@ -0,0 +1,13 @@
fn impure(_v: [int]) {
}
fn main() {
let x = {mut f: [3]};
alt x {
{f: v} => {
impure(v); //! ERROR illegal borrow unless pure: unique value in aliasable, mutable location
//!^ NOTE impure due to access to impure function
}
}
}