about summary refs log tree commit diff
path: root/src/comp/middle
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-11-21 10:56:00 +0100
committerMarijn Haverbeke <marijnh@gmail.com>2011-11-21 11:01:15 +0100
commitb4217b383bbbebafbdc621f31716d5bee3cd0c72 (patch)
tree14713c2dbf711758939b4ee4db22de5db25e6e57 /src/comp/middle
parent86c1f16a1066317fdde988c0357e21ecdb336fca (diff)
downloadrust-b4217b383bbbebafbdc621f31716d5bee3cd0c72.tar.gz
rust-b4217b383bbbebafbdc621f31716d5bee3cd0c72.zip
Add a pass that checks that blocks are only used in safe ways
Closes #1188
Diffstat (limited to 'src/comp/middle')
-rw-r--r--src/comp/middle/block_use.rs41
1 files changed, 41 insertions, 0 deletions
diff --git a/src/comp/middle/block_use.rs b/src/comp/middle/block_use.rs
new file mode 100644
index 00000000000..78a49692e01
--- /dev/null
+++ b/src/comp/middle/block_use.rs
@@ -0,0 +1,41 @@
+import syntax::visit;
+import syntax::ast::*;
+
+type ctx = {tcx: ty::ctxt, mutable allow_block: bool};
+
+fn check_crate(tcx: ty::ctxt, crate: @crate) {
+    let cx = {tcx: tcx, mutable allow_block: false};
+    let v = visit::mk_vt(@{visit_expr: visit_expr
+                           with *visit::default_visitor()});
+    visit::visit_crate(*crate, cx, v);
+}
+
+fn visit_expr(ex: @expr, cx: ctx, v: visit::vt<ctx>) {
+    if !cx.allow_block {
+        alt ty::struct(cx.tcx, ty::expr_ty(cx.tcx, ex)) {
+          ty::ty_fn(proto_block., _, _, _, _) {
+            cx.tcx.sess.span_err(ex.span, "expressions with block type \
+                can only appear in callee or (by-ref) argument position");
+          }
+          _ {}
+        }
+    }
+    let outer = cx.allow_block;
+    alt ex.node {
+      expr_call(f, args, _) {
+        cx.allow_block = true;
+        v.visit_expr(f, cx, v);
+        let i = 0u;
+        for arg_t in ty::ty_fn_args(cx.tcx, ty::expr_ty(cx.tcx, f)) {
+            cx.allow_block = arg_t.mode == by_ref;
+            v.visit_expr(args[i], cx, v);
+            i += 1u;
+        }
+      }
+      _ {
+        cx.allow_block = false;
+        visit::visit_expr(ex, cx, v);
+      }
+    }
+    cx.allow_block = outer;
+}