diff --git a/src/rustc/driver/driver.rs b/src/rustc/driver/driver.rs index 345678bb661..9c6a168d10f 100644 --- a/src/rustc/driver/driver.rs +++ b/src/rustc/driver/driver.rs @@ -221,6 +221,9 @@ fn compile_upto(sess: session, cfg: ast::crate_cfg, if upto == cu_typeck { return {crate: crate, tcx: Some(ty_cx)}; } + time(time_passes, ~"privacy checking", || + middle::privacy::check_crate(ty_cx, crate)); + time(time_passes, ~"loop checking", || middle::check_loop::check_crate(ty_cx, crate)); diff --git a/src/rustc/middle/privacy.rs b/src/rustc/middle/privacy.rs new file mode 100644 index 00000000000..83c341c609a --- /dev/null +++ b/src/rustc/middle/privacy.rs @@ -0,0 +1,75 @@ +// A pass that checks to make sure private fields and methods aren't used +// outside their scopes. + +use /*mod*/ syntax::ast; +use /*mod*/ syntax::visit; +use syntax::ast::{expr_field, ident, item_class, local_crate, node_id}; +use syntax::ast::{private}; +use ty::ty_class; + +use core::util::ignore; +use dvec::DVec; +use send_map::linear::LinearMap; + +fn check_crate(tcx: ty::ctxt, crate: @ast::crate) { + let privileged_structs = @DVec(); + + let add_privileged_structs = |items: &[@ast::item]| { + let mut count = 0; + for items.each |item| { + match item.node { + item_class(*) => { + privileged_structs.push(item.id); + count += 1; + } + _ => {} + } + } + count + }; + + let visitor = visit::mk_vt(@{ + visit_mod: |the_module, span, node_id, env, visitor| { + let n_added = add_privileged_structs(the_module.items); + + visit::visit_mod(the_module, span, node_id, env, visitor); + + for n_added.times { + ignore(privileged_structs.pop()); + } + }, + visit_expr: |expr, env, visitor| { + match expr.node { + expr_field(base, ident, _) => { + match ty::get(ty::expr_ty(tcx, base)).struct { + ty_class(id, _) + if id.crate != local_crate || + !privileged_structs.contains(id.node) => { + let fields = ty::lookup_class_fields(tcx, id); + for fields.each |field| { + if field.ident != ident { again; } + if field.vis == private { + tcx.sess.span_err(expr.span, + fmt!("field `%s` is \ + private", + *tcx.sess + .parse_sess + .interner + .get(ident))); + } + break; + } + } + _ => {} + } + } + _ => {} + } + + visit::visit_expr(expr, env, visitor); + } + with *visit::default_visitor() + }); + visit::visit_crate(*crate, (), visitor); +} + diff --git a/src/rustc/middle/ty.rs b/src/rustc/middle/ty.rs index f473244eda8..a3b9f1d05ac 100644 --- a/src/rustc/middle/ty.rs +++ b/src/rustc/middle/ty.rs @@ -3160,10 +3160,6 @@ fn lookup_class_field(cx: ctxt, parent: ast::def_id, field_id: ast::def_id) } } -fn lookup_public_fields(cx: ctxt, did: ast::def_id) -> ~[field_ty] { - vec::filter(lookup_class_fields(cx, did), is_public) -} - pure fn is_public(f: field_ty) -> bool { // XXX: This is wrong. match f.vis { diff --git a/src/rustc/middle/typeck.rs b/src/rustc/middle/typeck.rs index dc484f581e7..87012054779 100644 --- a/src/rustc/middle/typeck.rs +++ b/src/rustc/middle/typeck.rs @@ -51,9 +51,8 @@ use syntax::codemap::span; use pat_util::{pat_is_variant, pat_id_map}; use middle::ty; -use middle::ty::{arg, field, node_type_table, mk_nil, - ty_param_bounds_and_ty, lookup_public_fields, - vstore_uniq}; +use middle::ty::{arg, field, node_type_table, mk_nil, ty_param_bounds_and_ty}; +use middle::ty::{vstore_uniq}; use std::smallintmap; use std::map; use std::map::{hashmap, int_hash}; diff --git a/src/rustc/middle/typeck/check.rs b/src/rustc/middle/typeck/check.rs index dd8ac61dd46..ad0eb81c826 100644 --- a/src/rustc/middle/typeck/check.rs +++ b/src/rustc/middle/typeck/check.rs @@ -1317,18 +1317,7 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, // (1) verify that the class id actually has a field called // field debug!("class named %s", ty_to_str(tcx, base_t)); - /* - check whether this is a self-reference or not, which - determines whether we look at all fields or only public - ones - */ - let cls_items = if self_ref(fcx, base.id) { - // base expr is "self" -- consider all fields - ty::lookup_class_fields(tcx, base_id) - } - else { - lookup_public_fields(tcx, base_id) - }; + let cls_items = ty::lookup_class_fields(tcx, base_id); match lookup_field_ty(tcx, base_id, cls_items, field, &substs) { Some(field_ty) => { // (2) look up what field's type is, and return it @@ -1370,8 +1359,7 @@ fn check_field(fcx: @fn_ctxt, expr: @ast::expr, is_callee: bool, let msg = fmt!( "attempted access of field `%s` on type `%s`, \ - but no public field or method with that name \ - was found", + but no field or method with that name was found", tcx.sess.str_of(field), fcx.infcx().ty_to_str(t_err)); tcx.sess.span_err(expr.span, msg); diff --git a/src/rustc/rustc.rc b/src/rustc/rustc.rc index da347abad87..6890ec0acdc 100644 --- a/src/rustc/rustc.rc +++ b/src/rustc/rustc.rc @@ -102,6 +102,7 @@ mod middle { mod const_eval; mod astencode; mod lang_items; + mod privacy; } mod front { diff --git a/src/test/compile-fail/private-class-field.rs b/src/test/compile-fail/private-class-field.rs deleted file mode 100644 index ae0ae7c4a57..00000000000 --- a/src/test/compile-fail/private-class-field.rs +++ /dev/null @@ -1,15 +0,0 @@ -// error-pattern:no public field or method with that name -struct cat { - priv { - let mut meows : uint; - } - - let how_hungry : int; - - new(in_x : uint, in_y : int) { self.meows = in_x; self.how_hungry = in_y; } -} - -fn main() { - let nyan : cat = cat(52u, 99); - assert (nyan.meows == 52u); -} diff --git a/src/test/compile-fail/private-class-field-cross-crate.rs b/src/test/compile-fail/private-struct-field-cross-crate.rs similarity index 60% rename from src/test/compile-fail/private-class-field-cross-crate.rs rename to src/test/compile-fail/private-struct-field-cross-crate.rs index b96adc19cbb..c40b04004b4 100644 --- a/src/test/compile-fail/private-class-field-cross-crate.rs +++ b/src/test/compile-fail/private-struct-field-cross-crate.rs @@ -1,4 +1,3 @@ -// error-pattern:no public field or method with that name // xfail-fast // aux-build:cci_class.rs use cci_class; @@ -6,5 +5,5 @@ fn main() { let nyan : cat = cat(52u, 99); - assert (nyan.meows == 52u); + assert (nyan.meows == 52u); //~ ERROR field `meows` is private } diff --git a/src/test/compile-fail/private-struct-field.rs b/src/test/compile-fail/private-struct-field.rs new file mode 100644 index 00000000000..becef52fa61 --- /dev/null +++ b/src/test/compile-fail/private-struct-field.rs @@ -0,0 +1,14 @@ +mod cat { + struct Cat { + priv meows: uint; + } + + fn new_cat() -> Cat { + Cat { meows: 52 } + } +} + +fn main() { + let nyan = cat::new_cat(); + assert nyan.meows == 52; //~ ERROR field `meows` is private +}