From 287f163136b2527504162012b94d346f5523eac9 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Thu, 21 Jun 2012 09:41:33 -0700 Subject: [PATCH] Issue #2657: track mutability of bindings, also prevent move from bindings --- src/libsyntax/parse/lexer.rs | 2 +- src/rustc/middle/borrowck.rs | 9 +++++++++ src/rustc/middle/borrowck/categorization.rs | 14 +++++++++----- src/rustc/middle/borrowck/gather_loans.rs | 10 ++++++++++ src/rustc/middle/borrowck/loan.rs | 2 +- src/rustc/middle/borrowck/preserve.rs | 6 ++++++ src/rustc/middle/trans/base.rs | 2 +- src/test/compile-fail/borrowck-binding-mutbl.rs | 13 +++++++++++++ 8 files changed, 50 insertions(+), 8 deletions(-) create mode 100644 src/test/compile-fail/borrowck-binding-mutbl.rs diff --git a/src/libsyntax/parse/lexer.rs b/src/libsyntax/parse/lexer.rs index 14cb8b41473..bbf5330c18a 100644 --- a/src/libsyntax/parse/lexer.rs +++ b/src/libsyntax/parse/lexer.rs @@ -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; diff --git a/src/rustc/middle/borrowck.rs b/src/rustc/middle/borrowck.rs index 2208409ab50..9818c1c648b 100644 --- a/src/rustc/middle/borrowck.rs +++ b/src/rustc/middle/borrowck.rs @@ -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; +// 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; + // 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)] } diff --git a/src/rustc/middle/borrowck/categorization.rs b/src/rustc/middle/borrowck/categorization.rs index cdfb2a08c68..b7143706fc3 100644 --- a/src/rustc/middle/borrowck/categorization.rs +++ b/src/rustc/middle/borrowck/categorization.rs @@ -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} } } } diff --git a/src/rustc/middle/borrowck/gather_loans.rs b/src/rustc/middle/borrowck/gather_loans.rs index 87980bf7248..1745757151c 100644 --- a/src/rustc/middle/borrowck/gather_loans.rs +++ b/src/rustc/middle/borrowck/gather_loans.rs @@ -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| diff --git a/src/rustc/middle/borrowck/loan.rs b/src/rustc/middle/borrowck/loan.rs index ee61dd9f0cf..bbeca851742 100644 --- a/src/rustc/middle/borrowck/loan.rs +++ b/src/rustc/middle/borrowck/loan.rs @@ -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, diff --git a/src/rustc/middle/borrowck/preserve.rs b/src/rustc/middle/borrowck/preserve.rs index 98c9109fe8e..cbe9c4e3a4a 100644 --- a/src/rustc/middle/borrowck/preserve.rs +++ b/src/rustc/middle/borrowck/preserve.rs @@ -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. diff --git a/src/rustc/middle/trans/base.rs b/src/rustc/middle/trans/base.rs index 47baa8aebca..c3ab41636a8 100644 --- a/src/rustc/middle/trans/base.rs +++ b/src/rustc/middle/trans/base.rs @@ -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 { diff --git a/src/test/compile-fail/borrowck-binding-mutbl.rs b/src/test/compile-fail/borrowck-binding-mutbl.rs new file mode 100644 index 00000000000..183106aa28e --- /dev/null +++ b/src/test/compile-fail/borrowck-binding-mutbl.rs @@ -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 + } + } +} \ No newline at end of file