From 89cd2f6bd01e66f41b8dc49dd09930aa86cd2bd9 Mon Sep 17 00:00:00 2001 From: Tim Chevalier Date: Sun, 13 May 2012 19:59:43 -0700 Subject: [PATCH] Enforce that self doesn't escape from a class Closes #2294 --- src/rustc/driver/driver.rs | 2 + src/rustc/middle/check_self.rs | 60 +++++++++++++++++++++++++++++ src/rustc/rustc.rc | 1 + src/test/compile-fail/issue-2294.rs | 6 +++ 4 files changed, 69 insertions(+) create mode 100644 src/rustc/middle/check_self.rs create mode 100644 src/test/compile-fail/issue-2294.rs 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) { + alt it.node { + item_class(*) { + visit_item(it, cx, check_self_visitor()); + } + _ {} + } +} + +fn check_self_visitor() -> vt { + mk_vt(@{ + visit_expr: bind check_self_expr(_, _, _) + with *default_visitor() + }) +} + +fn check_self_expr(e: @expr, &&cx: ty::ctxt, &&v: vt) { + 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() {}