Skip to content

Commit 8aad161

Browse files
committed
Implement basic checking of by-reference bindings
Issue #918
1 parent 44c6370 commit 8aad161

File tree

1 file changed

+57
-3
lines changed

1 file changed

+57
-3
lines changed

src/comp/middle/alias.rs

+57-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type binding = @{node_id: node_id,
2222
unsafe_tys: [ty::t],
2323
mutable ok: valid,
2424
mutable copied: copied};
25+
// FIXME it may be worthwhile to use a linked list of bindings instead
2526
type scope = {bs: [binding], ret_style: ast::ret_style};
2627

2728
fn mk_binding(cx: ctx, id: node_id, span: span, root_var: option::t<node_id>,
@@ -46,7 +47,8 @@ fn check_crate(tcx: ty::ctxt, crate: @ast::crate) -> copy_map {
4647
copy_map: std::map::new_int_hash()};
4748
let v = @{visit_fn: bind visit_fn(cx, _, _, _, _, _, _, _),
4849
visit_expr: bind visit_expr(cx, _, _, _),
49-
visit_decl: bind visit_decl(cx, _, _, _)
50+
visit_decl: bind visit_decl(cx, _, _, _),
51+
visit_block: bind visit_block(cx, _, _, _)
5052
with *visit::default_visitor::<scope>()};
5153
visit::visit_crate(*crate, {bs: [], ret_style: ast::return_val},
5254
visit::mk_vt(v));
@@ -134,8 +136,7 @@ fn visit_decl(cx: @ctx, d: @ast::decl, sc: scope, v: vt<scope>) {
134136
visit::visit_decl(d, sc, v);
135137
alt d.node {
136138
ast::decl_local(locs) {
137-
// FIXME check that init is lvalue
138-
for (style, loc) in locs {
139+
for (_, loc) in locs {
139140
alt loc.node.init {
140141
some(init) {
141142
if init.op == ast::init_move {
@@ -150,6 +151,59 @@ fn visit_decl(cx: @ctx, d: @ast::decl, sc: scope, v: vt<scope>) {
150151
}
151152
}
152153

154+
fn visit_block(cx: @ctx, b: ast::blk, sc: scope, v: vt<scope>) {
155+
let ref_locs = [];
156+
for stmt in b.node.stmts {
157+
alt stmt.node {
158+
ast::stmt_decl(@{node: ast::decl_local(ls), _}, _) {
159+
for (st, loc) in ls {
160+
if st == ast::let_ref {
161+
ref_locs += [loc];
162+
}
163+
}
164+
}
165+
_ {}
166+
}
167+
}
168+
if vec::len(ref_locs) > 0u {
169+
let bindings = sc.bs;
170+
for loc in ref_locs { add_bindings_for_let(*cx, bindings, loc); }
171+
visit::visit_block(b, {bs: bindings with sc}, v);
172+
} else {
173+
visit::visit_block(b, sc, v);
174+
}
175+
}
176+
177+
fn add_bindings_for_let(cx: ctx, &bs: [binding], loc: @ast::local) {
178+
alt loc.node.init {
179+
some(init) {
180+
if init.op == ast::init_move {
181+
cx.tcx.sess.span_err
182+
(loc.span, "can not move into a by-reference binding");
183+
}
184+
let root = expr_root(cx.tcx, init.expr, false);
185+
let root_var = path_def_id(cx, root.ex);
186+
// FIXME also allow by-ref function calls
187+
if is_none(root_var) {
188+
cx.tcx.sess.span_err(loc.span, "a reference binding can't be \
189+
rooted in a temporary");
190+
}
191+
for proot in *pattern_roots(cx.tcx, *root.ds, loc.node.pat) {
192+
let bnd = mk_binding(cx, proot.id, proot.span, root_var,
193+
inner_mut(proot.ds));
194+
// Don't implicitly copy explicit references
195+
bnd.copied = not_allowed;
196+
bs += [bnd];
197+
}
198+
}
199+
_ {
200+
cx.tcx.sess.span_err
201+
(loc.span, "by-reference bindings must be initialized");
202+
}
203+
}
204+
}
205+
206+
153207
fn cant_copy(cx: ctx, b: binding) -> bool {
154208
alt b.copied {
155209
not_allowed. { ret true; }

0 commit comments

Comments
 (0)