Skip to content

mode: reset mode on entry to fn body. #4416

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/libcore/condition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl<T, U> Condition<T, U> {

fn raise(t: T) -> U {
let msg = fmt!("Unhandled condition: %s: %?", self.name, t);
self.raise_default(t, || fail msg)
self.raise_default(t, || fail copy msg)
}

fn raise_default(t: T, default: &fn() -> U) -> U {
Expand Down
23 changes: 21 additions & 2 deletions src/librustc/middle/mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,29 @@ use syntax::ast::{expr_binary, expr_call, expr_copy, expr_field, expr_index};
use syntax::ast::{expr_match, expr_method_call, expr_paren, expr_path};
use syntax::ast::{expr_swap, expr_unary, neg, node_id, not, pat, pat_ident};
use syntax::ast::{sty_uniq, sty_value, uniq};
use syntax::ast::{fn_decl, blk};
use syntax::visit;
use syntax::visit::vt;
use syntax::visit::{fn_kind, vt};
use syntax::print::pprust;
use syntax::codemap::span;

struct VisitContext {
tcx: ctxt,
method_map: HashMap<node_id,method_map_entry>,
mode: ValueMode,
}

fn compute_modes_for_fn(fk: fn_kind,
decl: fn_decl,
body: blk,
sp: span,
id: node_id,
&&cx: VisitContext,
v: vt<VisitContext>) {
let body_cx = VisitContext { mode: MoveValue, ..cx };
visit::visit_fn(fk, decl, body, sp, id, body_cx, v);
}

fn compute_modes_for_fn_args(callee_id: node_id,
args: &[@expr],
last_arg_is_block: bool,
Expand Down Expand Up @@ -79,6 +93,10 @@ fn record_mode_for_expr(expr: @expr, &&cx: VisitContext) {
fn compute_modes_for_expr(expr: @expr,
&&cx: VisitContext,
v: vt<VisitContext>) {
debug!("compute_modes_for_expr(expr=%?/%s, mode=%?)",
expr.id, pprust::expr_to_str(expr, cx.tcx.sess.intr()),
cx.mode);

// Adjust the mode if there was an implicit reference here.
let cx = match cx.tcx.adjustments.find(expr.id) {
None => cx,
Expand All @@ -91,7 +109,7 @@ fn compute_modes_for_expr(expr: @expr,
}
};

match /*bad*/copy expr.node {
match copy expr.node {
expr_call(callee, args, is_block) => {
let callee_cx = VisitContext { mode: ReadValue, ..cx };
compute_modes_for_expr(callee, callee_cx, v);
Expand Down Expand Up @@ -235,6 +253,7 @@ fn compute_modes_for_pat(pat: @pat,

pub fn compute_modes(tcx: ctxt, method_map: method_map, crate: @crate) {
let visitor = visit::mk_vt(@visit::Visitor {
visit_fn: compute_modes_for_fn,
visit_expr: compute_modes_for_expr,
visit_pat: compute_modes_for_pat,
.. *visit::default_visitor()
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id,
match csearch::maybe_get_item_ast(
ccx.tcx, fn_id,
|a,b,c,d| {
astencode::decode_inlined_item(a, b, ccx.maps, c, d)
astencode::decode_inlined_item(a, b, ccx.maps, /*bad*/ copy c, d)
}) {

csearch::not_found => {
Expand Down
32 changes: 12 additions & 20 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1507,12 +1507,12 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
// resolution is not possible (e.g., no constraints yet present), just
// returns `none`.
fn unpack_expected<O: Copy>(fcx: @fn_ctxt, expected: Option<ty::t>,
unpack: fn(ty::sty) -> Option<O>)
unpack: fn(&ty::sty) -> Option<O>)
-> Option<O> {
match expected {
Some(t) => {
match resolve_type(fcx.infcx(), t, force_tvar) {
Ok(t) => unpack(ty::get(t).sty),
Ok(t) => unpack(&ty::get(t).sty),
_ => None
}
}
Expand All @@ -1537,7 +1537,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
// to impure and block. Note that we only will use those for
// block syntax lambdas; that is, lambdas without explicit
// protos.
let expected_sty = unpack_expected(fcx, expected, |x| Some(x));
let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
let (expected_tys,
expected_purity,
expected_proto,
Expand Down Expand Up @@ -1969,8 +1969,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
ast::expr_unary(unop, oprnd) => {
let exp_inner = do unpack_expected(fcx, expected) |sty| {
match unop {
ast::box(_) | ast::uniq(_) => match sty {
ty::ty_box(mt) | ty::ty_uniq(mt) => Some(mt.ty),
ast::box(_) | ast::uniq(_) => match *sty {
ty::ty_box(ref mt) | ty::ty_uniq(ref mt) => Some(mt.ty),
_ => None
},
ast::not | ast::neg => expected,
Expand Down Expand Up @@ -2050,8 +2050,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
fcx.write_ty(id, oprnd_t);
}
ast::expr_addr_of(mutbl, oprnd) => {
bot = check_expr(fcx, oprnd, unpack_expected(fcx, expected, |ty|
match ty { ty::ty_rptr(_, mt) => Some(mt.ty), _ => None }
bot = check_expr(fcx, oprnd, unpack_expected(fcx, expected, |sty|
match *sty { ty::ty_rptr(_, ref mt) => Some(mt.ty), _ => None }
));

// Note: at this point, we cannot say what the best lifetime
Expand Down Expand Up @@ -2177,7 +2177,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
// 1. a closure that returns a bool is expected
// 2. the closure that was given returns unit
let mut err_happened = false;
let expected_sty = unpack_expected(fcx, expected, |x| Some(x));
let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
let inner_ty = match expected_sty {
Some(ty::ty_fn(ref fty)) => {
match fcx.mk_subty(false, expr.span,
Expand Down Expand Up @@ -2240,7 +2240,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
}
}
ast::expr_do_body(b) => {
let expected_sty = unpack_expected(fcx, expected, |x| Some(x));
let expected_sty = unpack_expected(fcx, expected, |x| Some(copy *x));
let inner_ty = match expected_sty {
Some(ty::ty_fn(ref fty)) => {
ty::mk_fn(tcx, (/*bad*/copy *fty))
Expand Down Expand Up @@ -2349,11 +2349,7 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
}
ast::expr_tup(elts) => {
let flds = unpack_expected(fcx, expected, |sty| {
// XXX: Beware! If you remove `copy` below, the borrow checker
// will NOT complain, but you will get a segfault at runtime! This
// is because the mode computation is currently unaware of
// argument modes.
match copy sty { ty::ty_tup(flds) => Some(flds), _ => None }
match *sty { ty::ty_tup(ref flds) => Some(copy *flds), _ => None }
});
let elt_ts = do elts.mapi |i, e| {
check_expr(fcx, *e, flds.map(|fs| fs[i]));
Expand All @@ -2368,12 +2364,8 @@ fn check_expr_with_unifier(fcx: @fn_ctxt,
Some(fcx.expr_ty(base.get()))
} else { expected };
let flds = unpack_expected(fcx, expected, |sty|
// XXX: Beware! If you remove `copy` below, the borrow checker
// will NOT complain, but you will get a segfault at runtime! This
// is because the mode computation is currently unaware of
// argument modes.
match copy sty {
ty::ty_rec(flds) => Some(flds),
match *sty {
ty::ty_rec(ref flds) => Some(copy *flds),
_ => None
}
);
Expand Down
10 changes: 10 additions & 0 deletions src/test/compile-fail/access-mode-in-closures.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
enum sty = ~[int];

fn unpack(unpack: &fn(v: &sty) -> ~[int]) {}

fn main() {
let foo = unpack(|s| {
// Test that `s` is moved here.
match *s { sty(v) => v } //~ ERROR moving out of dereference of immutable & pointer
});
}