about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-04-03 18:41:45 -0700
committerbors <bors@rust-lang.org>2014-04-03 18:41:45 -0700
commitc2e457686b77a7eec906549b73feba314667235b (patch)
tree7502e270074fa24186b7599ee78ec4116cd96261
parente7fe20722904cd2829a65f845ee7a1718cdf7292 (diff)
parent922dcfdc6950f4d68d3334199de5572eef52b75a (diff)
downloadrust-c2e457686b77a7eec906549b73feba314667235b.tar.gz
rust-c2e457686b77a7eec906549b73feba314667235b.zip
auto merge of #13237 : alexcrichton/rust/private-tuple-structs, r=brson
This is the final commit need to implement [RFC #4](https://github.com/rust-lang/rfcs/blob/master/active/0004-private-fields.md), it makes all tuple struct fields private by default, overridable with the `pub` keyword.

I'll note one divergence from the original RFC which is outlined in the first commit.
-rw-r--r--src/librand/distributions/exponential.rs2
-rw-r--r--src/librand/distributions/normal.rs2
-rw-r--r--src/librand/lib.rs4
-rw-r--r--src/librustc/metadata/csearch.rs8
-rw-r--r--src/librustc/metadata/decoder.rs11
-rw-r--r--src/librustc/middle/graph.rs4
-rw-r--r--src/librustc/middle/privacy.rs119
-rw-r--r--src/librustc/middle/trans/basic_block.rs2
-rw-r--r--src/librustc/middle/trans/value.rs2
-rw-r--r--src/librustc/middle/ty.rs6
-rw-r--r--src/librustc/middle/typeck/infer/coercion.rs2
-rw-r--r--src/librustc/middle/typeck/infer/glb.rs2
-rw-r--r--src/librustc/middle/typeck/infer/lub.rs2
-rw-r--r--src/librustc/middle/typeck/infer/sub.rs2
-rw-r--r--src/librustdoc/html/escape.rs2
-rw-r--r--src/librustdoc/html/format.rs6
-rw-r--r--src/librustdoc/html/markdown.rs4
-rw-r--r--src/libstd/rt/task.rs2
-rw-r--r--src/libstd/unstable/simd.rs28
-rw-r--r--src/libsyntax/ast.rs12
-rw-r--r--src/libsyntax/ast_map.rs2
-rw-r--r--src/libsyntax/codemap.rs4
-rw-r--r--src/test/auxiliary/issue-11508.rs2
-rw-r--r--src/test/auxiliary/issue-11529.rs2
-rw-r--r--src/test/auxiliary/issue-7899.rs2
-rw-r--r--src/test/auxiliary/issue_10031_aux.rs2
-rw-r--r--src/test/auxiliary/issue_2472_b.rs2
-rw-r--r--src/test/auxiliary/lint_stability.rs14
-rw-r--r--src/test/auxiliary/newtype_struct_xc.rs2
-rw-r--r--src/test/auxiliary/privacy-tuple-struct.rs14
-rw-r--r--src/test/compile-fail/privacy5.rs137
31 files changed, 326 insertions, 79 deletions
diff --git a/src/librand/distributions/exponential.rs b/src/librand/distributions/exponential.rs
index 5cd53ca88a9..70dd0da3130 100644
--- a/src/librand/distributions/exponential.rs
+++ b/src/librand/distributions/exponential.rs
@@ -28,7 +28,7 @@ use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
 /// Generate Normal Random
 /// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
 /// College, Oxford
-pub struct Exp1(f64);
+pub struct Exp1(pub f64);
 
 // This could be done via `-rng.gen::<f64>().ln()` but that is slower.
 impl Rand for Exp1 {
diff --git a/src/librand/distributions/normal.rs b/src/librand/distributions/normal.rs
index 7340d00929e..2745ddd4ce7 100644
--- a/src/librand/distributions/normal.rs
+++ b/src/librand/distributions/normal.rs
@@ -27,7 +27,7 @@ use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample};
 /// Generate Normal Random
 /// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
 /// College, Oxford
-pub struct StandardNormal(f64);
+pub struct StandardNormal(pub f64);
 
 impl Rand for StandardNormal {
     fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
diff --git a/src/librand/lib.rs b/src/librand/lib.rs
index cc2051fc80b..1784349b1eb 100644
--- a/src/librand/lib.rs
+++ b/src/librand/lib.rs
@@ -666,7 +666,7 @@ pub fn random<T: Rand>() -> T {
 /// let Open01(val) = random::<Open01<f32>>();
 /// println!("f32 from (0,1): {}", val);
 /// ```
-pub struct Open01<F>(F);
+pub struct Open01<F>(pub F);
 
 /// A wrapper for generating floating point numbers uniformly in the
 /// closed interval `[0,1]` (including both endpoints).
@@ -682,7 +682,7 @@ pub struct Open01<F>(F);
 /// let Closed01(val) = random::<Closed01<f32>>();
 /// println!("f32 from [0,1]: {}", val);
 /// ```
-pub struct Closed01<F>(F);
+pub struct Closed01<F>(pub F);
 
 #[cfg(test)]
 mod test {
diff --git a/src/librustc/metadata/csearch.rs b/src/librustc/metadata/csearch.rs
index 4300c2eedbf..977db296af9 100644
--- a/src/librustc/metadata/csearch.rs
+++ b/src/librustc/metadata/csearch.rs
@@ -290,3 +290,11 @@ pub fn get_exported_macros(cstore: &cstore::CStore,
     let cdata = cstore.get_crate_data(crate_num);
     decoder::get_exported_macros(cdata)
 }
+
+pub fn get_tuple_struct_definition_if_ctor(cstore: &cstore::CStore,
+                                           def_id: ast::DefId)
+    -> Option<ast::DefId>
+{
+    let cdata = cstore.get_crate_data(def_id.krate);
+    decoder::get_tuple_struct_definition_if_ctor(cdata, def_id.node)
+}
diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs
index dc8acf63719..556f0a38b03 100644
--- a/src/librustc/metadata/decoder.rs
+++ b/src/librustc/metadata/decoder.rs
@@ -929,23 +929,26 @@ pub fn get_static_methods_if_impl(intr: Rc<IdentInterner>,
 /// If node_id is the constructor of a tuple struct, retrieve the NodeId of
 /// the actual type definition, otherwise, return None
 pub fn get_tuple_struct_definition_if_ctor(cdata: Cmd,
-                                           node_id: ast::NodeId) -> Option<ast::NodeId> {
+                                           node_id: ast::NodeId)
+    -> Option<ast::DefId>
+{
     let item = lookup_item(node_id, cdata.data());
     let mut ret = None;
     reader::tagged_docs(item, tag_items_data_item_is_tuple_struct_ctor, |_| {
         ret = Some(item_reqd_and_translated_parent_item(cdata.cnum, item));
         false
     });
-    ret.map(|x| x.node)
+    ret
 }
 
 pub fn get_item_attrs(cdata: Cmd,
-                      node_id: ast::NodeId,
+                      orig_node_id: ast::NodeId,
                       f: |Vec<@ast::MetaItem> |) {
     // The attributes for a tuple struct are attached to the definition, not the ctor;
     // we assume that someone passing in a tuple struct ctor is actually wanting to
     // look at the definition
-    let node_id = get_tuple_struct_definition_if_ctor(cdata, node_id).unwrap_or(node_id);
+    let node_id = get_tuple_struct_definition_if_ctor(cdata, orig_node_id);
+    let node_id = node_id.map(|x| x.node).unwrap_or(orig_node_id);
     let item = lookup_item(node_id, cdata.data());
     reader::tagged_docs(item, tag_attributes, |attributes| {
         reader::tagged_docs(attributes, tag_attribute, |attribute| {
diff --git a/src/librustc/middle/graph.rs b/src/librustc/middle/graph.rs
index e4603b7eae2..2705f9bf9bf 100644
--- a/src/librustc/middle/graph.rs
+++ b/src/librustc/middle/graph.rs
@@ -56,11 +56,11 @@ pub struct Edge<E> {
 }
 
 #[deriving(Eq)]
-pub struct NodeIndex(uint);
+pub struct NodeIndex(pub uint);
 pub static InvalidNodeIndex: NodeIndex = NodeIndex(uint::MAX);
 
 #[deriving(Eq)]
-pub struct EdgeIndex(uint);
+pub struct EdgeIndex(pub uint);
 pub static InvalidEdgeIndex: EdgeIndex = EdgeIndex(uint::MAX);
 
 // Use a private field here to guarantee no more instances are created:
diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs
index e5644dbd246..9d9faee3645 100644
--- a/src/librustc/middle/privacy.rs
+++ b/src/librustc/middle/privacy.rs
@@ -14,6 +14,7 @@
 
 use std::mem::replace;
 
+use metadata::csearch;
 use middle::lint;
 use middle::resolve;
 use middle::ty;
@@ -358,6 +359,12 @@ enum PrivacyResult {
     DisallowedBy(ast::NodeId),
 }
 
+enum FieldName {
+    UnnamedField(uint), // index
+    // FIXME #6993: change type (and name) from Ident to Name
+    NamedField(ast::Ident),
+}
+
 impl<'a> PrivacyVisitor<'a> {
     // used when debugging
     fn nodestr(&self, id: ast::NodeId) -> ~str {
@@ -560,18 +567,23 @@ impl<'a> PrivacyVisitor<'a> {
     }
 
     // Checks that a field is in scope.
-    // FIXME #6993: change type (and name) from Ident to Name
-    fn check_field(&mut self, span: Span, id: ast::DefId, ident: ast::Ident) {
-        for field in ty::lookup_struct_fields(self.tcx, id).iter() {
-            if field.name != ident.name { continue; }
-            if field.vis == ast::Public { break }
-            if !is_local(field.id) ||
-               !self.private_accessible(field.id.node) {
-                self.tcx.sess.span_err(span,
-                                       format!("field `{}` is private",
-                                               token::get_ident(ident)))
+    fn check_field(&mut self, span: Span, id: ast::DefId,
+                   name: FieldName) {
+        let fields = ty::lookup_struct_fields(self.tcx, id);
+        let field = match name {
+            NamedField(ident) => {
+                fields.iter().find(|f| f.name == ident.name).unwrap()
             }
-            break;
+            UnnamedField(idx) => fields.get(idx)
+        };
+        if field.vis == ast::Public { return }
+        if !is_local(field.id) || !self.private_accessible(field.id.node) {
+            let msg = match name {
+                NamedField(name) => format!("field `{}` is private",
+                                            token::get_ident(name)),
+                UnnamedField(idx) => format!("field \\#{} is private", idx + 1),
+            };
+            self.tcx.sess.span_err(span, msg);
         }
     }
 
@@ -634,10 +646,11 @@ impl<'a> PrivacyVisitor<'a> {
                             _ => {},
                         }
                     }
-                    // If an import is not used in either namespace, we still want to check
-                    // that it could be legal. Therefore we check in both namespaces and only
-                    // report an error if both would be illegal. We only report one error,
-                    // even if it is illegal to import from both namespaces.
+                    // If an import is not used in either namespace, we still
+                    // want to check that it could be legal. Therefore we check
+                    // in both namespaces and only report an error if both would
+                    // be illegal. We only report one error, even if it is
+                    // illegal to import from both namespaces.
                     match (value_priv, check_value, type_priv, check_type) {
                         (Some(p), resolve::Unused, None, _) |
                         (None, _, Some(p), resolve::Unused) => {
@@ -701,7 +714,8 @@ impl<'a> PrivacyVisitor<'a> {
             // is whether the trait itself is accessible or not.
             MethodParam(MethodParam { trait_id: trait_id, .. }) |
             MethodObject(MethodObject { trait_id: trait_id, .. }) => {
-                self.report_error(self.ensure_public(span, trait_id, None, "source trait"));
+                self.report_error(self.ensure_public(span, trait_id, None,
+                                                     "source trait"));
             }
         }
     }
@@ -726,7 +740,7 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
                 match ty::get(ty::expr_ty_adjusted(self.tcx, base,
                                                    &*self.method_map.borrow())).sty {
                     ty::ty_struct(id, _) => {
-                        self.check_field(expr.span, id, ident);
+                        self.check_field(expr.span, id, NamedField(ident));
                     }
                     _ => {}
                 }
@@ -749,7 +763,8 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
                 match ty::get(ty::expr_ty(self.tcx, expr)).sty {
                     ty::ty_struct(id, _) => {
                         for field in (*fields).iter() {
-                            self.check_field(expr.span, id, field.ident.node);
+                            self.check_field(expr.span, id,
+                                             NamedField(field.ident.node));
                         }
                     }
                     ty::ty_enum(_, _) => {
@@ -757,7 +772,7 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
                             ast::DefVariant(_, variant_id, _) => {
                                 for field in fields.iter() {
                                     self.check_field(expr.span, variant_id,
-                                                     field.ident.node);
+                                                     NamedField(field.ident.node));
                                 }
                             }
                             _ => self.tcx.sess.span_bug(expr.span,
@@ -772,6 +787,46 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
                                                             struct type?!"),
                 }
             }
+            ast::ExprPath(..) => {
+                let guard = |did: ast::DefId| {
+                    let fields = ty::lookup_struct_fields(self.tcx, did);
+                    let any_priv = fields.iter().any(|f| {
+                        f.vis != ast::Public && (
+                            !is_local(f.id) ||
+                            !self.private_accessible(f.id.node))
+                    });
+                    if any_priv {
+                        self.tcx.sess.span_err(expr.span,
+                            "cannot invoke tuple struct constructor \
+                             with private fields");
+                    }
+                };
+                match self.tcx.def_map.borrow().find(&expr.id) {
+                    Some(&ast::DefStruct(did)) => {
+                        guard(if is_local(did) {
+                            local_def(self.tcx.map.get_parent(did.node))
+                        } else {
+                            // "tuple structs" with zero fields (such as
+                            // `pub struct Foo;`) don't have a ctor_id, hence
+                            // the unwrap_or to the same struct id.
+                            let maybe_did =
+                                csearch::get_tuple_struct_definition_if_ctor(
+                                    &self.tcx.sess.cstore, did);
+                            maybe_did.unwrap_or(did)
+                        })
+                    }
+                    // Tuple struct constructors across crates are identified as
+                    // DefFn types, so we explicitly handle that case here.
+                    Some(&ast::DefFn(did, _)) if !is_local(did) => {
+                        match csearch::get_tuple_struct_definition_if_ctor(
+                                    &self.tcx.sess.cstore, did) {
+                            Some(did) => guard(did),
+                            None => {}
+                        }
+                    }
+                    _ => {}
+                }
+            }
             _ => {}
         }
 
@@ -821,7 +876,8 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
                 match ty::get(ty::pat_ty(self.tcx, pattern)).sty {
                     ty::ty_struct(id, _) => {
                         for field in fields.iter() {
-                            self.check_field(pattern.span, id, field.ident);
+                            self.check_field(pattern.span, id,
+                                             NamedField(field.ident));
                         }
                     }
                     ty::ty_enum(_, _) => {
@@ -829,7 +885,7 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
                             Some(&ast::DefVariant(_, variant_id, _)) => {
                                 for field in fields.iter() {
                                     self.check_field(pattern.span, variant_id,
-                                                     field.ident);
+                                                     NamedField(field.ident));
                                 }
                             }
                             _ => self.tcx.sess.span_bug(pattern.span,
@@ -844,6 +900,27 @@ impl<'a> Visitor<()> for PrivacyVisitor<'a> {
                                                  struct type?!"),
                 }
             }
+
+            // Patterns which bind no fields are allowable (the path is check
+            // elsewhere).
+            ast::PatEnum(_, Some(ref fields)) => {
+                match ty::get(ty::pat_ty(self.tcx, pattern)).sty {
+                    ty::ty_struct(id, _) => {
+                        for (i, field) in fields.iter().enumerate() {
+                            match field.node {
+                                ast::PatWild(..) => continue,
+                                _ => {}
+                            }
+                            self.check_field(field.span, id, UnnamedField(i));
+                        }
+                    }
+                    ty::ty_enum(..) => {
+                        // enum fields have no privacy at this time
+                    }
+                    _ => {}
+                }
+
+            }
             _ => {}
         }
 
diff --git a/src/librustc/middle/trans/basic_block.rs b/src/librustc/middle/trans/basic_block.rs
index 074c9f4fec5..303ad5fbce2 100644
--- a/src/librustc/middle/trans/basic_block.rs
+++ b/src/librustc/middle/trans/basic_block.rs
@@ -12,7 +12,7 @@ use lib::llvm::{llvm, BasicBlockRef};
 use middle::trans::value::{Users, Value};
 use std::iter::{Filter, Map};
 
-pub struct BasicBlock(BasicBlockRef);
+pub struct BasicBlock(pub BasicBlockRef);
 
 pub type Preds<'a> = Map<'a, Value, BasicBlock, Filter<'a, Value, Users>>;
 
diff --git a/src/librustc/middle/trans/value.rs b/src/librustc/middle/trans/value.rs
index f66a393a50f..1efb47ad42f 100644
--- a/src/librustc/middle/trans/value.rs
+++ b/src/librustc/middle/trans/value.rs
@@ -13,7 +13,7 @@ use middle::trans::basic_block::BasicBlock;
 use middle::trans::common::Block;
 use std::libc::c_uint;
 
-pub struct Value(ValueRef);
+pub struct Value(pub ValueRef);
 
 macro_rules! opt_val ( ($e:expr) => (
     unsafe {
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index 85d47424e2b..4aefa3b9edc 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -866,13 +866,13 @@ impl CLike for BuiltinBound {
 }
 
 #[deriving(Clone, Eq, TotalEq, Hash)]
-pub struct TyVid(uint);
+pub struct TyVid(pub uint);
 
 #[deriving(Clone, Eq, TotalEq, Hash)]
-pub struct IntVid(uint);
+pub struct IntVid(pub uint);
 
 #[deriving(Clone, Eq, TotalEq, Hash)]
-pub struct FloatVid(uint);
+pub struct FloatVid(pub uint);
 
 #[deriving(Clone, Eq, TotalEq, Encodable, Decodable, Hash)]
 pub struct RegionVid {
diff --git a/src/librustc/middle/typeck/infer/coercion.rs b/src/librustc/middle/typeck/infer/coercion.rs
index dac018fb848..8a1662ca701 100644
--- a/src/librustc/middle/typeck/infer/coercion.rs
+++ b/src/librustc/middle/typeck/infer/coercion.rs
@@ -84,7 +84,7 @@ use syntax::ast;
 // Note: Coerce is not actually a combiner, in that it does not
 // conform to the same interface, though it performs a similar
 // function.
-pub struct Coerce<'f>(CombineFields<'f>);
+pub struct Coerce<'f>(pub CombineFields<'f>);
 
 impl<'f> Coerce<'f> {
     pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> {
diff --git a/src/librustc/middle/typeck/infer/glb.rs b/src/librustc/middle/typeck/infer/glb.rs
index e846e3621bd..83fc315bceb 100644
--- a/src/librustc/middle/typeck/infer/glb.rs
+++ b/src/librustc/middle/typeck/infer/glb.rs
@@ -28,7 +28,7 @@ use collections::HashMap;
 use util::common::{indenter};
 use util::ppaux::mt_to_str;
 
-pub struct Glb<'f>(CombineFields<'f>);  // "greatest lower bound" (common subtype)
+pub struct Glb<'f>(pub CombineFields<'f>);  // "greatest lower bound" (common subtype)
 
 impl<'f> Glb<'f> {
     pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> { let Glb(ref v) = *self; v }
diff --git a/src/librustc/middle/typeck/infer/lub.rs b/src/librustc/middle/typeck/infer/lub.rs
index bde750eb6f0..7f48e233367 100644
--- a/src/librustc/middle/typeck/infer/lub.rs
+++ b/src/librustc/middle/typeck/infer/lub.rs
@@ -27,7 +27,7 @@ use syntax::ast::{ExternFn, ImpureFn, UnsafeFn};
 use syntax::ast::{Onceness, Purity};
 use util::ppaux::mt_to_str;
 
-pub struct Lub<'f>(CombineFields<'f>);  // least-upper-bound: common supertype
+pub struct Lub<'f>(pub CombineFields<'f>);  // least-upper-bound: common supertype
 
 impl<'f> Lub<'f> {
     pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> { let Lub(ref v) = *self; v }
diff --git a/src/librustc/middle/typeck/infer/sub.rs b/src/librustc/middle/typeck/infer/sub.rs
index ef17a593654..b22e6f4677b 100644
--- a/src/librustc/middle/typeck/infer/sub.rs
+++ b/src/librustc/middle/typeck/infer/sub.rs
@@ -27,7 +27,7 @@ use util::ppaux::bound_region_to_str;
 
 use syntax::ast::{Onceness, Purity};
 
-pub struct Sub<'f>(CombineFields<'f>);  // "subtype", "subregion" etc
+pub struct Sub<'f>(pub CombineFields<'f>);  // "subtype", "subregion" etc
 
 impl<'f> Sub<'f> {
     pub fn get_ref<'a>(&'a self) -> &'a CombineFields<'f> { let Sub(ref v) = *self; v }
diff --git a/src/librustdoc/html/escape.rs b/src/librustdoc/html/escape.rs
index bb6b1eeaedd..60fcbe33a1b 100644
--- a/src/librustdoc/html/escape.rs
+++ b/src/librustdoc/html/escape.rs
@@ -17,7 +17,7 @@ use std::fmt;
 
 /// Wrapper struct which will emit the HTML-escaped version of the contained
 /// string when passed to a format string.
-pub struct Escape<'a>(&'a str);
+pub struct Escape<'a>(pub &'a str);
 
 impl<'a> fmt::Show for Escape<'a> {
     fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index acf6446a191..10c155262c3 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -28,12 +28,12 @@ use html::render::{cache_key, current_location_key};
 
 /// Helper to render an optional visibility with a space after it (if the
 /// visibility is preset)
-pub struct VisSpace(Option<ast::Visibility>);
+pub struct VisSpace(pub Option<ast::Visibility>);
 /// Similarly to VisSpace, this structure is used to render a purity with a
 /// space after it.
-pub struct PuritySpace(ast::Purity);
+pub struct PuritySpace(pub ast::Purity);
 /// Wrapper struct for properly emitting a method declaration.
-pub struct Method<'a>(&'a clean::SelfTy, &'a clean::FnDecl);
+pub struct Method<'a>(pub &'a clean::SelfTy, pub &'a clean::FnDecl);
 
 impl VisSpace {
     pub fn get(&self) -> Option<ast::Visibility> {
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index c52a6267657..ff2462cfb22 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -42,10 +42,10 @@ use html::highlight;
 /// A unit struct which has the `fmt::Show` trait implemented. When
 /// formatted, this struct will emit the HTML corresponding to the rendered
 /// version of the contained markdown string.
-pub struct Markdown<'a>(&'a str);
+pub struct Markdown<'a>(pub &'a str);
 /// A unit struct like `Markdown`, that renders the markdown with a
 /// table of contents.
-pub struct MarkdownWithToc<'a>(&'a str);
+pub struct MarkdownWithToc<'a>(pub &'a str);
 
 static OUTPUT_UNIT: libc::size_t = 64;
 static MKDEXT_NO_INTRA_EMPHASIS: libc::c_uint = 1 << 0;
diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs
index 0f90135512c..fc266df11e4 100644
--- a/src/libstd/rt/task.rs
+++ b/src/libstd/rt/task.rs
@@ -58,7 +58,7 @@ pub struct Task {
 }
 
 pub struct GarbageCollector;
-pub struct LocalStorage(Option<local_data::Map>);
+pub struct LocalStorage(pub Option<local_data::Map>);
 
 /// A handle to a blocked task. Usually this means having the ~Task pointer by
 /// ownership, but if the task is killable, a killer can steal it at any time.
diff --git a/src/libstd/unstable/simd.rs b/src/libstd/unstable/simd.rs
index 01200833b19..a7a314d35e7 100644
--- a/src/libstd/unstable/simd.rs
+++ b/src/libstd/unstable/simd.rs
@@ -14,40 +14,48 @@
 
 #[experimental]
 #[simd]
-pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8);
+pub struct i8x16(pub i8, pub i8, pub i8, pub i8,
+                 pub i8, pub i8, pub i8, pub i8,
+                 pub i8, pub i8, pub i8, pub i8,
+                 pub i8, pub i8, pub i8, pub i8);
 
 #[experimental]
 #[simd]
-pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
+pub struct i16x8(pub i16, pub i16, pub i16, pub i16,
+                 pub i16, pub i16, pub i16, pub i16);
 
 #[experimental]
 #[simd]
-pub struct i32x4(i32, i32, i32, i32);
+pub struct i32x4(pub i32, pub i32, pub i32, pub i32);
 
 #[experimental]
 #[simd]
-pub struct i64x2(i64, i64);
+pub struct i64x2(pub i64, pub i64);
 
 #[experimental]
 #[simd]
-pub struct u8x16(u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8, u8);
+pub struct u8x16(pub u8, pub u8, pub u8, pub u8,
+                 pub u8, pub u8, pub u8, pub u8,
+                 pub u8, pub u8, pub u8, pub u8,
+                 pub u8, pub u8, pub u8, pub u8);
 
 #[experimental]
 #[simd]
-pub struct u16x8(u16, u16, u16, u16, u16, u16, u16, u16);
+pub struct u16x8(pub u16, pub u16, pub u16, pub u16,
+                 pub u16, pub u16, pub u16, pub u16);
 
 #[experimental]
 #[simd]
-pub struct u32x4(u32, u32, u32, u32);
+pub struct u32x4(pub u32, pub u32, pub u32, pub u32);
 
 #[experimental]
 #[simd]
-pub struct u64x2(u64, u64);
+pub struct u64x2(pub u64, pub u64);
 
 #[experimental]
 #[simd]
-pub struct f32x4(f32, f32, f32, f32);
+pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
 
 #[experimental]
 #[simd]
-pub struct f64x2(f64, f64);
+pub struct f64x2(pub f64, pub f64);
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index 4612f8e6673..53d2ac97b49 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -493,10 +493,10 @@ pub enum Expr_ {
     ExprVstore(@Expr, ExprVstore),
     // First expr is the place; second expr is the value.
     ExprBox(@Expr, @Expr),
-    ExprVec(Vec<@Expr> , Mutability),
-    ExprCall(@Expr, Vec<@Expr> ),
-    ExprMethodCall(Ident, Vec<P<Ty>> , Vec<@Expr> ),
-    ExprTup(Vec<@Expr> ),
+    ExprVec(Vec<@Expr>, Mutability),
+    ExprCall(@Expr, Vec<@Expr>),
+    ExprMethodCall(Ident, Vec<P<Ty>>, Vec<@Expr>),
+    ExprTup(Vec<@Expr>),
     ExprBinary(BinOp, @Expr, @Expr),
     ExprUnary(UnOp, @Expr),
     ExprLit(@Lit),
@@ -508,14 +508,14 @@ pub enum Expr_ {
     // Conditionless loop (can be exited with break, cont, or ret)
     // FIXME #6993: change to Option<Name>
     ExprLoop(P<Block>, Option<Ident>),
-    ExprMatch(@Expr, Vec<Arm> ),
+    ExprMatch(@Expr, Vec<Arm>),
     ExprFnBlock(P<FnDecl>, P<Block>),
     ExprProc(P<FnDecl>, P<Block>),
     ExprBlock(P<Block>),
 
     ExprAssign(@Expr, @Expr),
     ExprAssignOp(BinOp, @Expr, @Expr),
-    ExprField(@Expr, Ident, Vec<P<Ty>> ),
+    ExprField(@Expr, Ident, Vec<P<Ty>>),
     ExprIndex(@Expr, @Expr),
 
     /// Expression that looks like a "name". For example,
diff --git a/src/libsyntax/ast_map.rs b/src/libsyntax/ast_map.rs
index e098dcd99fd..cf584ff62ac 100644
--- a/src/libsyntax/ast_map.rs
+++ b/src/libsyntax/ast_map.rs
@@ -66,7 +66,7 @@ impl<'a> Iterator<PathElem> for LinkedPath<'a> {
 
 // HACK(eddyb) move this into libstd (value wrapper for slice::Items).
 #[deriving(Clone)]
-pub struct Values<'a, T>(slice::Items<'a, T>);
+pub struct Values<'a, T>(pub slice::Items<'a, T>);
 
 impl<'a, T: Copy> Iterator<T> for Values<'a, T> {
     fn next(&mut self) -> Option<T> {
diff --git a/src/libsyntax/codemap.rs b/src/libsyntax/codemap.rs
index 0d2492d7fad..7cadce54765 100644
--- a/src/libsyntax/codemap.rs
+++ b/src/libsyntax/codemap.rs
@@ -33,13 +33,13 @@ pub trait Pos {
 /// A byte offset. Keep this small (currently 32-bits), as AST contains
 /// a lot of them.
 #[deriving(Clone, Eq, TotalEq, Hash, Ord, Show)]
-pub struct BytePos(u32);
+pub struct BytePos(pub u32);
 
 /// A character offset. Because of multibyte utf8 characters, a byte offset
 /// is not equivalent to a character offset. The CodeMap will convert BytePos
 /// values to CharPos values as necessary.
 #[deriving(Eq, Hash, Ord, Show)]
-pub struct CharPos(uint);
+pub struct CharPos(pub uint);
 
 // FIXME: Lots of boilerplate in these impls, but so far my attempts to fix
 // have been unsuccessful
diff --git a/src/test/auxiliary/issue-11508.rs b/src/test/auxiliary/issue-11508.rs
index dfdde5e5e4e..c5dc3439f2f 100644
--- a/src/test/auxiliary/issue-11508.rs
+++ b/src/test/auxiliary/issue-11508.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub struct Closed01<F>(F);
+pub struct Closed01<F>(pub F);
 
 pub trait Bar { fn new() -> Self; }
 
diff --git a/src/test/auxiliary/issue-11529.rs b/src/test/auxiliary/issue-11529.rs
index 9d500532401..a8a4c438e67 100644
--- a/src/test/auxiliary/issue-11529.rs
+++ b/src/test/auxiliary/issue-11529.rs
@@ -8,4 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub struct A<'a>(&'a int);
+pub struct A<'a>(pub &'a int);
diff --git a/src/test/auxiliary/issue-7899.rs b/src/test/auxiliary/issue-7899.rs
index f1a0fcffd16..e197e84442b 100644
--- a/src/test/auxiliary/issue-7899.rs
+++ b/src/test/auxiliary/issue-7899.rs
@@ -8,4 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub struct V2<T>(T, T);
+pub struct V2<T>(pub T, pub T);
diff --git a/src/test/auxiliary/issue_10031_aux.rs b/src/test/auxiliary/issue_10031_aux.rs
index 5724d876ef4..f0f1af2e3a3 100644
--- a/src/test/auxiliary/issue_10031_aux.rs
+++ b/src/test/auxiliary/issue_10031_aux.rs
@@ -8,4 +8,4 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub struct Wrap<A>(A);
+pub struct Wrap<A>(pub A);
diff --git a/src/test/auxiliary/issue_2472_b.rs b/src/test/auxiliary/issue_2472_b.rs
index 1475b1a75a6..5f55476427f 100644
--- a/src/test/auxiliary/issue_2472_b.rs
+++ b/src/test/auxiliary/issue_2472_b.rs
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 
-pub struct S(());
+pub struct S(pub ());
 
 impl S {
     pub fn foo(&self) { }
diff --git a/src/test/auxiliary/lint_stability.rs b/src/test/auxiliary/lint_stability.rs
index 30224912d92..5afbf4492b3 100644
--- a/src/test/auxiliary/lint_stability.rs
+++ b/src/test/auxiliary/lint_stability.rs
@@ -161,15 +161,15 @@ pub enum Enum {
 }
 
 #[deprecated]
-pub struct DeprecatedTupleStruct(int);
+pub struct DeprecatedTupleStruct(pub int);
 #[experimental]
-pub struct ExperimentalTupleStruct(int);
+pub struct ExperimentalTupleStruct(pub int);
 #[unstable]
-pub struct UnstableTupleStruct(int);
-pub struct UnmarkedTupleStruct(int);
+pub struct UnstableTupleStruct(pub int);
+pub struct UnmarkedTupleStruct(pub int);
 #[stable]
-pub struct StableTupleStruct(int);
+pub struct StableTupleStruct(pub int);
 #[frozen]
-pub struct FrozenTupleStruct(int);
+pub struct FrozenTupleStruct(pub int);
 #[locked]
-pub struct LockedTupleStruct(int);
+pub struct LockedTupleStruct(pub int);
diff --git a/src/test/auxiliary/newtype_struct_xc.rs b/src/test/auxiliary/newtype_struct_xc.rs
index 3833b549b5f..60c64842c71 100644
--- a/src/test/auxiliary/newtype_struct_xc.rs
+++ b/src/test/auxiliary/newtype_struct_xc.rs
@@ -10,4 +10,4 @@
 
 #[crate_type="lib"];
 
-pub struct Au(int);
+pub struct Au(pub int);
diff --git a/src/test/auxiliary/privacy-tuple-struct.rs b/src/test/auxiliary/privacy-tuple-struct.rs
new file mode 100644
index 00000000000..2fb9d9923cb
--- /dev/null
+++ b/src/test/auxiliary/privacy-tuple-struct.rs
@@ -0,0 +1,14 @@
+// Copyright 2014 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 struct A(());
+pub struct B(int);
+pub struct C(pub int, int);
+pub struct D(pub int);
diff --git a/src/test/compile-fail/privacy5.rs b/src/test/compile-fail/privacy5.rs
new file mode 100644
index 00000000000..c057236265e
--- /dev/null
+++ b/src/test/compile-fail/privacy5.rs
@@ -0,0 +1,137 @@
+// Copyright 2014 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:privacy-tuple-struct.rs
+// ignore-fast
+
+extern crate other = "privacy-tuple-struct";
+
+mod a {
+    pub struct A(());
+    pub struct B(int);
+    pub struct C(pub int, int);
+    pub struct D(pub int);
+
+    fn test() {
+        let a = A(());
+        let b = B(2);
+        let c = C(2, 3);
+        let d = D(4);
+
+        let A(()) = a;
+        let A(_) = a;
+        match a { A(()) => {} }
+        match a { A(_) => {} }
+
+        let B(_) = b;
+        let B(_b) = b;
+        match b { B(_) => {} }
+        match b { B(_b) => {} }
+        match b { B(1) => {} B(_) => {} }
+
+        let C(_, _) = c;
+        let C(_a, _) = c;
+        let C(_, _b) = c;
+        let C(_a, _b) = c;
+        match c { C(_, _) => {} }
+        match c { C(_a, _) => {} }
+        match c { C(_, _b) => {} }
+        match c { C(_a, _b) => {} }
+
+        let D(_) = d;
+        let D(_d) = d;
+        match d { D(_) => {} }
+        match d { D(_d) => {} }
+        match d { D(1) => {} D(_) => {} }
+
+        let a2 = A;
+        let b2 = B;
+        let c2 = C;
+        let d2 = D;
+    }
+}
+
+fn this_crate() {
+    let a = a::A(()); //~ ERROR: cannot invoke tuple struct constructor
+    let b = a::B(2); //~ ERROR: cannot invoke tuple struct constructor
+    let c = a::C(2, 3); //~ ERROR: cannot invoke tuple struct constructor
+    let d = a::D(4);
+
+    let a::A(()) = a; //~ ERROR: field #1 is private
+    let a::A(_) = a;
+    match a { a::A(()) => {} } //~ ERROR: field #1 is private
+    match a { a::A(_) => {} }
+
+    let a::B(_) = b;
+    let a::B(_b) = b; //~ ERROR: field #1 is private
+    match b { a::B(_) => {} }
+    match b { a::B(_b) => {} } //~ ERROR: field #1 is private
+    match b { a::B(1) => {} a::B(_) => {} } //~ ERROR: field #1 is private
+
+    let a::C(_, _) = c;
+    let a::C(_a, _) = c;
+    let a::C(_, _b) = c; //~ ERROR: field #2 is private
+    let a::C(_a, _b) = c; //~ ERROR: field #2 is private
+    match c { a::C(_, _) => {} }
+    match c { a::C(_a, _) => {} }
+    match c { a::C(_, _b) => {} } //~ ERROR: field #2 is private
+    match c { a::C(_a, _b) => {} } //~ ERROR: field #2 is private
+
+    let a::D(_) = d;
+    let a::D(_d) = d;
+    match d { a::D(_) => {} }
+    match d { a::D(_d) => {} }
+    match d { a::D(1) => {} a::D(_) => {} }
+
+    let a2 = a::A; //~ ERROR: cannot invoke tuple struct constructor
+    let b2 = a::B; //~ ERROR: cannot invoke tuple struct constructor
+    let c2 = a::C; //~ ERROR: cannot invoke tuple struct constructor
+    let d2 = a::D;
+}
+
+fn xcrate() {
+    let a = other::A(()); //~ ERROR: cannot invoke tuple struct constructor
+    let b = other::B(2); //~ ERROR: cannot invoke tuple struct constructor
+    let c = other::C(2, 3); //~ ERROR: cannot invoke tuple struct constructor
+    let d = other::D(4);
+
+    let other::A(()) = a; //~ ERROR: field #1 is private
+    let other::A(_) = a;
+    match a { other::A(()) => {} } //~ ERROR: field #1 is private
+    match a { other::A(_) => {} }
+
+    let other::B(_) = b;
+    let other::B(_b) = b; //~ ERROR: field #1 is private
+    match b { other::B(_) => {} }
+    match b { other::B(_b) => {} } //~ ERROR: field #1 is private
+    match b { other::B(1) => {} other::B(_) => {} } //~ ERROR: field #1 is private
+
+    let other::C(_, _) = c;
+    let other::C(_a, _) = c;
+    let other::C(_, _b) = c; //~ ERROR: field #2 is private
+    let other::C(_a, _b) = c; //~ ERROR: field #2 is private
+    match c { other::C(_, _) => {} }
+    match c { other::C(_a, _) => {} }
+    match c { other::C(_, _b) => {} } //~ ERROR: field #2 is private
+    match c { other::C(_a, _b) => {} } //~ ERROR: field #2 is private
+
+    let other::D(_) = d;
+    let other::D(_d) = d;
+    match d { other::D(_) => {} }
+    match d { other::D(_d) => {} }
+    match d { other::D(1) => {} other::D(_) => {} }
+
+    let a2 = other::A; //~ ERROR: cannot invoke tuple struct constructor
+    let b2 = other::B; //~ ERROR: cannot invoke tuple struct constructor
+    let c2 = other::C; //~ ERROR: cannot invoke tuple struct constructor
+    let d2 = other::D;
+}
+
+fn main() {}