diff --git a/src/librustc/driver/driver.rs b/src/librustc/driver/driver.rs index 1ddebbb428010..9994ab885f507 100644 --- a/src/librustc/driver/driver.rs +++ b/src/librustc/driver/driver.rs @@ -195,6 +195,7 @@ pub fn phase_2_configure_and_expand(sess: Session, pub struct CrateAnalysis { exp_map2: middle::resolve::ExportMap2, + exported_items: @mut middle::resolve::ExportedItems, ty_cx: ty::ctxt, maps: astencode::Maps, reachable: @mut HashSet @@ -223,7 +224,8 @@ pub fn phase_3_run_analysis_passes(sess: Session, let middle::resolve::CrateMap { def_map: def_map, exp_map2: exp_map2, - trait_map: trait_map + trait_map: trait_map, + exported_items: exported_items } = time(time_passes, ~"resolution", || middle::resolve::resolve_crate(sess, lang_items, crate)); @@ -298,6 +300,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 317b9cf6ce34f..e505e57db2ec0 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::def_id, - purity: ast::purity + purity: ast::purity, + vis: ast::visibility, } pub fn get_symbol(cstore: @mut cstore::CStore, def: ast::def_id) -> ~str { diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 9eb09806bc07d..56f414cc716e8 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -525,7 +525,8 @@ impl<'self> EachItemContext<'self> { fn process_item_and_pop_name(&mut self, doc: ebml::Doc, def_id: ast::def_id, - 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 { @@ -544,8 +545,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); @@ -634,9 +633,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 @@ -682,12 +684,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); } } @@ -1007,7 +1010,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 dbed508348d03..65813c27af669 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::hash::HashUtil; @@ -58,6 +58,7 @@ pub struct EncodeParams<'self> { diag: @mut span_handler, tcx: ty::ctxt, reexports2: middle::resolve::ExportMap2, + exported_items: @mut middle::resolve::ExportedItems, item_symbols: &'self HashMap, discrim_symbols: &'self HashMap, link_meta: &'self LinkMeta, @@ -86,6 +87,7 @@ pub struct EncodeContext<'self> { tcx: ty::ctxt, stats: @mut Stats, reexports2: middle::resolve::ExportMap2, + exported_items: @mut middle::resolve::ExportedItems, item_symbols: &'self HashMap, discrim_symbols: &'self HashMap, link_meta: &'self LinkMeta, @@ -808,7 +810,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, @@ -836,6 +839,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)); (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, _) => { @@ -853,6 +857,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) => { @@ -879,7 +884,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(*) => { @@ -891,6 +896,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) => { @@ -907,6 +913,7 @@ fn encode_info_for_item(ecx: &EncodeContext, (ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item)); 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(); encode_enum_variant_info(ecx, @@ -938,6 +945,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 @@ -1187,7 +1195,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") } @@ -1592,6 +1605,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] { diag, tcx, reexports2, + exported_items, discrim_symbols, cstore, encode_inlined_item, @@ -1606,6 +1620,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, link_meta: link_meta, diff --git a/src/librustc/metadata/filesearch.rs b/src/librustc/metadata/filesearch.rs index 33d517f3981bb..c5bd45cdeef3f 100644 --- a/src/librustc/metadata/filesearch.rs +++ b/src/librustc/metadata/filesearch.rs @@ -128,7 +128,7 @@ fn make_target_lib_path(sysroot: &Path, sysroot.push_rel(&relative_target_lib_path(target_triple)) } -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 222bef641d224..4918313f706f0 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -261,12 +261,12 @@ impl PrivacyVisitor { fmt!("function `%s` is private", token::ident_to_str(path.idents.last()))); } - } 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.idents.last()))); } + // 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. } _ => {} } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index 2e8748e4ff832..66b4e66adc823 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -65,6 +65,11 @@ pub struct Export2 { reexport: bool, // Whether this is a reexport. } +// 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; + #[deriving(Eq)] pub enum PatternBindingMode { RefutableMode, @@ -818,6 +823,7 @@ pub fn Resolver(session: Session, xray_context: NoXray, current_trait_refs: None, + path_all_public: true, self_ident: special_idents::self_, type_self_ident: special_idents::type_self, @@ -830,6 +836,7 @@ pub fn Resolver(session: Session, export_map2: @mut HashMap::new(), trait_map: HashMap::new(), used_imports: HashSet::new(), + exported_items: @mut HashSet::new(), emit_errors: true, intr: session.intr() @@ -874,6 +881,13 @@ pub struct Resolver { // The trait that the current context can refer to. current_trait_refs: Option<~[def_id]>, + // A set of all items which are re-exported to be used across crates + exported_items: @mut ExportedItems, + + // When determinining the list of exported items, this is relevant for + // determining if `pub` uses should be re-exported across crates + path_all_public: bool, + // The ident for the keyword "self". self_ident: ident, // The ident for the non-keyword "Self". @@ -1780,8 +1794,8 @@ impl Resolver { |path_string, def_like, visibility| { debug!("(building reduced graph for external crate) found path \ - entry: %s (%?)", - path_string, def_like); + entry: %s (%?, %?)", + path_string, def_like, visibility); let mut pieces: ~[&str] = path_string.split_str_iter("::").collect(); let final_ident_str = pieces.pop(); @@ -1927,8 +1941,10 @@ impl Resolver { let def = def_fn( 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()); } } @@ -3252,14 +3268,15 @@ impl Resolver { match (namebindings.def_for_namespace(ns), namebindings.privacy_for_namespace(ns)) { (Some(d), Some(Public)) => { + let def = def_id_of_def(d); debug!("(computing exports) YES: %s '%s' => %?", if reexport { ~"reexport" } else { ~"export"}, self.session.str_of(ident), - def_id_of_def(d)); + def); exports2.push(Export2 { reexport: reexport, name: self.session.str_of(ident), - def_id: def_id_of_def(d) + def_id: def, }); } (Some(_), Some(privacy)) => { @@ -3511,6 +3528,13 @@ impl Resolver { self.xray_context = Xray; } + let orig_path_all_public = self.path_all_public; + self.path_all_public = self.path_all_public && item.vis == ast::public; + + if self.path_all_public { + self.exported_items.insert(item.id); + } + match item.node { // enum item: resolve all the variants' discrs, @@ -3550,6 +3574,10 @@ impl Resolver { ref implemented_traits, ref self_type, ref methods) => { + self.path_all_public = orig_path_all_public; + if self.path_all_public { + self.exported_items.insert(item.id); + } self.resolve_implementation(item.id, generics, implemented_traits, @@ -3634,6 +3662,11 @@ impl Resolver { } item_foreign_mod(ref foreign_module) => { + self.path_all_public = orig_path_all_public; + if self.path_all_public { + self.exported_items.insert(item.id); + } + do self.with_scope(Some(item.ident)) { for foreign_item in foreign_module.items.iter() { match foreign_item.node { @@ -3681,6 +3714,7 @@ impl Resolver { } self.xray_context = orig_xray_flag; + self.path_all_public = orig_path_all_public; } pub fn with_type_parameter_rib(@mut self, @@ -5464,8 +5498,9 @@ impl Resolver { pub struct CrateMap { def_map: DefMap, + trait_map: TraitMap, exp_map2: ExportMap2, - trait_map: TraitMap + exported_items: @mut ExportedItems, } /// Entry point to crate resolution. @@ -5478,6 +5513,7 @@ pub fn resolve_crate(session: Session, CrateMap { def_map: resolver.def_map, exp_map2: resolver.export_map2, + exported_items: resolver.exported_items, trait_map: resolver.trait_map.clone(), } } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index f735c059ab615..0dc770fcd7f5e 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -2906,6 +2906,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, link_meta: link_meta, @@ -2998,6 +2999,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 1318ef2c8958d..0a03436cf6788 100644 --- a/src/librustc/middle/trans/context.rs +++ b/src/librustc/middle/trans/context.rs @@ -49,6 +49,7 @@ pub struct CrateContext { intrinsics: HashMap<&'static str, ValueRef>, item_vals: HashMap, exp_map2: resolve::ExportMap2, + exported_items: @mut resolve::ExportedItems, reachable: @mut HashSet, item_symbols: HashMap, link_meta: LinkMeta, @@ -120,6 +121,7 @@ impl CrateContext { name: &str, tcx: ty::ctxt, emap2: resolve::ExportMap2, + exported_items: @mut resolve::ExportedItems, maps: astencode::Maps, symbol_hasher: hash::State, link_meta: LinkMeta, @@ -180,6 +182,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/test/auxiliary/issue2378a.rs b/src/test/auxiliary/issue2378a.rs index 88439e32b0dda..ea14229cc48a7 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 d2c42bacc63a9..71c0bab138f46 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/packed.rs b/src/test/auxiliary/packed.rs index 478d51b540cdf..150de8d314d8f 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 0000000000000..c860b5a3ef685 --- /dev/null +++ b/src/test/auxiliary/static_priv_by_default.rs @@ -0,0 +1,47 @@ +// 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"]; + +pub use e = foo::a; +pub use f = foo::b; +pub use g = foo::c; +pub use h = foo::d; + +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() {} + } +} + +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/static-priv-by-default.rs b/src/test/compile-fail/static-priv-by-default.rs new file mode 100644 index 0000000000000..88671f259677f --- /dev/null +++ b/src/test/compile-fail/static-priv-by-default.rs @@ -0,0 +1,37 @@ +// 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 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 0000000000000..28a17cf5e1c5c --- /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/xcrate-private-by-default.rs b/src/test/compile-fail/xcrate-private-by-default.rs new file mode 100644 index 0000000000000..9abd13365e5ca --- /dev/null +++ b/src/test/compile-fail/xcrate-private-by-default.rs @@ -0,0 +1,55 @@ +// 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; + +fn main() { + // Actual public items should be public + use static_priv_by_default::a; + use static_priv_by_default::b; + use static_priv_by_default::c; + use static_priv_by_default::d; + + // publicly re-exported items should be available + use static_priv_by_default::e; + use static_priv_by_default::f; + use static_priv_by_default::g; + use static_priv_by_default::h; + + // private items at the top should be inaccessible + use static_priv_by_default::i; + //~^ ERROR: unresolved import + //~^^ ERROR: failed to resolve + use static_priv_by_default::j; + //~^ ERROR: unresolved import + //~^^ ERROR: failed to resolve + use static_priv_by_default::k; + //~^ ERROR: unresolved import + //~^^ ERROR: failed to resolve + use static_priv_by_default::l; + //~^ ERROR: unresolved import + //~^^ ERROR: failed to resolve + + // public items in a private mod should be inaccessible + use static_priv_by_default::foo::a; + //~^ ERROR: unresolved import + //~^^ ERROR: failed to resolve + use static_priv_by_default::foo::b; + //~^ ERROR: unresolved import + //~^^ ERROR: failed to resolve + use static_priv_by_default::foo::c; + //~^ ERROR: unresolved import + //~^^ ERROR: failed to resolve + use static_priv_by_default::foo::d; + //~^ ERROR: unresolved import + //~^^ ERROR: failed to resolve +}