Skip to content

Commit 73d6df3

Browse files
committed
Emergency safe-ref-checker maintenance
It still has some big problems, but at least it more or less understands block arguments now. Closes #1925
1 parent b5a4fa9 commit 73d6df3

File tree

2 files changed

+92
-82
lines changed

2 files changed

+92
-82
lines changed

src/rustc/middle/alias.rs

Lines changed: 91 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,8 @@ fn visit_expr(cx: @ctx, ex: @ast::expr, sc: scope, v: vt<scope>) {
9999
let mut handled = true;
100100
alt ex.node {
101101
ast::expr_call(f, args, _) {
102-
check_call(*cx, sc, f, args);
103-
handled = false;
102+
check_call(cx, sc, f, args, v);
103+
visit_expr(cx, f, sc, v);
104104
}
105105
ast::expr_alt(input, arms, _) { check_alt(*cx, input, arms, sc, v); }
106106
ast::expr_for(decl, seq, blk) {
@@ -163,33 +163,6 @@ fn visit_block(cx: @ctx, b: ast::blk, sc: scope, v: vt<scope>) {
163163
visit::visit_expr_opt(b.node.expr, sc, v);
164164
}
165165

166-
fn add_bindings_for_let(cx: ctx, &bs: [binding], loc: @ast::local) {
167-
alt loc.node.init {
168-
some(init) {
169-
if init.op == ast::init_move {
170-
err(cx, loc.span, "can not move into a by-reference binding");
171-
}
172-
let root = expr_root(cx, init.expr, false);
173-
let root_var = path_def_id(cx, root.ex);
174-
if is_none(root_var) {
175-
err(cx, loc.span, "a reference binding can't be \
176-
rooted in a temporary");
177-
}
178-
for proot in pattern_roots(cx.tcx, root.mutbl, loc.node.pat) {
179-
let bnd = mk_binding(cx, proot.id, proot.span, root_var,
180-
unsafe_set(proot.mutbl));
181-
// Don't implicitly copy explicit references
182-
bnd.copied = not_allowed;
183-
bs += [bnd];
184-
}
185-
}
186-
_ {
187-
err(cx, loc.span, "by-reference bindings must be initialized");
188-
}
189-
}
190-
}
191-
192-
193166
fn cant_copy(cx: ctx, b: binding) -> bool {
194167
alt b.copied {
195168
not_allowed { ret true; }
@@ -209,47 +182,67 @@ fn cant_copy(cx: ctx, b: binding) -> bool {
209182
} else { ret true; }
210183
}
211184

212-
fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
213-
-> [binding] {
185+
// FIXME this is a really awful hack
186+
fn local_id_for_args(cx: ctx, args: [@ast::expr]) -> uint {
187+
for vec::each(args) {|arg|
188+
alt arg.node {
189+
ast::expr_fn_block(decl, _) | ast::expr_fn(_, decl, _, _) |
190+
ast::expr_loop_body(@{node: ast::expr_fn_block(decl, _), _}) {
191+
if decl.inputs.len() > 0u {
192+
ret local_id_of_node(cx, decl.inputs[0].id);
193+
}
194+
}
195+
_ {}
196+
}
197+
}
198+
0xFFFFFFFFu
199+
}
200+
201+
fn check_call(cx: @ctx, sc: scope, f: @ast::expr, args: [@ast::expr],
202+
v: vt<scope>) {
214203
let fty = ty::expr_ty(cx.tcx, f);
215204
let arg_ts = ty::ty_fn_args(fty);
216-
let mut mut_roots: [{arg: uint, node: node_id}] = [];
205+
let mut mut_roots: [{arg: @ast::expr, node: node_id}] = [];
217206
let mut bindings = [];
218-
let mut i = 0u;
219-
for arg_t: ty::arg in arg_ts {
220-
let arg = args[i];
221-
let root = expr_root(cx, arg, false);
207+
let mut blocks = [], loc_id = local_id_for_args(*cx, args);
208+
vec::iter2(args, arg_ts) {|arg, arg_t|
209+
let root = expr_root(*cx, arg, false);
222210
alt ty::resolved_mode(cx.tcx, arg_t.mode) {
223211
ast::by_mutbl_ref {
224-
alt path_def(cx, arg) {
212+
alt path_def(*cx, arg) {
225213
some(def) {
226214
let dnum = ast_util::def_id_of_def(def).node;
227-
mut_roots += [{arg: i, node: dnum}];
215+
mut_roots += [{arg: arg, node: dnum}];
228216
}
229217
_ { }
230218
}
231219
}
232-
ast::by_ref | ast::by_val | ast::by_move | ast::by_copy { }
220+
ast::by_ref | ast::by_val | ast::by_move | ast::by_copy {}
221+
}
222+
alt arg.node {
223+
ast::expr_fn_block(_, _) { blocks += [arg]; }
224+
ast::expr_loop_body(b) { blocks += [b]; }
225+
_ {
226+
let root_var = path_def_id(*cx, root.ex);
227+
let arg_copied = alt ty::resolved_mode(cx.tcx, arg_t.mode) {
228+
ast::by_move | ast::by_copy { copied }
229+
ast::by_mutbl_ref { not_allowed }
230+
ast::by_ref | ast::by_val { not_copied }
231+
};
232+
visit_expr(cx, arg, sc, v);
233+
bindings += [@{node_id: arg.id,
234+
span: arg.span,
235+
root_var: root_var,
236+
local_id: loc_id,
237+
unsafe_tys: unsafe_set(root.mutbl),
238+
mut copied: arg_copied}];
239+
}
233240
}
234-
let root_var = path_def_id(cx, root.ex);
235-
let arg_copied = alt ty::resolved_mode(cx.tcx, arg_t.mode) {
236-
ast::by_move | ast::by_copy { copied }
237-
ast::by_mutbl_ref { not_allowed }
238-
ast::by_ref | ast::by_val { not_copied }
239-
};
240-
bindings += [@{node_id: arg.id,
241-
span: arg.span,
242-
root_var: root_var,
243-
local_id: 0u,
244-
unsafe_tys: unsafe_set(root.mutbl),
245-
mut copied: arg_copied}];
246-
i += 1u;
247241
}
248-
let f_may_close =
249-
alt f.node {
250-
ast::expr_path(_) { def_is_local_or_self(cx.tcx.def_map.get(f.id)) }
251-
_ { true }
252-
};
242+
let f_may_close = alt f.node {
243+
ast::expr_path(_) { def_is_local_or_self(cx.tcx.def_map.get(f.id)) }
244+
_ { true }
245+
};
253246
if f_may_close {
254247
let mut i = 0u;
255248
for b in bindings {
@@ -264,43 +257,44 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
264257
}
265258
_ {}
266259
}
267-
if unsfe && cant_copy(cx, b) {
268-
err(cx, f.span, #fmt["function may alias with argument \
269-
%u, which is not immutably rooted", i]);
260+
if unsfe && cant_copy(*cx, b) {
261+
err(*cx, f.span, #fmt["function may alias with argument \
262+
%u, which is not immutably rooted", i]);
270263
}
271264
i += 1u;
272265
}
273266
}
274267
let mut j = 0u;
275268
for b in bindings {
276269
for unsafe_ty in b.unsafe_tys {
277-
let mut i = 0u;
278-
for arg_t: ty::arg in arg_ts {
270+
vec::iteri(arg_ts) {|i, arg_t|
279271
let mut_alias =
280272
(ast::by_mutbl_ref == ty::arg_mode(cx.tcx, arg_t));
281-
if i != j &&
282-
ty_can_unsafely_include(cx, unsafe_ty, arg_t.ty,
283-
mut_alias) &&
284-
cant_copy(cx, b) {
285-
err(cx, args[i].span,
286-
#fmt["argument %u may alias with argument %u, \
287-
which is not immutably rooted", i, j]);
273+
alt args[i].node {
274+
ast::expr_fn_block(_, _) | ast::expr_loop_body(_) {}
275+
_ {
276+
if i != j && ty_can_unsafely_include(
277+
*cx, unsafe_ty, arg_t.ty, mut_alias) &&
278+
cant_copy(*cx, b) {
279+
err(*cx, args[i].span,
280+
#fmt["argument %u may alias with argument %u, \
281+
which is not immutably rooted", i, j]);
282+
}
283+
}
288284
}
289-
i += 1u;
290285
}
291286
}
292287
j += 1u;
293288
}
294-
// Ensure we're not passing a root by mut alias.
295289

290+
// Ensure we're not passing a root by mut alias.
296291
for {node: node, arg: arg} in mut_roots {
297-
let mut i = 0u;
298292
for b in bindings {
299-
if i != arg {
293+
if b.node_id != arg.id {
300294
alt b.root_var {
301295
some(root) {
302-
if node == root && cant_copy(cx, b) {
303-
err(cx, args[arg].span,
296+
if node == root && cant_copy(*cx, b) {
297+
err(*cx, arg.span,
304298
"passing a mut reference to a \
305299
variable that roots another reference");
306300
break;
@@ -309,10 +303,22 @@ fn check_call(cx: ctx, sc: scope, f: @ast::expr, args: [@ast::expr])
309303
none { }
310304
}
311305
}
312-
i += 1u;
313306
}
314307
}
315-
ret bindings;
308+
// Check the bodies of block arguments against the current scope
309+
if blocks.len() > 0u {
310+
let inner_sc = {bs: bindings + sc.bs, invalid: sc.invalid};
311+
for blk in blocks {
312+
alt check blk.node {
313+
ast::expr_fn_block(_, body) {
314+
v.visit_block(body, inner_sc, v);
315+
}
316+
}
317+
}
318+
for binding in bindings {
319+
test_scope(*cx, sc, binding, none);
320+
}
321+
}
316322
}
317323

318324
fn check_alt(cx: ctx, input: @ast::expr, arms: [ast::arm], sc: scope,
@@ -397,7 +403,7 @@ fn check_var(cx: ctx, ex: @ast::expr, p: @ast::path, id: ast::node_id,
397403
}
398404
}
399405
} else if b.node_id == my_defnum {
400-
test_scope(cx, sc, b, p);
406+
test_scope(cx, sc, b, some(p));
401407
}
402408
}
403409
}
@@ -444,7 +450,7 @@ fn check_loop(cx: ctx, sc: scope, checker: fn()) {
444450
*sc.invalid = new_invalid;
445451
}
446452

447-
fn test_scope(cx: ctx, sc: scope, b: binding, p: @ast::path) {
453+
fn test_scope(cx: ctx, sc: scope, b: binding, p: option<@ast::path>) {
448454
let mut prob = find_invalid(b.node_id, *sc.invalid);
449455
alt b.root_var {
450456
some(dn) {
@@ -463,8 +469,12 @@ fn test_scope(cx: ctx, sc: scope, b: binding, p: @ast::path) {
463469
overwritten { "overwriting " + ast_util::path_name(i.path) }
464470
val_taken { "taking the value of " + ast_util::path_name(i.path) }
465471
};
466-
err(cx, i.sp, msg + " will invalidate reference " +
467-
ast_util::path_name(p) + ", which is still used");
472+
let refname = alt p {
473+
some(pt) { "reference " + ast_util::path_name(pt) +
474+
", which is still used" }
475+
none { "an argument" }
476+
};
477+
err(cx, i.sp, msg + " will invalidate " + refname);
468478
}
469479
}
470480

src/rustc/middle/trans/base.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3677,7 +3677,7 @@ fn trans_block_cleanups(bcx: block, cleanup_cx: block) ->
36773677
let mut bcx = bcx;
36783678
alt check cleanup_cx.kind {
36793679
block_scope({cleanups, _}) {
3680-
vec::riter(cleanups) {|cu|
3680+
vec::riter(copy cleanups) {|cu|
36813681
alt cu { clean(cfn) | clean_temp(_, cfn) { bcx = cfn(bcx); } }
36823682
}
36833683
}

0 commit comments

Comments
 (0)