diff --git a/src/libextra/arc.rs b/src/libextra/arc.rs index ca8000c984d..28a067a782b 100644 --- a/src/libextra/arc.rs +++ b/src/libextra/arc.rs @@ -162,7 +162,7 @@ struct MutexArcInner { priv lock: Mutex, priv failed: bool, priv data: T } /// An Arc with mutable data protected by a blocking mutex. #[no_freeze] -struct MutexArc { priv x: UnsafeArc> } +pub struct MutexArc { priv x: UnsafeArc> } impl Clone for MutexArc { @@ -343,7 +343,7 @@ struct RWArcInner { priv lock: RWLock, priv failed: bool, priv data: T } * Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested. */ #[no_freeze] -struct RWArc { +pub struct RWArc { priv x: UnsafeArc>, } diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 24ab8360e8f..e24fe3eb8c2 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -127,7 +127,7 @@ impl WorkMap { } } -struct Database { +pub struct Database { db_filename: Path, db_cache: TreeMap<~str, ~str>, db_dirty: bool @@ -207,7 +207,7 @@ impl Drop for Database { } } -struct Logger { +pub struct Logger { // FIXME #4432: Fill in a: () } @@ -223,10 +223,10 @@ impl Logger { } } -type FreshnessMap = TreeMap<~str,extern fn(&str,&str)->bool>; +pub type FreshnessMap = TreeMap<~str,extern fn(&str,&str)->bool>; #[deriving(Clone)] -struct Context { +pub struct Context { db: RWArc, logger: RWArc, cfg: Arc, @@ -239,13 +239,13 @@ struct Context { freshness: Arc } -struct Prep<'self> { +pub struct Prep<'self> { ctxt: &'self Context, fn_name: &'self str, declared_inputs: WorkMap, } -struct Exec { +pub struct Exec { discovered_inputs: WorkMap, discovered_outputs: WorkMap } diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index c9a5ca2c61c..5518dde0ee9 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -197,6 +197,7 @@ pub fn phase_2_configure_and_expand(sess: Session, pub struct CrateAnalysis { exp_map2: middle::resolve::ExportMap2, + exported_items: @middle::privacy::ExportedItems, ty_cx: ty::ctxt, maps: astencode::Maps, reachable: @mut HashSet @@ -258,8 +259,9 @@ pub fn phase_3_run_analysis_passes(sess: Session, middle::check_const::check_crate(sess, crate, ast_map, def_map, method_map, ty_cx)); - time(time_passes, ~"privacy checking", || - middle::privacy::check_crate(ty_cx, &method_map, crate)); + let exported_items = + time(time_passes, ~"privacy checking", || + middle::privacy::check_crate(ty_cx, &method_map, &exp_map2, crate)); time(time_passes, ~"effect checking", || middle::effect::check_crate(ty_cx, method_map, crate)); @@ -301,6 +303,7 @@ pub fn phase_3_run_analysis_passes(sess: Session, CrateAnalysis { exp_map2: exp_map2, + exported_items: @exported_items, ty_cx: ty_cx, maps: astencode::Maps { root_map: root_map, diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs index bc7cba46c6b..841142ee62f 100644 --- a/src/librustc/metadata/csearch.rs +++ b/src/librustc/metadata/csearch.rs @@ -27,7 +27,8 @@ use syntax::diagnostic::expect; pub struct StaticMethodInfo { ident: ast::Ident, def_id: ast::DefId, - purity: ast::purity + purity: ast::purity, + vis: ast::visibility, } pub fn get_symbol(cstore: @mut cstore::CStore, def: ast::DefId) -> ~str { @@ -52,7 +53,8 @@ pub fn each_lang_item(cstore: @mut cstore::CStore, /// Iterates over each child of the given item. pub fn each_child_of_item(cstore: @mut cstore::CStore, def_id: ast::DefId, - callback: &fn(decoder::DefLike, ast::Ident)) { + callback: &fn(decoder::DefLike, ast::Ident, + ast::visibility)) { let crate_data = cstore::get_crate_data(cstore, def_id.crate); let get_crate_data: decoder::GetCrateDataCb = |cnum| { cstore::get_crate_data(cstore, cnum) @@ -68,7 +70,8 @@ pub fn each_child_of_item(cstore: @mut cstore::CStore, pub fn each_top_level_item_of_crate(cstore: @mut cstore::CStore, cnum: ast::CrateNum, callback: &fn(decoder::DefLike, - ast::Ident)) { + ast::Ident, + ast::visibility)) { let crate_data = cstore::get_crate_data(cstore, cnum); let get_crate_data: decoder::GetCrateDataCb = |cnum| { cstore::get_crate_data(cstore, cnum) diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index c94151095a4..fe7309d4467 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -96,7 +96,7 @@ fn find_item(item_id: int, items: ebml::Doc) -> ebml::Doc { // Looks up an item in the given metadata and returns an ebml doc pointing // to the item data. -fn lookup_item(item_id: int, data: @~[u8]) -> ebml::Doc { +pub fn lookup_item(item_id: int, data: @~[u8]) -> ebml::Doc { let items = reader::get_doc(reader::Doc(data), tag_items); find_item(item_id, items) } @@ -291,7 +291,7 @@ fn enum_variant_ids(item: ebml::Doc, cdata: Cmd) -> ~[ast::DefId] { return ids; } -fn item_path(item_doc: ebml::Doc) -> ast_map::path { +pub fn item_path(item_doc: ebml::Doc) -> ast_map::path { let path_doc = reader::get_doc(item_doc, tag_path); let len_doc = reader::get_doc(path_doc, tag_path_len); @@ -332,7 +332,7 @@ fn item_name(intr: @ident_interner, item: ebml::Doc) -> ast::Ident { } } -fn item_to_def_like(item: ebml::Doc, did: ast::DefId, cnum: ast::CrateNum) +pub fn item_to_def_like(item: ebml::Doc, did: ast::DefId, cnum: ast::CrateNum) -> DefLike { let fam = item_family(item); match fam { @@ -491,7 +491,7 @@ pub enum DefLike { DlField } -fn def_like_to_def(def_like: DefLike) -> ast::Def { +pub fn def_like_to_def(def_like: DefLike) -> ast::Def { match def_like { DlDef(def) => return def, DlImpl(*) => fail!("found impl in def_like_to_def"), @@ -544,7 +544,8 @@ impl<'self> EachItemContext<'self> { fn process_item_and_pop_name(&mut self, doc: ebml::Doc, def_id: ast::DefId, - old_len: uint) + old_len: uint, + vis: ast::visibility) -> bool { let def_like = item_to_def_like(doc, def_id, self.cdata.cnum); match def_like { @@ -563,8 +564,6 @@ impl<'self> EachItemContext<'self> { } } - let vis = item_visibility(doc); - let mut continue = (self.callback)(*self.path_builder, def_like, vis); let family = item_family(doc); @@ -653,9 +652,12 @@ impl<'self> EachItemContext<'self> { self.push_name(token::ident_to_str(&child_name)); // Process this item. + + let vis = item_visibility(child_item_doc); continue = self.process_item_and_pop_name(child_item_doc, child_def_id, - old_len); + old_len, + vis); } } continue @@ -701,12 +703,13 @@ impl<'self> EachItemContext<'self> { // Get the item. match maybe_find_item(def_id.node, other_crates_items) { - None => {} + None => { self.pop_name(old_len); } Some(reexported_item_doc) => { continue = self.process_item_and_pop_name( reexported_item_doc, def_id, - old_len); + old_len, + ast::public); } } @@ -721,7 +724,8 @@ fn each_child_of_item_or_crate(intr: @ident_interner, cdata: Cmd, item_doc: ebml::Doc, get_crate_data: GetCrateDataCb, - callback: &fn(DefLike, ast::Ident)) { + callback: &fn(DefLike, ast::Ident, + ast::visibility)) { // Iterate over all children. let _ = do reader::tagged_docs(item_doc, tag_mod_child) |child_info_doc| { let child_def_id = reader::with_doc_data(child_info_doc, @@ -746,7 +750,8 @@ fn each_child_of_item_or_crate(intr: @ident_interner, let def_like = item_to_def_like(child_item_doc, child_def_id, cdata.cnum); - callback(def_like, child_name); + let visibility = item_visibility(child_item_doc); + callback(def_like, child_name, visibility); } } @@ -788,7 +793,8 @@ fn each_child_of_item_or_crate(intr: @ident_interner, impl_method_def_id, cdata.cnum); callback(static_method_def_like, - static_method_name); + static_method_name, + item_visibility(impl_method_doc)); } _ => {} } @@ -831,7 +837,8 @@ fn each_child_of_item_or_crate(intr: @ident_interner, let def_like = item_to_def_like(child_item_doc, child_def_id, cdata.cnum); - callback(def_like, token::str_to_ident(name)); + callback(def_like, token::str_to_ident(name), + item_visibility(child_item_doc)); } } @@ -844,7 +851,7 @@ pub fn each_child_of_item(intr: @ident_interner, cdata: Cmd, id: ast::NodeId, get_crate_data: GetCrateDataCb, - callback: &fn(DefLike, ast::Ident)) { + callback: &fn(DefLike, ast::Ident, ast::visibility)) { // Find the item. let root_doc = reader::Doc(cdata.data); let items = reader::get_doc(root_doc, tag_items); @@ -864,7 +871,8 @@ pub fn each_child_of_item(intr: @ident_interner, pub fn each_top_level_item_of_crate(intr: @ident_interner, cdata: Cmd, get_crate_data: GetCrateDataCb, - callback: &fn(DefLike, ast::Ident)) { + callback: &fn(DefLike, ast::Ident, + ast::visibility)) { let root_doc = reader::Doc(cdata.data); let misc_info_doc = reader::get_doc(root_doc, tag_misc_info); let crate_items_doc = reader::get_doc(misc_info_doc, @@ -1161,7 +1169,8 @@ pub fn get_static_methods_if_impl(intr: @ident_interner, static_impl_methods.push(StaticMethodInfo { ident: item_name(intr, impl_method_doc), def_id: item_def_id(impl_method_doc, cdata), - purity: purity + purity: purity, + vis: item_visibility(impl_method_doc), }); } _ => {} diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index 9e65e4ec18a..de60927f2a2 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -16,9 +16,9 @@ use metadata::cstore; use metadata::decoder; use metadata::tyencode; use middle::ty::{node_id_to_type, lookup_item_type}; +use middle::astencode; use middle::ty; use middle::typeck; -use middle::astencode; use middle; use std::hashmap::{HashMap, HashSet}; @@ -58,6 +58,7 @@ pub struct EncodeParams<'self> { diag: @mut span_handler, tcx: ty::ctxt, reexports2: middle::resolve::ExportMap2, + exported_items: @middle::privacy::ExportedItems, item_symbols: &'self HashMap, discrim_symbols: &'self HashMap, non_inlineable_statics: &'self HashSet, @@ -88,6 +89,7 @@ pub struct EncodeContext<'self> { tcx: ty::ctxt, stats: @mut Stats, reexports2: middle::resolve::ExportMap2, + exported_items: @middle::privacy::ExportedItems, item_symbols: &'self HashMap, discrim_symbols: &'self HashMap, non_inlineable_statics: &'self HashSet, @@ -881,7 +883,8 @@ fn encode_info_for_item(ecx: &EncodeContext, ebml_w: &mut writer::Encoder, item: @item, index: @mut ~[entry], - path: &[ast_map::path_elt]) { + path: &[ast_map::path_elt], + vis: ast::visibility) { let tcx = ecx.tcx; fn add_to_index_(item: @item, ebml_w: &writer::Encoder, @@ -912,6 +915,7 @@ fn encode_info_for_item(ecx: &EncodeContext, if !ecx.non_inlineable_statics.contains(&item.id) { (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); } + encode_visibility(ebml_w, vis); ebml_w.end_tag(); } item_fn(_, purity, _, ref generics, _) => { @@ -929,6 +933,7 @@ fn encode_info_for_item(ecx: &EncodeContext, } else { encode_symbol(ecx, ebml_w, item.id); } + encode_visibility(ebml_w, vis); ebml_w.end_tag(); } item_mod(ref m) => { @@ -955,7 +960,7 @@ fn encode_info_for_item(ecx: &EncodeContext, ebml_w.wr_str(def_to_str(local_def(foreign_item.id))); ebml_w.end_tag(); } - + encode_visibility(ebml_w, vis); ebml_w.end_tag(); } item_ty(*) => { @@ -967,6 +972,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_name(ecx, ebml_w, item.ident); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); encode_region_param(ecx, ebml_w, item); + encode_visibility(ebml_w, vis); ebml_w.end_tag(); } item_enum(ref enum_definition, ref generics) => { @@ -987,6 +993,7 @@ fn encode_info_for_item(ecx: &EncodeContext, // Encode inherent implementations for this enumeration. encode_inherent_implementations(ecx, ebml_w, def_id); + encode_visibility(ebml_w, vis); ebml_w.end_tag(); encode_enum_variant_info(ecx, @@ -1018,6 +1025,7 @@ fn encode_info_for_item(ecx: &EncodeContext, encode_attributes(ebml_w, item.attrs); encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident)); encode_region_param(ecx, ebml_w, item); + encode_visibility(ebml_w, vis); /* Encode def_ids for each field and method for methods, write all the stuff get_trait_method @@ -1264,7 +1272,12 @@ fn my_visit_item(i:@item, items: ast_map::map, ebml_w:&writer::Encoder, let mut ebml_w = ebml_w.clone(); // See above let ecx : &EncodeContext = unsafe { cast::transmute(ecx_ptr) }; - encode_info_for_item(ecx, &mut ebml_w, i, index, *pt); + let vis = if ecx.exported_items.contains(&i.id) { + ast::public + } else { + ast::inherited + }; + encode_info_for_item(ecx, &mut ebml_w, i, index, *pt, vis); } _ => fail!("bad item") } @@ -1727,6 +1740,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { diag, tcx, reexports2, + exported_items, discrim_symbols, cstore, encode_inlined_item, @@ -1742,6 +1756,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { tcx: tcx, stats: stats, reexports2: reexports2, + exported_items: exported_items, item_symbols: item_symbols, discrim_symbols: discrim_symbols, non_inlineable_statics: non_inlineable_statics, diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 892217988c7..c719146c999 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -150,7 +150,7 @@ fn make_rustpkg_target_lib_path(dir: &Path, dir.push_rel(&Path(libdir()).push(target_triple.to_owned())) } -fn get_or_default_sysroot() -> Path { +pub fn get_or_default_sysroot() -> Path { match os::self_exe_path() { option::Some(ref p) => (*p).pop(), option::None => fail!("can't determine value for sysroot") diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 51fe2acc72a..3c60bd67362 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -9,9 +9,13 @@ // except according to those terms. //! A pass that checks to make sure private fields and methods aren't used -//! outside their scopes. +//! outside their scopes. This pass will also generate a set of exported items +//! which are available for use externally when compiled as a library. + +use std::hashmap::HashSet; use metadata::csearch; +use middle::resolve::ExportMap2; use middle::ty::{ty_struct, ty_enum}; use middle::ty; use middle::typeck::{method_map, method_origin, method_param}; @@ -37,9 +41,23 @@ use syntax::visit; use syntax::visit::Visitor; use syntax::ast::{_mod,Expr,item,Block,Pat}; +// This set is a set of all item nodes which can be used by external crates if +// we're building a library. The necessary qualifications for this are that all +// items leading down to the current item (excluding an `impl`) must be `pub`. +pub type ExportedItems = HashSet; + +type Context<'self> = (&'self method_map, &'self ExportMap2); + struct PrivacyVisitor { tcx: ty::ctxt, privileged_items: @mut ~[NodeId], + + // A set of all items which are re-exported to be used across crates + exported_items: ExportedItems, + + // A flag as to whether the current path is public all the way down to the + // current point or not + path_all_public: bool, } impl PrivacyVisitor { @@ -265,15 +283,20 @@ impl PrivacyVisitor { .last() .identifier))); } - } else if csearch::get_item_visibility(self.tcx.sess.cstore, - def_id) != public { - self.tcx.sess.span_err(span, - fmt!("function `%s` is private", - token::ident_to_str( - &path.segments - .last() - .identifier))); + //} else if csearch::get_item_visibility(self.tcx.sess.cstore, + // def_id) != public { + // self.tcx.sess.span_err(span, + // fmt!("function `%s` is private", + // token::ident_to_str( + // &path.segments + // .last() + // .identifier))); } + // If this is a function from a non-local crate, then the + // privacy check is enforced during resolve. All public items + // will be tagged as such in the crate metadata and then usage + // of the private items will be blocked during resolve. Hence, + // if this isn't from the local crate, nothing to check. } _ => {} } @@ -341,31 +364,78 @@ impl PrivacyVisitor { } } -impl<'self> Visitor<&'self method_map> for PrivacyVisitor { +impl<'self> Visitor> for PrivacyVisitor { - fn visit_mod<'mm>(&mut self, the_module:&_mod, _:Span, _:NodeId, - method_map:&'mm method_map) { + fn visit_mod(&mut self, the_module:&_mod, _:Span, _:NodeId, + cx: Context<'self>) { let n_added = self.add_privileged_items(the_module.items); - visit::walk_mod(self, the_module, method_map); + visit::walk_mod(self, the_module, cx); do n_added.times { ignore(self.privileged_items.pop()); } } - fn visit_item<'mm>(&mut self, item:@item, method_map:&'mm method_map) { + fn visit_item(&mut self, item:@item, cx: Context<'self>) { - // Do not check privacy inside items with the resolve_unexported - // attribute. This is used for the test runner. - if !attr::contains_name(item.attrs, "!resolve_unexported") { - check_sane_privacy(self.tcx, item); - visit::walk_item(self, item, method_map); + // Do not check privacy inside items with the resolve_unexported + // attribute. This is used for the test runner. + if attr::contains_name(item.attrs, "!resolve_unexported") { + return; + } + + // Disallow unnecessary visibility qualifiers + check_sane_privacy(self.tcx, item); + + // Keep track of whether this item is available for export or not. + let orig_all_pub = self.path_all_public; + match item.node { + // impls/extern blocks do not break the "public chain" because they + // cannot have visibility qualifiers on them anyway + ast::item_impl(*) | ast::item_foreign_mod(*) => {} + + // Private by default, hence we only retain the "public chain" if + // `pub` is explicitly listed. + _ => { + self.path_all_public = orig_all_pub && item.vis == ast::public; } + } + debug2!("public path at {}: {}", item.id, self.path_all_public); + + if self.path_all_public { + debug2!("all the way public {}", item.id); + self.exported_items.insert(item.id); + + // All re-exported items in a module which is public should also be + // public (in terms of how they should get encoded) + match item.node { + ast::item_mod(*) => { + let (_, exp_map2) = cx; + match exp_map2.find(&item.id) { + Some(exports) => { + for export in exports.iter() { + if export.reexport && is_local(export.def_id) { + debug2!("found reexported {:?}", export); + let id = export.def_id.node; + self.exported_items.insert(id); + } + } + } + None => {} + } + } + _ => {} + } + } + + visit::walk_item(self, item, cx); + + self.path_all_public = orig_all_pub; } - fn visit_block<'mm>(&mut self, block:&Block, method_map:&'mm method_map) { + fn visit_block(&mut self, block:&Block, cx: Context<'self>) { // Gather up all the privileged items. let mut n_added = 0; @@ -383,7 +453,7 @@ impl<'self> Visitor<&'self method_map> for PrivacyVisitor { } } - visit::walk_block(self, block, method_map); + visit::walk_block(self, block, cx); do n_added.times { ignore(self.privileged_items.pop()); @@ -391,8 +461,8 @@ impl<'self> Visitor<&'self method_map> for PrivacyVisitor { } - fn visit_expr<'mm>(&mut self, expr:@Expr, method_map:&'mm method_map) { - + fn visit_expr(&mut self, expr:@Expr, cx: Context<'self>) { + let (method_map, _) = cx; match expr.node { ExprField(base, ident, _) => { // Method calls are now a special syntactic form, @@ -499,11 +569,11 @@ impl<'self> Visitor<&'self method_map> for PrivacyVisitor { _ => {} } - visit::walk_expr(self, expr, method_map); + visit::walk_expr(self, expr, cx); } - fn visit_pat<'mm>(&mut self, pattern:@Pat, method_map:&'mm method_map) { + fn visit_pat(&mut self, pattern:@Pat, cx: Context<'self>) { match pattern.node { PatStruct(_, ref fields, _) => { @@ -550,20 +620,24 @@ impl<'self> Visitor<&'self method_map> for PrivacyVisitor { _ => {} } - visit::walk_pat(self, pattern, method_map); + visit::walk_pat(self, pattern, cx); } } -pub fn check_crate<'mm>(tcx: ty::ctxt, - method_map: &'mm method_map, - crate: &ast::Crate) { +pub fn check_crate(tcx: ty::ctxt, + method_map: &method_map, + exp_map2: &ExportMap2, + crate: &ast::Crate) -> ExportedItems { let privileged_items = @mut ~[]; let mut visitor = PrivacyVisitor { tcx: tcx, privileged_items: privileged_items, + exported_items: HashSet::new(), + path_all_public: true, // start out as public }; - visit::walk_crate(&mut visitor, crate, method_map); + visit::walk_crate(&mut visitor, crate, (method_map, exp_map2)); + return visitor.exported_items; } /// Validates all of the visibility qualifers placed on the item given. This @@ -571,17 +645,45 @@ pub fn check_crate<'mm>(tcx: ty::ctxt, /// anything. In theory these qualifiers wouldn't parse, but that may happen /// later on down the road... fn check_sane_privacy(tcx: ty::ctxt, item: @ast::item) { + let check_inherited = |sp: Span, vis: ast::visibility, note: &str| { + if vis != ast::inherited { + tcx.sess.span_err(sp, "unnecessary visibility qualifier"); + if note.len() > 0 { + tcx.sess.span_note(sp, note); + } + } + }; + let check_not_priv = |sp: Span, vis: ast::visibility, note: &str| { + if vis == ast::private { + tcx.sess.span_err(sp, "unnecessary `priv` qualifier"); + if note.len() > 0 { + tcx.sess.span_note(sp, note); + } + } + }; match item.node { // implementations of traits don't need visibility qualifiers because // that's controlled by having the trait in scope. ast::item_impl(_, Some(*), _, ref methods) => { + check_inherited(item.span, item.vis, + "visibility qualifiers have no effect on trait impls"); for m in methods.iter() { - match m.vis { - ast::private | ast::public => { - tcx.sess.span_err(m.span, "unnecessary visibility") - } - ast::inherited => {} - } + check_inherited(m.span, m.vis, ""); + } + } + + ast::item_impl(_, _, _, ref methods) => { + check_inherited(item.span, item.vis, + "place qualifiers on individual methods instead"); + for i in methods.iter() { + check_not_priv(i.span, i.vis, "functions are private by default"); + } + } + ast::item_foreign_mod(ref fm) => { + check_inherited(item.span, item.vis, + "place qualifiers on individual functions instead"); + for i in fm.items.iter() { + check_not_priv(i.span, i.vis, "functions are private by default"); } } @@ -624,22 +726,18 @@ fn check_sane_privacy(tcx: ty::ctxt, item: @ast::item) { for m in methods.iter() { match *m { ast::provided(ref m) => { - match m.vis { - ast::private | ast::public => { - tcx.sess.span_err(m.span, "unnecessary \ - visibility"); - } - ast::inherited => {} - } + check_inherited(m.span, m.vis, + "unnecessary visibility"); } - // this is warned about in the parser ast::required(*) => {} } } } - ast::item_impl(*) | ast::item_static(*) | ast::item_foreign_mod(*) | + ast::item_static(*) | ast::item_fn(*) | ast::item_mod(*) | ast::item_ty(*) | - ast::item_mac(*) => {} + ast::item_mac(*) => { + check_not_priv(item.span, item.vis, "items are private by default"); + } } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 3a9ef3cf06f..320baf33181 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -1661,6 +1661,9 @@ impl Resolver { ident: Ident, new_parent: ReducedGraphParent) { let privacy = visibility_to_privacy(visibility); + debug!("(building reduced graph for \ + external crate) building external def, priv %?", + privacy); match def { DefMod(def_id) | DefForeignMod(def_id) | DefStruct(def_id) | DefTy(def_id) => { @@ -1788,7 +1791,8 @@ impl Resolver { fn build_reduced_graph_for_external_crate_def(@mut self, root: @mut Module, def_like: DefLike, - ident: Ident) { + ident: Ident, + visibility: visibility) { match def_like { DlDef(def) => { // Add the new child item, if necessary. @@ -1798,11 +1802,12 @@ impl Resolver { // eagerly. do csearch::each_child_of_item(self.session.cstore, def_id) - |def_like, child_ident| { + |def_like, child_ident, vis| { self.build_reduced_graph_for_external_crate_def( root, def_like, - child_ident) + child_ident, + vis) } } _ => { @@ -1813,7 +1818,7 @@ impl Resolver { dummy_sp()); self.handle_external_def(def, - public, + visibility, child_name_bindings, self.session.str_of(ident), ident, @@ -1897,10 +1902,11 @@ impl Resolver { let def = DefFn( static_method_info.def_id, static_method_info.purity); + + let p = visibility_to_privacy( + static_method_info.vis); method_name_bindings.define_value( - Public, - def, - dummy_sp()); + p, def, dummy_sp()); } } @@ -1931,12 +1937,13 @@ impl Resolver { }; do csearch::each_child_of_item(self.session.cstore, def_id) - |def_like, child_ident| { + |def_like, child_ident, visibility| { debug!("(populating external module) ... found ident: %s", token::ident_to_str(&child_ident)); self.build_reduced_graph_for_external_crate_def(module, def_like, - child_ident) + child_ident, + visibility) } module.populated = true } @@ -1956,10 +1963,11 @@ impl Resolver { root: @mut Module) { do csearch::each_top_level_item_of_crate(self.session.cstore, root.def_id.unwrap().crate) - |def_like, ident| { + |def_like, ident, visibility| { self.build_reduced_graph_for_external_crate_def(root, def_like, - ident) + ident, + visibility) } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 67aee43bc46..f9527e6935c 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -3008,6 +3008,7 @@ pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::encode_ diag: diag, tcx: cx.tcx, reexports2: cx.exp_map2, + exported_items: cx.exported_items, item_symbols: item_symbols, discrim_symbols: discrim_symbols, non_inlineable_statics: &cx.non_inlineable_statics, @@ -3101,6 +3102,7 @@ pub fn trans_crate(sess: session::Session, llmod_id, analysis.ty_cx, analysis.exp_map2, + analysis.exported_items, analysis.maps, symbol_hasher, link_meta, diff --git a/src/librustc/middle/trans/context.rs b/src/librustc/middle/trans/context.rs index e342bcaf4fa..134db45be43 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -16,6 +16,7 @@ use lib::llvm::{llvm, TargetData, TypeNames}; use lib::llvm::mk_target_data; use metadata::common::LinkMeta; use middle::astencode; +use middle::privacy; use middle::resolve; use middle::trans::adt; use middle::trans::base; @@ -49,6 +50,7 @@ pub struct CrateContext { intrinsics: HashMap<&'static str, ValueRef>, item_vals: HashMap, exp_map2: resolve::ExportMap2, + exported_items: @privacy::ExportedItems, reachable: @mut HashSet, item_symbols: HashMap, link_meta: LinkMeta, @@ -127,6 +129,7 @@ impl CrateContext { name: &str, tcx: ty::ctxt, emap2: resolve::ExportMap2, + exported_items: @privacy::ExportedItems, maps: astencode::Maps, symbol_hasher: hash::State, link_meta: LinkMeta, @@ -187,6 +190,7 @@ impl CrateContext { intrinsics: intrinsics, item_vals: HashMap::new(), exp_map2: emap2, + exported_items: exported_items, reachable: reachable, item_symbols: HashMap::new(), link_meta: link_meta, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index ba2342d7827..5111682f6d0 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -702,7 +702,7 @@ impl AstBuilder for @ExtCtxt { attrs: attrs, id: ast::DUMMY_NODE_ID, node: node, - vis: ast::public, + vis: ast::inherited, span: span } } diff --git a/src/libsyntax/parse/obsolete.rs b/src/libsyntax/parse/obsolete.rs index b056b39eb6e..fe2aa05584d 100644 --- a/src/libsyntax/parse/obsolete.rs +++ b/src/libsyntax/parse/obsolete.rs @@ -44,7 +44,6 @@ pub enum ObsoleteSyntax { ObsoleteImplSyntax, ObsoleteMutOwnedPointer, ObsoleteMutVector, - ObsoleteImplVisibility, ObsoleteRecordType, ObsoleteRecordPattern, ObsoletePostFnTySigil, @@ -60,9 +59,7 @@ pub enum ObsoleteSyntax { ObsoleteNamedExternModule, ObsoleteMultipleLocalDecl, ObsoleteMutWithMultipleBindings, - ObsoleteExternVisibility, ObsoleteUnsafeExternFn, - ObsoletePrivVisibility, ObsoleteTraitFuncVisibility, ObsoleteConstPointer, } @@ -161,11 +158,6 @@ impl ParserObsoleteMethods for Parser { in a mutable location, like a mutable local variable or an \ `@mut` box" ), - ObsoleteImplVisibility => ( - "visibility-qualified implementation", - "`pub` or `priv` goes on individual functions; remove the \ - `pub` or `priv`" - ), ObsoleteRecordType => ( "structural record type", "use a structure instead" @@ -233,20 +225,11 @@ impl ParserObsoleteMethods for Parser { "use multiple local declarations instead of e.g. `let mut \ (x, y) = ...`." ), - ObsoleteExternVisibility => ( - "`pub extern` or `priv extern`", - "place the `pub` or `priv` on the individual external items \ - instead" - ), ObsoleteUnsafeExternFn => ( "unsafe external function", "external functions are always unsafe; remove the `unsafe` \ keyword" ), - ObsoletePrivVisibility => ( - "`priv` not necessary", - "an item without a visibility qualifier is private by default" - ), ObsoleteTraitFuncVisibility => ( "visibility not necessary", "trait functions inherit the visibility of the trait itself" diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 4aad5c24d0f..c0dcafa8fb2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -922,7 +922,7 @@ impl Parser { let attrs = p.parse_outer_attributes(); let lo = p.span.lo; - let vis = p.parse_non_priv_visibility(); + let vis = p.parse_visibility(); let pur = p.parse_fn_purity(); // NB: at the moment, trait methods are public by default; this // could change. @@ -3753,7 +3753,7 @@ impl Parser { let attrs = self.parse_outer_attributes(); let lo = self.span.lo; - let visa = self.parse_non_priv_visibility(); + let visa = self.parse_visibility(); let pur = self.parse_fn_purity(); let ident = self.parse_ident(); let generics = self.parse_generics(); @@ -3801,7 +3801,7 @@ impl Parser { // Parses two variants (with the region/type params always optional): // impl Foo { ... } // impl ToStr for ~[T] { ... } - fn parse_item_impl(&self, visibility: ast::visibility) -> item_info { + fn parse_item_impl(&self) -> item_info { // First, parse type parameters if necessary. let generics = self.parse_generics(); @@ -3846,11 +3846,6 @@ impl Parser { None }; - // Do not allow visibility to be specified. - if visibility != ast::inherited { - self.obsolete(*self.span, ObsoleteImplVisibility); - } - let mut meths = ~[]; if !self.eat(&token::SEMI) { self.expect(&token::LBRACE); @@ -4012,18 +4007,6 @@ impl Parser { else { inherited } } - // parse visibility, but emits an obsolete error if it's private - fn parse_non_priv_visibility(&self) -> visibility { - match self.parse_visibility() { - public => public, - inherited => inherited, - private => { - self.obsolete(*self.last_span, ObsoletePrivVisibility); - inherited - } - } - } - fn parse_staticness(&self) -> bool { if self.eat_keyword(keywords::Static) { self.obsolete(*self.last_span, ObsoleteStaticMethod); @@ -4216,7 +4199,7 @@ impl Parser { // parse a function declaration from a foreign module fn parse_item_foreign_fn(&self, attrs: ~[Attribute]) -> @foreign_item { let lo = self.span.lo; - let vis = self.parse_non_priv_visibility(); + let vis = self.parse_visibility(); // Parse obsolete purity. let purity = self.parse_fn_purity(); @@ -4352,11 +4335,6 @@ impl Parser { self.obsolete(*self.last_span, ObsoleteNamedExternModule); } - // Do not allow visibility to be specified. - if visibility != ast::inherited { - self.obsolete(*self.last_span, ObsoleteExternVisibility); - } - let abis = opt_abis.unwrap_or(AbiSet::C()); let (inner, next) = self.parse_inner_attrs_and_next(); @@ -4367,7 +4345,7 @@ impl Parser { self.last_span.hi, ident, item_foreign_mod(m), - public, + visibility, maybe_append(attrs, Some(inner)))); } @@ -4614,7 +4592,7 @@ impl Parser { let lo = self.span.lo; - let visibility = self.parse_non_priv_visibility(); + let visibility = self.parse_visibility(); // must be a view item: if self.eat_keyword(keywords::Use) { @@ -4722,8 +4700,7 @@ impl Parser { } if self.eat_keyword(keywords::Impl) { // IMPL ITEM - let (ident, item_, extra_attrs) = - self.parse_item_impl(visibility); + let (ident, item_, extra_attrs) = self.parse_item_impl(); return iovi_item(self.mk_item(lo, self.last_span.hi, ident, item_, visibility, maybe_append(attrs, extra_attrs))); @@ -4746,7 +4723,7 @@ impl Parser { maybe_whole!(iovi self, nt_item); let lo = self.span.lo; - let visibility = self.parse_non_priv_visibility(); + let visibility = self.parse_visibility(); if (self.is_keyword(keywords::Const) || self.is_keyword(keywords::Static)) { // FOREIGN CONST ITEM diff --git a/src/test/auxiliary/issue2378a.rs b/src/test/auxiliary/issue2378a.rs index 88439e32b0d..ea14229cc48 100644 --- a/src/test/auxiliary/issue2378a.rs +++ b/src/test/auxiliary/issue2378a.rs @@ -11,7 +11,7 @@ #[link (name = "issue2378a")]; #[crate_type = "lib"]; -enum maybe { just(T), nothing } +pub enum maybe { just(T), nothing } impl Index for maybe { fn index(&self, _idx: &uint) -> T { diff --git a/src/test/auxiliary/issue2378b.rs b/src/test/auxiliary/issue2378b.rs index d2c42bacc63..71c0bab138f 100644 --- a/src/test/auxiliary/issue2378b.rs +++ b/src/test/auxiliary/issue2378b.rs @@ -15,7 +15,7 @@ extern mod issue2378a; use issue2378a::maybe; -struct two_maybes {a: maybe, b: maybe} +pub struct two_maybes {a: maybe, b: maybe} impl Index for two_maybes { fn index(&self, idx: &uint) -> (T, T) { diff --git a/src/test/auxiliary/nested_item.rs b/src/test/auxiliary/nested_item.rs index c2f38134d1e..96bae656390 100644 --- a/src/test/auxiliary/nested_item.rs +++ b/src/test/auxiliary/nested_item.rs @@ -9,7 +9,7 @@ // except according to those terms. // original problem -fn foo() -> int { +pub fn foo() -> int { { static foo: int = 2; foo diff --git a/src/test/auxiliary/packed.rs b/src/test/auxiliary/packed.rs index 478d51b540c..150de8d314d 100644 --- a/src/test/auxiliary/packed.rs +++ b/src/test/auxiliary/packed.rs @@ -1,5 +1,5 @@ #[packed] -struct S { +pub struct S { a: u8, b: u32 } diff --git a/src/test/auxiliary/static_priv_by_default.rs b/src/test/auxiliary/static_priv_by_default.rs new file mode 100644 index 00000000000..d46ccf299e8 --- /dev/null +++ b/src/test/auxiliary/static_priv_by_default.rs @@ -0,0 +1,57 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[crate_type = "lib"]; +#[no_std]; + +static private: int = 0; +pub static public: int = 0; + +pub struct A(()); + +impl A { + fn foo() {} +} + +mod foo { + pub static a: int = 0; + pub fn b() {} + pub struct c; + pub enum d {} + + pub struct A(()); + + impl A { + fn foo() {} + } + + // these are public so the parent can reexport them. + pub static reexported_a: int = 0; + pub fn reexported_b() {} + pub struct reexported_c; + pub enum reexported_d {} +} + +pub mod bar { + pub use e = foo::reexported_a; + pub use f = foo::reexported_b; + pub use g = foo::reexported_c; + pub use h = foo::reexported_d; +} + +pub static a: int = 0; +pub fn b() {} +pub struct c; +pub enum d {} + +static i: int = 0; +fn j() {} +struct k; +enum l {} diff --git a/src/test/compile-fail/obsolete-syntax.rs b/src/test/compile-fail/obsolete-syntax.rs index 49af0972341..872f3b1010e 100644 --- a/src/test/compile-fail/obsolete-syntax.rs +++ b/src/test/compile-fail/obsolete-syntax.rs @@ -54,9 +54,9 @@ extern mod obsolete_name { fn bar(); } -pub extern { - //~^ ERROR obsolete syntax: `pub extern` - pub fn bar(); +trait A { + pub fn foo(); //~ ERROR: visibility not necessary + pub fn bar(); //~ ERROR: visibility not necessary } fn main() { } diff --git a/src/test/compile-fail/priv-in-bad-locations.rs b/src/test/compile-fail/priv-in-bad-locations.rs new file mode 100644 index 00000000000..db649ed0cc6 --- /dev/null +++ b/src/test/compile-fail/priv-in-bad-locations.rs @@ -0,0 +1,28 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub extern { + //~^ ERROR unnecessary visibility + pub fn bar(); +} + +trait A { + fn foo() {} +} + +struct B; + +pub impl B {} //~ ERROR: unnecessary visibility + +pub impl A for B { //~ ERROR: unnecessary visibility + pub fn foo() {} //~ ERROR: unnecessary visibility +} + +pub fn main() {} diff --git a/src/test/compile-fail/static-priv-by-default.rs b/src/test/compile-fail/static-priv-by-default.rs new file mode 100644 index 00000000000..59d7e23855c --- /dev/null +++ b/src/test/compile-fail/static-priv-by-default.rs @@ -0,0 +1,39 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:static_priv_by_default.rs + +#[no_std]; + +extern mod static_priv_by_default; + +mod child { + pub mod childs_child { + static private: int = 0; + pub static public: int = 0; + } +} + +fn foo(_: int) {} + +fn full_ref() { + foo(static_priv_by_default::private); //~ ERROR: unresolved name + foo(static_priv_by_default::public); + foo(child::childs_child::private); //~ ERROR: unresolved name + foo(child::childs_child::public); +} + +fn medium_ref() { + use child::childs_child; + foo(childs_child::private); //~ ERROR: unresolved name + foo(childs_child::public); +} + +fn main() {} diff --git a/src/test/compile-fail/static-priv-by-default2.rs b/src/test/compile-fail/static-priv-by-default2.rs new file mode 100644 index 00000000000..28a17cf5e1c --- /dev/null +++ b/src/test/compile-fail/static-priv-by-default2.rs @@ -0,0 +1,29 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:static_priv_by_default.rs + +extern mod static_priv_by_default; + +mod child { + pub mod childs_child { + static private: int = 0; + pub static public: int = 0; + } +} + +fn main() { + use static_priv_by_default::private; //~ ERROR: unresolved import + //~^ ERROR: failed to resolve + use static_priv_by_default::public; + use child::childs_child::private; //~ ERROR: unresolved import + //~^ ERROR: failed to resolve + use child::childs_child::public; +} diff --git a/src/test/compile-fail/useless-priv2.rs b/src/test/compile-fail/useless-priv2.rs index 0d94300329c..29c87e77ac0 100644 --- a/src/test/compile-fail/useless-priv2.rs +++ b/src/test/compile-fail/useless-priv2.rs @@ -12,8 +12,3 @@ pub trait E { pub fn foo(); //~ ERROR: obsolete syntax } trait F { pub fn foo(); } //~ ERROR: obsolete syntax - -struct B; -impl E for B { - priv fn foo() {} //~ ERROR: obsolete syntax -} diff --git a/src/test/compile-fail/xc-private-method.rs b/src/test/compile-fail/xc-private-method.rs index 371bac7a902..b4a999766b5 100644 --- a/src/test/compile-fail/xc-private-method.rs +++ b/src/test/compile-fail/xc-private-method.rs @@ -1,16 +1,22 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + // xfail-fast // aux-build:xc_private_method_lib.rs extern mod xc_private_method_lib; fn main() { - // normal method on struct - let _ = xc_private_method_lib::Struct{ x: 10 }.meth_struct(); //~ ERROR method `meth_struct` is private - // static method on struct - let _ = xc_private_method_lib::Struct::static_meth_struct(); //~ ERROR method `static_meth_struct` is private + let _ = xc_private_method_lib::Struct::static_meth_struct(); + //~^ ERROR: unresolved name - // normal method on enum - let _ = xc_private_method_lib::Variant1(20).meth_enum(); //~ ERROR method `meth_enum` is private - // static method on enum - let _ = xc_private_method_lib::Enum::static_meth_enum(); //~ ERROR method `static_meth_enum` is private + let _ = xc_private_method_lib::Enum::static_meth_enum(); + //~^ ERROR: unresolved name } diff --git a/src/test/compile-fail/xc-private-method2.rs b/src/test/compile-fail/xc-private-method2.rs new file mode 100644 index 00000000000..c2eaa9287f4 --- /dev/null +++ b/src/test/compile-fail/xc-private-method2.rs @@ -0,0 +1,20 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// xfail-fast +// aux-build:xc_private_method_lib.rs + +extern mod xc_private_method_lib; + +fn main() { + let _ = xc_private_method_lib::Struct{ x: 10 }.meth_struct(); //~ ERROR method `meth_struct` is private + + let _ = xc_private_method_lib::Variant1(20).meth_enum(); //~ ERROR method `meth_enum` is private +} diff --git a/src/test/compile-fail/xcrate-private-by-default.rs b/src/test/compile-fail/xcrate-private-by-default.rs new file mode 100644 index 00000000000..38649981f93 --- /dev/null +++ b/src/test/compile-fail/xcrate-private-by-default.rs @@ -0,0 +1,57 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// aux-build:static_priv_by_default.rs + +#[allow(unused_imports)]; +#[no_std]; + +extern mod static_priv_by_default; + +fn foo() {} + +#[start] +fn main(_: int, _: **u8, _: *u8) -> int { + // Actual public items should be public + static_priv_by_default::a; + static_priv_by_default::b; + static_priv_by_default::c; + foo::(); + + // publicly re-exported items should be available + static_priv_by_default::bar::e; + static_priv_by_default::bar::f; + static_priv_by_default::bar::g; + foo::(); + + // private items at the top should be inaccessible + static_priv_by_default::i; + //~^ ERROR: unresolved name + static_priv_by_default::j; + //~^ ERROR: unresolved name + static_priv_by_default::k; + //~^ ERROR: unresolved name + foo::(); + //~^ ERROR: use of undeclared type name + //~^^ ERROR: use of undeclared type name + + // public items in a private mod should be inaccessible + static_priv_by_default::foo::a; + //~^ ERROR: unresolved name + static_priv_by_default::foo::b; + //~^ ERROR: unresolved name + static_priv_by_default::foo::c; + //~^ ERROR: unresolved name + foo::(); + //~^ ERROR: use of undeclared type name + //~^^ ERROR: use of undeclared type name + + 3 +}