about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libextra/arc.rs4
-rw-r--r--src/libextra/workcache.rs12
-rw-r--r--src/librustc/driver/driver.rs7
-rw-r--r--src/librustc/metadata/csearch.rs9
-rw-r--r--src/librustc/metadata/decoder.rs43
-rw-r--r--src/librustc/metadata/encoder.rs23
-rw-r--r--src/librustc/metadata/filesearch.rs2
-rw-r--r--src/librustc/middle/privacy.rs190
-rw-r--r--src/librustc/middle/resolve.rs30
-rw-r--r--src/librustc/middle/trans/base.rs2
-rw-r--r--src/librustc/middle/trans/context.rs4
-rw-r--r--src/libsyntax/ext/build.rs2
-rw-r--r--src/libsyntax/parse/obsolete.rs17
-rw-r--r--src/libsyntax/parse/parser.rs39
-rw-r--r--src/test/auxiliary/issue2378a.rs2
-rw-r--r--src/test/auxiliary/issue2378b.rs2
-rw-r--r--src/test/auxiliary/nested_item.rs2
-rw-r--r--src/test/auxiliary/packed.rs2
-rw-r--r--src/test/auxiliary/static_priv_by_default.rs57
-rw-r--r--src/test/compile-fail/obsolete-syntax.rs6
-rw-r--r--src/test/compile-fail/priv-in-bad-locations.rs28
-rw-r--r--src/test/compile-fail/static-priv-by-default.rs39
-rw-r--r--src/test/compile-fail/static-priv-by-default2.rs29
-rw-r--r--src/test/compile-fail/useless-priv2.rs5
-rw-r--r--src/test/compile-fail/xc-private-method.rs22
-rw-r--r--src/test/compile-fail/xc-private-method2.rs20
-rw-r--r--src/test/compile-fail/xcrate-private-by-default.rs57
27 files changed, 494 insertions, 161 deletions
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<T> { priv lock: Mutex, priv failed: bool, priv data: T }
 
 /// An Arc with mutable data protected by a blocking mutex.
 #[no_freeze]
-struct MutexArc<T> { priv x: UnsafeArc<MutexArcInner<T>> }
+pub struct MutexArc<T> { priv x: UnsafeArc<MutexArcInner<T>> }
 
 
 impl<T:Send> Clone for MutexArc<T> {
@@ -343,7 +343,7 @@ struct RWArcInner<T> { 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<T> {
+pub struct RWArc<T> {
     priv x: UnsafeArc<RWArcInner<T>>,
 }
 
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<Database>,
     logger: RWArc<Logger>,
     cfg: Arc<json::Object>,
@@ -239,13 +239,13 @@ struct Context {
     freshness: Arc<FreshnessMap>
 }
 
-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<ast::NodeId>
@@ -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<ast::NodeId, ~str>,
     discrim_symbols: &'self HashMap<ast::NodeId, @str>,
     non_inlineable_statics: &'self HashSet<ast::NodeId>,
@@ -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<ast::NodeId, ~str>,
     discrim_symbols: &'self HashMap<ast::NodeId, @str>,
     non_inlineable_statics: &'self HashSet<ast::NodeId>,
@@ -881,7 +883,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
                         ebml_w: &mut writer::Encoder,
                         item: @item,
                         index: @mut ~[entry<i64>],
-                        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<NodeId>;
+
+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<Context<'self>> 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") {
+            return;
+        }
+
+        // Disallow unnecessary visibility qualifiers
+        check_sane_privacy(self.tcx, item);
 
-            // 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);
+        // 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<ast::NodeId, ValueRef>,
      exp_map2: resolve::ExportMap2,
+     exported_items: @privacy::ExportedItems,
      reachable: @mut HashSet<ast::NodeId>,
      item_symbols: HashMap<ast::NodeId, ~str>,
      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<T> Foo { ... }
     //    impl<T> 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<T> { just(T), nothing }
+pub enum maybe<T> { just(T), nothing }
 
 impl <T:Clone> Index<uint,T> for maybe<T> {
     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<T> {a: maybe<T>, b: maybe<T>}
+pub struct two_maybes<T> {a: maybe<T>, b: maybe<T>}
 
 impl<T:Clone> Index<uint,(T,T)> for two_maybes<T> {
     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<T>() -> int {
+pub fn foo<T>() -> 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T>() {}
+
+#[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::<static_priv_by_default::d>();
+
+    // 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::<static_priv_by_default::bar::h>();
+
+    // 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::<static_priv_by_default::l>();
+    //~^ 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::<static_priv_by_default::foo::d>();
+    //~^ ERROR: use of undeclared type name
+    //~^^ ERROR: use of undeclared type name
+
+    3
+}