Skip to content

Commit 2f40234

Browse files
committed
Make for loop alias-safe
1 parent 3e92f90 commit 2f40234

File tree

5 files changed

+46
-54
lines changed

5 files changed

+46
-54
lines changed

src/comp/middle/alias.rs

Lines changed: 28 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,12 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> copy_map {
5959
fn visit_fn(f: ast::_fn, _tp: [ast::ty_param], _sp: span, _name: fn_ident,
6060
_id: ast::node_id, sc: scope, v: vt<scope>) {
6161
visit::visit_fn_decl(f.decl, sc, v);
62-
let scope =
63-
alt f.proto {
64-
65-
66-
67-
// Blocks need to obey any restrictions from the enclosing scope.
68-
ast::proto_block. | ast::proto_closure. {
69-
sc
70-
}
71-
72-
73-
74-
// Non capturing functions start out fresh.
75-
_ {
76-
@[]
77-
}
78-
};
62+
let scope = alt f.proto {
63+
// Blocks need to obey any restrictions from the enclosing scope.
64+
ast::proto_block. | ast::proto_closure. { sc }
65+
// Non capturing functions start out fresh.
66+
_ { @[] }
67+
};
7968
v.visit_block(f.body, scope, v);
8069
}
8170

@@ -279,7 +268,7 @@ fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
279268
type info = {id: node_id, mutable unsafe: [ty::t], span: span};
280269
let binding_info: [info] = [];
281270
for pat in a.pats {
282-
for proot in *pattern_roots(cx.tcx, root.ds, pat) {
271+
for proot in *pattern_roots(cx.tcx, *root.ds, pat) {
283272
let canon_id = pat_id_map.get(proot.name);
284273
// FIXME I wanted to use a block, but that hit a
285274
// typestate bug.
@@ -327,33 +316,34 @@ fn check_for(cx: ctx, local: @ast::local, seq: @ast::expr, blk: ast::blk,
327316
sc: scope, v: vt<scope>) {
328317
v.visit_expr(seq, sc, v);
329318
let root = expr_root(cx.tcx, seq, false);
330-
let unsafe = inner_mut(root.ds);
331319

332320
// If this is a mutable vector, don't allow it to be touched.
333321
let seq_t = ty::expr_ty(cx.tcx, seq);
334-
let elt_t;
322+
let ext_ds = *root.ds;
335323
alt ty::struct(cx.tcx, seq_t) {
336324
ty::ty_vec(mt) {
337-
if mt.mut != ast::imm { unsafe = [seq_t]; }
338-
elt_t = mt.ty;
325+
if mt.mut != ast::imm {
326+
ext_ds += [@{mut: true, kind: index, outer_t: seq_t}];
327+
}
339328
}
340-
ty::ty_str. { elt_t = ty::mk_mach(cx.tcx, ast::ty_u8); }
329+
_ {}
341330
}
342331
let root_var = path_def_id(cx, root.ex);
343-
let new_sc =
344-
@{root_var: root_var,
345-
// FIXME reenable when trans knows how to copy for vars
346-
node_id: 0, // blk.node.id,
347-
ty: elt_t,
348-
span: local.node.pat.span,
349-
local_id: cx.next_local,
350-
bindings: ast_util::pat_binding_ids(local.node.pat),
351-
unsafe_tys: unsafe,
352-
depends_on: deps(sc, root_var),
353-
mutable ok: valid,
354-
mutable given_up: false};
332+
let new_sc = *sc;
333+
for proot in *pattern_roots(cx.tcx, ext_ds, local.node.pat) {
334+
new_sc += [@{root_var: root_var,
335+
node_id: proot.id,
336+
ty: ty::node_id_to_type(cx.tcx, proot.id),
337+
span: proot.span,
338+
local_id: cx.next_local,
339+
bindings: [proot.id],
340+
unsafe_tys: inner_mut(proot.ds),
341+
depends_on: deps(sc, root_var),
342+
mutable ok: valid,
343+
mutable given_up: false}];
344+
}
355345
register_locals(cx, local.node.pat);
356-
visit::visit_block(blk, @(*sc + [new_sc]), v);
346+
visit::visit_block(blk, @new_sc, v);
357347
}
358348

359349
fn check_var(cx: ctx, ex: @ast::expr, p: ast::path, id: ast::node_id,
@@ -555,7 +545,7 @@ fn copy_is_expensive(tcx: ty::ctxt, ty: ty::t) -> bool {
555545

556546
type pattern_root = {id: node_id, name: ident, ds: @[deref], span: span};
557547

558-
fn pattern_roots(tcx: ty::ctxt, base: @[deref], pat: @ast::pat)
548+
fn pattern_roots(tcx: ty::ctxt, base: [deref], pat: @ast::pat)
559549
-> @[pattern_root] {
560550
fn walk(tcx: ty::ctxt, base: [deref], pat: @ast::pat,
561551
&set: [pattern_root]) {
@@ -587,7 +577,7 @@ fn pattern_roots(tcx: ty::ctxt, base: @[deref], pat: @ast::pat)
587577
}
588578
}
589579
let set = [];
590-
walk(tcx, *base, pat, set);
580+
walk(tcx, base, pat, set);
591581
ret @set;
592582
}
593583

src/comp/middle/trans.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2418,22 +2418,16 @@ fn trans_if(cx: @block_ctxt, cond: @ast::expr, thn: ast::blk,
24182418

24192419
fn trans_for(cx: @block_ctxt, local: @ast::local, seq: @ast::expr,
24202420
body: ast::blk) -> result {
2421-
fn inner(cx: @block_ctxt, local: @ast::local, curr: ValueRef, t: ty::t,
2421+
fn inner(bcx: @block_ctxt, local: @ast::local, curr: ValueRef, t: ty::t,
24222422
body: ast::blk, outer_next_cx: @block_ctxt) -> @block_ctxt {
2423-
let next_cx = new_sub_block_ctxt(cx, "next");
2423+
let next_cx = new_sub_block_ctxt(bcx, "next");
24242424
let scope_cx =
2425-
new_loop_scope_block_ctxt(cx,
2426-
option::some::<@block_ctxt>(next_cx),
2425+
new_loop_scope_block_ctxt(bcx, option::some(next_cx),
24272426
outer_next_cx, "for loop scope");
2428-
Br(cx, scope_cx.llbb);
2429-
let {bcx: bcx, val: dst} = alloc_local(scope_cx, local);
2430-
let val =
2431-
load_if_immediate(bcx, PointerCast(bcx, curr, val_ty(dst)), t);
2432-
let bcx = copy_val(bcx, INIT, dst, val, t);
2433-
add_clean(scope_cx, dst, t);
2434-
let bcx =
2435-
trans_alt::bind_irrefutable_pat(bcx, local.node.pat, dst,
2436-
cx.fcx.lllocals, false);
2427+
Br(bcx, scope_cx.llbb);
2428+
curr = PointerCast(bcx, curr, T_ptr(type_of_or_i8(bcx, t)));
2429+
bcx = trans_alt::bind_irrefutable_pat(scope_cx, local.node.pat, curr,
2430+
bcx.fcx.lllocals, false);
24372431
bcx = trans_block(bcx, body, return).bcx;
24382432
if !is_terminated(bcx) {
24392433
Br(bcx, next_cx.llbb);

src/comp/middle/trans_alt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,7 @@ fn bind_irrefutable_pat(bcx: @block_ctxt, pat: @ast::pat, val: ValueRef,
571571
let ccx = bcx.fcx.lcx.ccx;
572572
alt pat.node {
573573
ast::pat_bind(_) {
574-
if make_copy {
574+
if make_copy || ccx.copy_map.contains_key(pat.id) {
575575
let ty = ty::node_id_to_monotype(ccx.tcx, pat.id);
576576
// FIXME: Could constrain pat_bind to make this
577577
// check unnecessary.

src/test/compile-fail/unsafe-for.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// error-pattern:invalidate reference x
22

33
fn main() {
4-
let v: [mutable int] = [mutable 1, 2, 3];
5-
for x: int in v { v[0] = 10; log x; }
4+
let v: [mutable {mutable x: int}] = [mutable {mutable x: 1}];
5+
for x in v { v[0] = {mutable x: 2}; log x; }
66
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
fn main() {
2+
let x = [@{mutable a: @10, b: @20}];
3+
for @{a, b} in x {
4+
assert *a == 10;
5+
(*x[0]).a = @30;
6+
assert *a == 10;
7+
}
8+
}

0 commit comments

Comments
 (0)