1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
/*
* The region checking pass. Ensures that region-annotated pointers never
* outlive their referents.
*/
import driver::session::session;
import middle::ty;
import std::map::hashmap;
import syntax::{ast, visit};
// An "extended region", which includes the ordinarily-unnamed reference-
// counted heap and exchange heap regions. This is used to detect borrowing.
enum region_ext {
re_rc,
re_exheap,
re_region(ty::region)
}
type ctxt = {
tcx: ty::ctxt,
enclosing_block: option<ast::node_id>
};
fn check_expr(expr: @ast::expr, cx: ctxt, visitor: visit::vt<ctxt>) {
let t = ty::expr_ty(cx.tcx, expr);
if ty::type_has_rptrs(t) {
ty::walk_ty(t) { |t|
alt ty::get(t).struct {
ty::ty_rptr(region, _) {
alt region {
ty::re_self | ty::re_inferred | ty::re_param(_) {
/* ok */
}
ty::re_block(rbi) {
let referent_block_id = rbi;
let enclosing_block_id = alt cx.enclosing_block {
none {
cx.tcx.sess.span_bug(expr.span,
"block region " +
"type outside a " +
"block?!");
}
some(eb) { eb }
};
if !region::scope_contains(cx.tcx.region_map,
referent_block_id,
enclosing_block_id) {
cx.tcx.sess.span_err(expr.span, "reference " +
"escapes its block");
}
}
ty::re_var(_) {
cx.tcx.sess.span_bug(expr.span,
"unresolved region");
}
}
}
_ { /* no-op */ }
}
}
}
visit::visit_expr(expr, cx, visitor);
}
fn check_block(blk: ast::blk, cx: ctxt, visitor: visit::vt<ctxt>) {
let new_cx: ctxt = { enclosing_block: some(blk.node.id) with cx };
visit::visit_block(blk, new_cx, visitor);
}
fn check_crate(ty_cx: ty::ctxt, crate: @ast::crate) {
let cx: ctxt = {tcx: ty_cx, enclosing_block: none};
let visitor = visit::mk_vt(@{
visit_expr: check_expr,
visit_block: check_block
with *visit::default_visitor()
});
visit::visit_crate(*crate, cx, visitor);
}
|