about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTim Chevalier <chevalier@alum.wellesley.edu>2012-05-13 19:59:43 -0700
committerTim Chevalier <chevalier@alum.wellesley.edu>2012-05-14 14:26:10 -0700
commit89cd2f6bd01e66f41b8dc49dd09930aa86cd2bd9 (patch)
tree122d27dbed85bdb6e6931a2227abcbabb05a14e7
parent11e9947ff55b4c8a4f9c8ce875bfff6f2016e8b4 (diff)
downloadrust-89cd2f6bd01e66f41b8dc49dd09930aa86cd2bd9.tar.gz
rust-89cd2f6bd01e66f41b8dc49dd09930aa86cd2bd9.zip
Enforce that self doesn't escape from a class
Closes #2294
-rw-r--r--src/rustc/driver/driver.rs2
-rw-r--r--src/rustc/middle/check_self.rs60
-rw-r--r--src/rustc/rustc.rc1
-rw-r--r--src/test/compile-fail/issue-2294.rs6
4 files changed, 69 insertions, 0 deletions
diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs
index 1cc19143eec..efa32a5884d 100644
--- a/src/rustc/driver/driver.rs
+++ b/src/rustc/driver/driver.rs
@@ -186,6 +186,8 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg,
          bind middle::check_loop::check_crate(ty_cx, crate));
     time(time_passes, "alt checking",
          bind middle::check_alt::check_crate(ty_cx, crate));
+    time(time_passes, "self checking",
+         bind middle::check_self::check_crate(ty_cx, crate));
     time(time_passes, "typestate checking",
          bind middle::tstate::ck::check_crate(ty_cx, crate));
     let (_root_map, mutbl_map) = time(
diff --git a/src/rustc/middle/check_self.rs b/src/rustc/middle/check_self.rs
new file mode 100644
index 00000000000..b1d2c4b8215
--- /dev/null
+++ b/src/rustc/middle/check_self.rs
@@ -0,0 +1,60 @@
+/*
+  This module checks that within a class, "self" doesn't escape.
+  That is, it rejects any class in which "self" occurs other than
+  as the left-hand side of a field reference.
+ */
+import syntax::ast::*;
+import syntax::visit::*;
+import driver::session::session;
+import std::map::hashmap;
+import resolve::def_map;
+
+fn check_crate(cx: ty::ctxt, crate: @crate) {
+    visit_crate(*crate, cx, mk_vt(@{
+        visit_item: bind check_item(_, _, _)
+        with *default_visitor()
+    }));
+    cx.sess.abort_if_errors();
+}
+
+fn check_item(it: @item, &&cx: ty::ctxt, &&_v: vt<ty::ctxt>) {
+    alt it.node {
+      item_class(*) {
+          visit_item(it, cx, check_self_visitor());
+      }
+      _ {}
+    }
+}
+
+fn check_self_visitor() -> vt<ty::ctxt> {
+    mk_vt(@{
+        visit_expr: bind check_self_expr(_, _, _)
+                with *default_visitor()
+    })
+}
+
+fn check_self_expr(e: @expr, &&cx: ty::ctxt, &&v: vt<ty::ctxt>) {
+   alt e.node {
+     expr_field(@{node: expr_path(p),_},_,_) {
+       // self is ok here; don't descend
+     }
+     expr_path(_) {
+       alt cx.def_map.find(e.id) {
+          some(def_self(_)) {
+            cx.sess.span_err(e.span, "can't return self or store \
+              it in a data structure");
+          }
+          _ {}
+       }
+     }
+     _ { visit_expr(e, cx, v); }
+  }
+}
+
+// Local Variables:
+// mode: rust
+// fill-column: 78;
+// indent-tabs-mode: nil
+// c-basic-offset: 4
+// buffer-file-coding-system: utf-8-unix
+// End:
diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc
index 71235ac3313..41635f8fec7 100644
--- a/src/rustc/rustc.rc
+++ b/src/rustc/rustc.rc
@@ -55,6 +55,7 @@ mod middle {
     mod check_loop;
     mod check_alt;
     mod check_const;
+    mod check_self;
     mod lint;
     mod borrowck;
     mod alias;
diff --git a/src/test/compile-fail/issue-2294.rs b/src/test/compile-fail/issue-2294.rs
new file mode 100644
index 00000000000..292a4aa3947
--- /dev/null
+++ b/src/test/compile-fail/issue-2294.rs
@@ -0,0 +1,6 @@
+class cat {
+  fn kitty() -> cat { self } //! ERROR: can't return self or store it in a data structure
+  new() { }
+}
+
+fn main() {}