Skip to content

Commit 62544cc

Browse files
committed
---
yaml --- r: 2951 b: refs/heads/master c: 4bd5f83 h: refs/heads/master i: 2949: d876fc9 2947: 66d79eb 2943: 3f3608b v: v3
1 parent cca7640 commit 62544cc

File tree

6 files changed

+286
-1
lines changed

6 files changed

+286
-1
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
---
2-
refs/heads/master: 2b334f061a7e7e7ff766f934081bc40ebfdaa698
2+
refs/heads/master: 4bd5f834b0a259a3ca39c881f81f01f16c65e066

trunk/src/comp/driver/rustc.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ fn compile_input(session::session sess,
109109
bind middle::tstate::ck::check_crate(ty_cx, crate));
110110
}
111111

112+
time(time_passes, "alias checking",
113+
bind middle::alias::check_crate(@ty_cx, def_map, crate));
114+
112115
auto llmod =
113116
time[llvm::llvm::ModuleRef](time_passes, "translation",
114117
bind trans::trans_crate(sess, crate,

trunk/src/comp/middle/alias.rs

Lines changed: 255 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,255 @@
1+
import front::ast;
2+
import front::ast::ident;
3+
import front::ast::def_id;
4+
import std::vec;
5+
import std::str;
6+
import std::option;
7+
import std::option::some;
8+
import std::option::none;
9+
10+
tag deref_t {
11+
field(ident);
12+
index;
13+
unbox;
14+
}
15+
type deref = rec(bool mut, deref_t t);
16+
17+
type ctx = @rec(@ty::ctxt tcx,
18+
resolve::def_map dm,
19+
// The current blacklisted (non-assignable) locals
20+
mutable vec[vec[def_id]] bl,
21+
// A stack of blacklists for outer function scopes
22+
mutable vec[vec[vec[def_id]]] blstack);
23+
24+
fn check_crate(@ty::ctxt tcx, resolve::def_map dm, &@ast::crate crate) {
25+
auto cx = @rec(tcx = tcx,
26+
dm = dm,
27+
mutable bl = vec::empty[vec[def_id]](),
28+
mutable blstack = vec::empty[vec[vec[def_id]]]());
29+
auto v = rec(visit_item_pre = bind enter_item(cx, _),
30+
visit_item_post = bind leave_item(cx, _),
31+
visit_method_pre = bind enter_method(cx, _),
32+
visit_method_post = bind leave_method(cx, _),
33+
visit_expr_pre = bind check_expr(cx, _),
34+
visit_expr_post = bind leave_expr(cx, _)
35+
with walk::default_visitor());
36+
walk::walk_crate(v, *crate);
37+
}
38+
39+
fn enter_item(ctx cx, &@ast::item it) {
40+
alt (it.node) {
41+
case (ast::item_fn(_, _, _, _, _)) {
42+
vec::push(cx.blstack, cx.bl);
43+
cx.bl = [];
44+
}
45+
case (_) {}
46+
}
47+
}
48+
fn leave_item(ctx cx, &@ast::item it) {
49+
alt (it.node) {
50+
case (ast::item_fn(_, _, _, _, _)) {
51+
cx.bl = vec::pop(cx.blstack);
52+
}
53+
case (_) {}
54+
}
55+
}
56+
57+
fn enter_method(ctx cx, &@ast::method mt) {
58+
vec::push(cx.blstack, cx.bl);
59+
cx.bl = [];
60+
}
61+
fn leave_method(ctx cx, &@ast::method mt) {
62+
cx.bl = vec::pop(cx.blstack);
63+
}
64+
65+
fn check_expr(ctx cx, &@ast::expr ex) {
66+
alt (ex.node) {
67+
case (ast::expr_call(?f, ?args, _)) {
68+
auto fty = ty::expr_ty(*cx.tcx, f);
69+
auto argtys = alt (ty::struct(*cx.tcx, fty)) {
70+
case (ty::ty_fn(_, ?args, _, _)) { args }
71+
case (ty::ty_native_fn(_, ?args, _)) { args }
72+
};
73+
auto i = 0u;
74+
let vec[def_id] listed = [];
75+
for (ty::arg argty in argtys) {
76+
// FIXME Treat mo_either specially here?
77+
if (argty.mode != ty::mo_val) {
78+
alt (check_rooted(cx, args.(i), false)) {
79+
case (some(?did)) {
80+
vec::push(listed, did);
81+
}
82+
case (_) {}
83+
}
84+
}
85+
i += 1u;
86+
}
87+
// FIXME when mutable aliases can be distinguished, go over the
88+
// args again and ensure that we're not passing a blacklisted
89+
// variable by mutable alias (using 'listed' and the context
90+
// blacklist).
91+
}
92+
case (ast::expr_put(?val, _)) {
93+
alt (val) {
94+
case (some(?ex)) { check_rooted(cx, ex, false); }
95+
case (_) {}
96+
}
97+
}
98+
case (ast::expr_alt(?input, _, _)) {
99+
vec::push(cx.bl, alt (check_rooted(cx, input, true)) {
100+
case (some(?did)) { [did] }
101+
case (_) { vec::empty[def_id]() }
102+
});
103+
}
104+
105+
case (ast::expr_move(?dest, _, _)) { check_assign(cx, dest); }
106+
case (ast::expr_assign(?dest, _, _)) { check_assign(cx, dest); }
107+
case (ast::expr_assign_op(_, ?dest, _, _)) { check_assign(cx, dest); }
108+
case (_) {}
109+
}
110+
}
111+
112+
fn leave_expr(ctx cx, &@ast::expr ex) {
113+
alt (ex.node) {
114+
case (ast::expr_alt(_, _, _)) { vec::pop(cx.bl); }
115+
case (_) {}
116+
}
117+
}
118+
119+
fn check_assign(&ctx cx, &@ast::expr ex) {
120+
alt (ex.node) {
121+
case (ast::expr_path(?pt, ?ann)) {
122+
auto did = ast::def_id_of_def(cx.dm.get(ann.id));
123+
for (vec[def_id] layer in cx.bl) {
124+
for (def_id black in layer) {
125+
if (did == black) {
126+
cx.tcx.sess.span_err
127+
(ex.span, str::connect(pt.node.idents, "::") +
128+
" is being aliased and may not be assigned to");
129+
}
130+
}
131+
}
132+
}
133+
case (_) {}
134+
}
135+
}
136+
137+
fn check_rooted(&ctx cx, &@ast::expr ex, bool autoderef)
138+
-> option::t[def_id] {
139+
auto root = expr_root(cx, ex, autoderef);
140+
if (has_unsafe_box(root.ds)) {
141+
cx.tcx.sess.span_err
142+
(ex.span, "can not create alias to improperly anchored value");
143+
}
144+
alt (root.ex.node) {
145+
case (ast::expr_path(_, ?ann)) {
146+
ret some(ast::def_id_of_def(cx.dm.get(ann.id)));
147+
}
148+
case (_) {
149+
ret none[def_id];
150+
}
151+
}
152+
}
153+
154+
fn expr_root(&ctx cx, @ast::expr ex, bool autoderef)
155+
-> rec(@ast::expr ex, vec[deref] ds) {
156+
let vec[deref] ds = [];
157+
if (autoderef) {
158+
auto auto_unbox = maybe_auto_unbox(cx, ex);
159+
if (auto_unbox.done) {
160+
vec::push(ds, rec(mut=auto_unbox.mut, t=unbox));
161+
}
162+
}
163+
while (true) {
164+
alt ({ex.node}) {
165+
case (ast::expr_field(?base, ?ident, _)) {
166+
auto auto_unbox = maybe_auto_unbox(cx, base);
167+
alt (auto_unbox.t) {
168+
case (ty::ty_tup(?fields)) {
169+
auto fnm = ty::field_num(cx.tcx.sess, ex.span, ident);
170+
auto mt = fields.(fnm).mut != ast::imm;
171+
vec::push(ds, rec(mut=mt, t=field(ident)));
172+
}
173+
case (ty::ty_rec(?fields)) {
174+
for (ty::field fld in fields) {
175+
if (str::eq(ident, fld.ident)) {
176+
auto mt = fld.mt.mut != ast::imm;
177+
vec::push(ds, rec(mut=mt, t=field(ident)));
178+
break;
179+
}
180+
}
181+
}
182+
case (ty::ty_obj(_)) {
183+
vec::push(ds, rec(mut=false, t=field(ident)));
184+
}
185+
}
186+
if (auto_unbox.done) {
187+
vec::push(ds, rec(mut=auto_unbox.mut, t=unbox));
188+
}
189+
ex = base;
190+
}
191+
case (ast::expr_index(?base, _, _)) {
192+
auto auto_unbox = maybe_auto_unbox(cx, base);
193+
alt (auto_unbox.t) {
194+
case (ty::ty_vec(?mt)) {
195+
vec::push(ds, rec(mut=mt.mut != ast::imm, t=index));
196+
}
197+
}
198+
if (auto_unbox.done) {
199+
vec::push(ds, rec(mut=auto_unbox.mut, t=unbox));
200+
}
201+
ex = base;
202+
}
203+
case (ast::expr_unary(?op, ?base, _)) {
204+
if (op == ast::deref) {
205+
alt (ty::struct(*cx.tcx, ty::expr_ty(*cx.tcx, base))) {
206+
case (ty::ty_box(?mt)) {
207+
vec::push(ds, rec(mut=mt.mut!=ast::imm, t=unbox));
208+
}
209+
}
210+
ex = base;
211+
} else {
212+
break;
213+
}
214+
}
215+
case (_) { break; }
216+
}
217+
}
218+
vec::reverse(ds);
219+
ret rec(ex = ex, ds = ds);
220+
}
221+
222+
fn maybe_auto_unbox(&ctx cx, &@ast::expr ex)
223+
-> rec(ty::sty t, bool done, bool mut) {
224+
auto tp = ty::struct(*cx.tcx, ty::expr_ty(*cx.tcx, ex));
225+
alt (tp) {
226+
case (ty::ty_box(?mt)) {
227+
ret rec(t=ty::struct(*cx.tcx, mt.ty),
228+
done=true, mut=mt.mut != ast::imm);
229+
}
230+
case (_) { ret rec(t=tp, done=false, mut=false); }
231+
}
232+
}
233+
234+
fn has_unsafe_box(&vec[deref] ds) -> bool {
235+
auto saw_mut = false;
236+
for (deref d in ds) {
237+
if (d.mut) { saw_mut = true; }
238+
if (d.t == unbox) {
239+
// Directly aliasing the content of a mutable box is never okay,
240+
// and any box living under mutable connection may be severed from
241+
// its root and freed.
242+
if (saw_mut) { ret true; }
243+
}
244+
}
245+
ret false;
246+
}
247+
248+
// Local Variables:
249+
// mode: rust
250+
// fill-column: 78;
251+
// indent-tabs-mode: nil
252+
// c-basic-offset: 4
253+
// buffer-file-coding-system: utf-8-unix
254+
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
255+
// End:

trunk/src/comp/rustc.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ mod middle {
1616
mod metadata;
1717
mod resolve;
1818
mod typeck;
19+
mod alias;
1920

2021
mod tstate {
2122
mod ck;
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// error-pattern:can not create alias
2+
3+
fn foo(&int x) {
4+
log x;
5+
}
6+
7+
fn main() {
8+
auto box = @mutable 1;
9+
foo(*box);
10+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// error-pattern:x is being aliased
2+
3+
tag foo {
4+
left(int);
5+
right(bool);
6+
}
7+
8+
fn main() {
9+
auto x = left(10);
10+
alt (x) {
11+
case (left(?i)) {
12+
x = right(false);
13+
}
14+
case (_) {}
15+
}
16+
}

0 commit comments

Comments
 (0)