Issue #2657: track mutability of bindings, also prevent move from bindings
This commit is contained in:
parent
c3d384b18f
commit
287f163136
|
@ -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;
|
||||
|
|
|
@ -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)] }
|
||||
|
|
|
@ -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}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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|
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue