correct used_mut annotations for args, inherited case

This commit is contained in:
Niko Matsakis 2013-04-30 14:07:52 -04:00
parent aa48a170d5
commit 7a0c1ea560
5 changed files with 24 additions and 61 deletions

View File

@ -260,11 +260,21 @@ pub impl<'self> CheckLoanCtxt<'self> {
// and report an error otherwise.
match cmt.mutbl {
mc::McDeclared => {
// OK
// OK, but we have to mark arguments as requiring mut
// if they are assigned (other cases are handled by liveness,
// since we need to distinguish local variables assigned
// once vs those assigned multiple times)
match cmt.cat {
mc::cat_self(*) |
mc::cat_arg(*) => {
mark_variable_as_used_mut(self, cmt);
}
_ => {}
}
}
mc::McInherited => {
// OK, but we may have to add an entry to `used_mut_nodes`
mark_writes_through_upvars_as_used_mut(self, cmt);
mark_variable_as_used_mut(self, cmt);
}
mc::McReadOnly | mc::McImmutable => {
// Subtle: liveness guarantees that immutable local
@ -289,33 +299,28 @@ pub impl<'self> CheckLoanCtxt<'self> {
self, expr, cmt);
}
fn mark_writes_through_upvars_as_used_mut(self: &CheckLoanCtxt,
cmt: mc::cmt) {
fn mark_variable_as_used_mut(self: &CheckLoanCtxt,
cmt: mc::cmt) {
//! If the mutability of the `cmt` being written is inherited
//! from a local variable in another closure, liveness may
//! from a local variable, liveness will
//! not have been able to detect that this variable's mutability
//! is important, so we must add the variable to the
//! `used_mut_nodes` table here. This is because liveness
//! does not consider closures.
//! `used_mut_nodes` table here.
let mut passed_upvar = false;
let mut cmt = cmt;
loop {
debug!("mark_writes_through_upvars_as_used_mut(cmt=%s)",
cmt.repr(self.tcx()));
match cmt.cat {
mc::cat_local(id) |
mc::cat_arg(id, _) |
mc::cat_arg(id) |
mc::cat_self(id) => {
if passed_upvar {
self.tcx().used_mut_nodes.insert(id);
}
self.tcx().used_mut_nodes.insert(id);
return;
}
mc::cat_stack_upvar(b) => {
cmt = b;
passed_upvar = true;
}
mc::cat_rvalue |
@ -552,7 +557,7 @@ pub impl<'self> CheckLoanCtxt<'self> {
match cmt.cat {
// Rvalues, locals, and arguments can be moved:
mc::cat_rvalue | mc::cat_local(_) |
mc::cat_arg(_, ast::by_copy) | mc::cat_self(_) => {}
mc::cat_arg(_) | mc::cat_self(_) => {}
// It seems strange to allow a move out of a static item,
// but what happens in practice is that you have a

View File

@ -255,7 +255,7 @@ impl GuaranteeLifetimeContext {
match cmt.guarantor().cat {
mc::cat_local(id) |
mc::cat_self(id) |
mc::cat_arg(id, _) => {
mc::cat_arg(id) => {
self.bccx.moved_variables_set.contains(&id)
}
mc::cat_rvalue |
@ -292,7 +292,7 @@ impl GuaranteeLifetimeContext {
ty::re_static
}
mc::cat_local(local_id) |
mc::cat_arg(local_id, _) |
mc::cat_arg(local_id) |
mc::cat_self(local_id) => {
self.bccx.tcx.region_maps.encl_region(local_id)
}

View File

@ -27,7 +27,6 @@ use util::common::indenter;
use util::ppaux::{Repr};
use core::hashmap::HashSet;
use core::vec;
use syntax::ast::{m_const, m_imm, m_mutbl};
use syntax::ast;
use syntax::ast_util::id_range;
@ -169,20 +168,6 @@ fn gather_loans_in_expr(ex: @ast::expr,
visit::visit_expr(ex, self, vt);
}
ast::expr_call(f, ref args, _) => {
let arg_tys = ty::ty_fn_args(ty::expr_ty(self.tcx(), f));
self.guarantee_arguments(ex, *args, arg_tys);
visit::visit_expr(ex, self, vt);
}
ast::expr_method_call(_, _, _, ref args, _) => {
let arg_tys = ty::ty_fn_args(ty::node_id_to_type(self.tcx(),
ex.callee_id));
self.guarantee_arguments(ex, *args, arg_tys);
visit::visit_expr(ex, self, vt);
}
ast::expr_match(ex_v, ref arms) => {
let cmt = self.bccx.cat_expr(ex_v);
for arms.each |arm| {
@ -271,30 +256,6 @@ pub impl GatherLoanCtxt {
assert!(id == popped);
}
fn guarantee_arguments(&mut self,
call_expr: @ast::expr,
args: &[@ast::expr],
arg_tys: &[ty::arg]) {
for vec::each2(args, arg_tys) |arg, arg_ty| {
match ty::resolved_mode(self.tcx(), arg_ty.mode) {
ast::by_ref => {
self.guarantee_by_ref_argument(call_expr, *arg);
}
ast::by_copy => {}
}
}
}
fn guarantee_by_ref_argument(&mut self,
call_expr: @ast::expr,
arg_expr: @ast::expr) {
// FIXME(#5074) nested method calls
let scope_r = ty::re_scope(call_expr.id);
let arg_cmt = self.bccx.cat_expr(arg_expr);
self.guarantee_valid(arg_expr.id, arg_expr.span,
arg_cmt, m_imm, scope_r);
}
fn guarantee_adjustments(&mut self,
expr: @ast::expr,
adjustment: &ty::AutoAdjustment) {

View File

@ -15,7 +15,6 @@ use middle::borrowck::*;
use mc = middle::mem_categorization;
use middle::ty;
use syntax::ast::{m_const, m_imm, m_mutbl};
use syntax::ast;
use syntax::codemap::span;
pub enum RestrictionResult {
@ -74,7 +73,7 @@ impl RestrictionsContext {
}
mc::cat_local(local_id) |
mc::cat_arg(local_id, ast::by_copy) |
mc::cat_arg(local_id) |
mc::cat_self(local_id) => {
let lp = @LpVar(local_id);
SafeIf(lp, ~[Restriction {loan_path: lp,
@ -114,7 +113,6 @@ impl RestrictionsContext {
mc::cat_copied_upvar(*) | // FIXME(#2152) allow mutation of upvars
mc::cat_static_item(*) |
mc::cat_implicit_self(*) |
mc::cat_arg(_, ast::by_ref) |
mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) |
mc::cat_deref(_, _, mc::gc_ptr(m_imm)) => {
Safe

View File

@ -242,13 +242,12 @@ pub fn opt_loan_path(cmt: mc::cmt) -> Option<@LoanPath> {
mc::cat_rvalue |
mc::cat_static_item |
mc::cat_copied_upvar(_) |
mc::cat_implicit_self |
mc::cat_arg(_, ast::by_ref) => {
mc::cat_implicit_self => {
None
}
mc::cat_local(id) |
mc::cat_arg(id, ast::by_copy) |
mc::cat_arg(id) |
mc::cat_self(id) => {
Some(@LpVar(id))
}