Skip to content

Commit 4f4a468

Browse files
committed
Forbid deinitializing upvars in typestate
Closes #1965.
1 parent 46e358f commit 4f4a468

File tree

3 files changed

+48
-15
lines changed

3 files changed

+48
-15
lines changed

src/rustc/middle/tstate/auxiliary.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,12 @@ fn find_instance_(pattern: [constr_arg_general_<inst>], descs: [pred_args]) ->
710710
}
711711

712712
type inst = {ident: ident, node: node_id};
713+
714+
enum dest {
715+
local_dest(inst), // RHS is assigned to a local variable
716+
call // RHS is passed to a function
717+
}
718+
713719
type subst = [{from: inst, to: inst}];
714720

715721
fn find_instances(_fcx: fn_ctxt, subst: subst, c: constraint) ->
@@ -1064,12 +1070,12 @@ fn ast_constr_to_sp_constr(tcx: ty::ctxt, args: [arg], c: @constr) ->
10641070
ret respan(c.span, tconstr);
10651071
}
10661072

1067-
type binding = {lhs: [inst], rhs: option<initializer>};
1073+
type binding = {lhs: [dest], rhs: option<initializer>};
10681074

10691075
fn local_to_bindings(tcx: ty::ctxt, loc: @local) -> binding {
10701076
let mut lhs = [];
10711077
pat_bindings(tcx.def_map, loc.node.pat) {|p_id, _s, name|
1072-
lhs += [{ident: path_to_ident(name), node: p_id}];
1078+
lhs += [local_dest({ident: path_to_ident(name), node: p_id})];
10731079
};
10741080
{lhs: lhs, rhs: loc.node.init}
10751081
}
@@ -1106,12 +1112,12 @@ fn callee_arg_init_ops(fcx: fn_ctxt, callee: node_id) -> [init_op] {
11061112
}
11071113
}
11081114

1109-
fn anon_bindings(ops: [init_op], es: [@expr]) -> [binding] {
1115+
fn arg_bindings(ops: [init_op], es: [@expr]) -> [binding] {
11101116
let mut bindings: [binding] = [];
1111-
let mut i = 0;
1117+
let mut i = 0u;
11121118
for ops.each {|op|
1113-
bindings += [{lhs: [], rhs: some({op: op, expr: es[i]})}];
1114-
i += 1;
1119+
bindings += [{lhs: [call], rhs: some({op: op, expr: es[i]})}];
1120+
i += 1u;
11151121
}
11161122
ret bindings;
11171123
}

src/rustc/middle/tstate/states.rs

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import driver::session::session;
1313
import std::map::hashmap;
1414

1515
fn forbid_upvar(fcx: fn_ctxt, rhs_id: node_id, sp: span, t: oper_type) {
16+
// fcx.ccx.tcx.sess.span_note(sp,
17+
// #fmt("forbid_upvar: checking. %?", t));
18+
1619
alt t {
1720
oper_move {
1821
alt local_node_id_to_def(fcx, rhs_id) {
@@ -29,7 +32,7 @@ fn forbid_upvar(fcx: fn_ctxt, rhs_id: node_id, sp: span, t: oper_type) {
2932
}
3033

3134
fn handle_move_or_copy(fcx: fn_ctxt, post: poststate, rhs_path: @path,
32-
rhs_id: node_id, instlhs: inst, init_op: init_op) {
35+
rhs_id: node_id, destlhs: dest, init_op: init_op) {
3336
forbid_upvar(fcx, rhs_id, rhs_path.span, op_to_oper_ty(init_op));
3437

3538
let rhs_d_id = local_node_id_to_def_id(fcx, rhs_id);
@@ -38,8 +41,13 @@ fn handle_move_or_copy(fcx: fn_ctxt, post: poststate, rhs_path: @path,
3841
// RHS is a local var
3942
let instrhs =
4043
{ident: path_to_ident(rhs_path), node: rhsid.node};
41-
copy_in_poststate(fcx, post, instlhs, instrhs,
42-
op_to_oper_ty(init_op));
44+
alt destlhs {
45+
local_dest(instlhs) {
46+
copy_in_poststate(fcx, post, instlhs, instrhs,
47+
op_to_oper_ty(init_op));
48+
}
49+
_ {}
50+
}
4351
}
4452
_ {
4553
// not a local -- do nothing
@@ -74,15 +82,20 @@ fn seq_states(fcx: fn_ctxt, pres: prestate, bindings: [binding]) ->
7482
changed |=
7583
find_pre_post_state_expr(fcx, post, an_init.expr) || changed;
7684
post = tritv_clone(expr_poststate(fcx.ccx, an_init.expr));
77-
for b.lhs.each {|i|
85+
for b.lhs.each {|d|
7886
alt an_init.expr.node {
7987
expr_path(p) {
80-
handle_move_or_copy(fcx, post, p, an_init.expr.id, i,
88+
handle_move_or_copy(fcx, post, p, an_init.expr.id, d,
8189
an_init.op);
8290
}
8391
_ { }
8492
}
85-
set_in_poststate_ident(fcx, i.node, i.ident, post);
93+
alt d {
94+
local_dest(i) {
95+
set_in_poststate_ident(fcx, i.node, i.ident, post);
96+
}
97+
_ {}
98+
}
8699
}
87100

88101
// Forget the RHS if we just moved it.
@@ -91,9 +104,14 @@ fn seq_states(fcx: fn_ctxt, pres: prestate, bindings: [binding]) ->
91104
}
92105
}
93106
none {
94-
for b.lhs.each {|i|
107+
for b.lhs.each {|d|
95108
// variables w/o an initializer
96-
clear_in_poststate_ident_(fcx, i.node, i.ident, post);
109+
alt check d {
110+
// would be an error to pass something uninit'd to a call
111+
local_dest(i) {
112+
clear_in_poststate_ident_(fcx, i.node, i.ident, post);
113+
}
114+
}
97115
}
98116
}
99117
}
@@ -198,7 +216,7 @@ fn find_pre_post_state_call(fcx: fn_ctxt, pres: prestate, a: @expr,
198216
fn find_pre_post_state_exprs(fcx: fn_ctxt, pres: prestate, id: node_id,
199217
ops: [init_op], es: [@expr], cf: ret_style) ->
200218
bool {
201-
let rs = seq_states(fcx, pres, anon_bindings(ops, es));
219+
let rs = seq_states(fcx, pres, arg_bindings(ops, es));
202220
let mut changed = rs.changed | set_prestate_ann(fcx.ccx, id, pres);
203221
/* if this is a failing call, it sets everything as initialized */
204222
alt cf {
@@ -371,6 +389,8 @@ fn find_pre_post_state_expr(fcx: fn_ctxt, pres: prestate, e: @expr) -> bool {
371389
return_val);
372390
}
373391
expr_call(operator, operands, _) {
392+
#debug("hey it's a call");
393+
log_expr(*e);
374394
ret find_pre_post_state_call(fcx, pres, operator, e.id,
375395
callee_arg_init_ops(fcx, operator.id),
376396
operands,

src/test/compile-fail/issue-1965.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// error-pattern:tried to deinitialize a variable declared in a different
2+
fn test(-x: uint) {}
3+
4+
fn main() {
5+
let i = 3u;
6+
uint::range(0u, 10u) {|_x| test(i)}
7+
}

0 commit comments

Comments
 (0)