]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #38932 - petrochenkov:privctor, r=jseyfried
authorbors <bors@rust-lang.org>
Thu, 2 Feb 2017 05:10:40 +0000 (05:10 +0000)
committerbors <bors@rust-lang.org>
Thu, 2 Feb 2017 05:10:40 +0000 (05:10 +0000)
Privatize constructors of tuple structs with private fields

This PR implements the strictest version of such "privatization" - it just sets visibilities for struct constructors, this affects everything including imports.
```
visibility(struct_ctor) = min(visibility(struct), visibility(field_1), ..., visibility(field_N))
```
Needs crater run before proceeding.

Resolves https://github.com/rust-lang/rfcs/issues/902

r? @nikomatsakis

18 files changed:
src/librustc/lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_metadata/encoder.rs
src/librustc_privacy/diagnostics.rs
src/librustc_privacy/lib.rs
src/librustc_resolve/build_reduced_graph.rs
src/librustc_resolve/lib.rs
src/librustdoc/html/markdown.rs
src/libsyntax/symbol.rs
src/test/compile-fail-fulldeps/explore-issue-38412.rs
src/test/compile-fail/E0450.rs [deleted file]
src/test/compile-fail/E0451.rs
src/test/compile-fail/issue-38412.rs
src/test/compile-fail/privacy/legacy-ctor-visibility.rs [new file with mode: 0644]
src/test/compile-fail/privacy5.rs
src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs [new file with mode: 0644]
src/test/ui/resolve/privacy-struct-ctor.rs [new file with mode: 0644]
src/test/ui/resolve/privacy-struct-ctor.stderr [new file with mode: 0644]

index b0db3b75029fb16148bbfddaec9bf1fd08136d0f..e1605959922c0530e64e1a2b1ab299282afc6639 100644 (file)
     "detects names that resolve to ambiguous glob imports with RFC 1560"
 }
 
+declare_lint! {
+    pub LEGACY_CONSTRUCTOR_VISIBILITY,
+    Deny,
+    "detects use of struct constructors that would be invisible with new visibility rules"
+}
+
 declare_lint! {
     pub DEPRECATED,
     Warn,
@@ -271,6 +277,7 @@ fn get_lints(&self) -> LintArray {
             EXTRA_REQUIREMENT_IN_IMPL,
             LEGACY_DIRECTORY_OWNERSHIP,
             LEGACY_IMPORTS,
+            LEGACY_CONSTRUCTOR_VISIBILITY,
             DEPRECATED
         )
     }
index 34bc57884ecbbb5b9a19a457fc195cd3bf821eca..18067cb86739b51cd0787c63973d8455cc183d92 100644 (file)
@@ -240,6 +240,10 @@ macro_rules! add_lint_group {
             id: LintId::of(LEGACY_IMPORTS),
             reference: "issue #38260 <https://github.com/rust-lang/rust/issues/38260>",
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY),
+            reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
+        },
         ]);
 
     // Register renamed and removed lints
index 028555d1df848c9e2346f8532674a806d1f3f716..b9c2f0622b6988e70ff1fc5bd0c121948bd3352d 100644 (file)
@@ -396,10 +396,16 @@ fn encode_struct_ctor(&mut self, (adt_def_id, def_id): (DefId, DefId)) -> Entry<
 
         let struct_id = tcx.hir.as_local_node_id(adt_def_id).unwrap();
         let struct_vis = &tcx.hir.expect_item(struct_id).vis;
+        let mut ctor_vis = ty::Visibility::from_hir(struct_vis, struct_id, tcx);
+        for field in &variant.fields {
+            if ctor_vis.is_at_least(field.vis, tcx) {
+                ctor_vis = field.vis;
+            }
+        }
 
         Entry {
             kind: EntryKind::Struct(self.lazy(&data)),
-            visibility: self.lazy(&ty::Visibility::from_hir(struct_vis, struct_id, tcx)),
+            visibility: self.lazy(&ctor_vis),
             span: self.lazy(&tcx.def_span(def_id)),
             attributes: LazySeq::empty(),
             children: LazySeq::empty(),
index 66afe5835bf6fc6f3549dfc788e7feaab720f948..49f2ccb7c57f59865c723449bcc968c7b2e9e61c 100644 (file)
@@ -115,45 +115,6 @@ pub enum Foo {
 ```
 "##,
 
-E0450: r##"
-A tuple constructor was invoked while some of its fields are private. Erroneous
-code example:
-
-```compile_fail,E0450
-mod Bar {
-    pub struct Foo(isize);
-}
-
-let f = Bar::Foo(0); // error: cannot invoke tuple struct constructor with
-                     //        private fields
-```
-
-To solve this issue, please ensure that all of the fields of the tuple struct
-are public. Alternatively, provide a `new()` method to the tuple struct to
-construct it from a given inner value. Example:
-
-```
-mod Bar {
-    pub struct Foo(pub isize); // we set its field to public
-}
-
-let f = Bar::Foo(0); // ok!
-
-// or:
-mod bar {
-    pub struct Foo(isize);
-
-    impl Foo {
-        pub fn new(x: isize) -> Foo {
-            Foo(x)
-        }
-    }
-}
-
-let f = bar::Foo::new(1);
-```
-"##,
-
 E0451: r##"
 A struct constructor with private fields was invoked. Erroneous code example:
 
@@ -204,3 +165,7 @@ pub fn new() -> Foo { // we create a method to instantiate `Foo`
 "##,
 
 }
+
+register_diagnostics! {
+//  E0450, moved into resolve
+}
index 7357d6f38b651a0d3a5d25a71ba873452db3bcba..9dc94745cff7b72fc64b4c8f142605e058502e40 100644 (file)
@@ -27,7 +27,7 @@
 
 use rustc::dep_graph::DepNode;
 use rustc::hir::{self, PatKind};
-use rustc::hir::def::{self, Def, CtorKind};
+use rustc::hir::def::{self, Def};
 use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::itemlikevisit::DeepVisitor;
@@ -478,33 +478,6 @@ fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
                     }
                 }
             }
-            hir::ExprPath(hir::QPath::Resolved(_, ref path)) => {
-                if let Def::StructCtor(_, CtorKind::Fn) = path.def {
-                    let adt_def = self.tcx.expect_variant_def(path.def);
-                    let private_indexes = adt_def.fields.iter().enumerate().filter(|&(_, field)| {
-                        !field.vis.is_accessible_from(self.curitem, self.tcx)
-                    }).map(|(i, _)| i).collect::<Vec<_>>();
-
-                    if !private_indexes.is_empty() {
-                        let mut error = struct_span_err!(self.tcx.sess, expr.span, E0450,
-                                                         "cannot invoke tuple struct constructor \
-                                                          with private fields");
-                        error.span_label(expr.span,
-                                         &format!("cannot construct with a private field"));
-
-                        if let Some(node_id) = self.tcx.hir.as_local_node_id(adt_def.did) {
-                            let node = self.tcx.hir.find(node_id);
-                            if let Some(hir::map::NodeStructCtor(vdata)) = node {
-                                for i in private_indexes {
-                                    error.span_label(vdata.fields()[i].span,
-                                                     &format!("private field declared here"));
-                                }
-                            }
-                        }
-                        error.emit();
-                    }
-                }
-            }
             _ => {}
         }
 
index f74af416cde09c5a62a40e3f8f1a995fa2fd4bb1..eb6c7f4bed5deaddb2cdeec5528afc97a4f3d2b0 100644 (file)
@@ -327,21 +327,26 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, expansion: Mark) {
                 let def = Def::Struct(self.definitions.local_def_id(item.id));
                 self.define(parent, ident, TypeNS, (def, vis, sp, expansion));
 
-                // If this is a tuple or unit struct, define a name
-                // in the value namespace as well.
-                if !struct_def.is_struct() {
-                    let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()),
-                                                   CtorKind::from_ast(struct_def));
-                    self.define(parent, ident, ValueNS, (ctor_def, vis, sp, expansion));
-                }
-
                 // Record field names for error reporting.
+                let mut ctor_vis = vis;
                 let field_names = struct_def.fields().iter().filter_map(|field| {
-                    self.resolve_visibility(&field.vis);
+                    let field_vis = self.resolve_visibility(&field.vis);
+                    if ctor_vis.is_at_least(field_vis, &*self) {
+                        ctor_vis = field_vis;
+                    }
                     field.ident.map(|ident| ident.name)
                 }).collect();
                 let item_def_id = self.definitions.local_def_id(item.id);
                 self.insert_field_names(item_def_id, field_names);
+
+                // If this is a tuple or unit struct, define a name
+                // in the value namespace as well.
+                if !struct_def.is_struct() {
+                    let ctor_def = Def::StructCtor(self.definitions.local_def_id(struct_def.id()),
+                                                   CtorKind::from_ast(struct_def));
+                    self.define(parent, ident, ValueNS, (ctor_def, ctor_vis, sp, expansion));
+                    self.struct_constructors.insert(def.def_id(), (ctor_def, ctor_vis));
+                }
             }
 
             ItemKind::Union(ref vdata, _) => {
@@ -434,9 +439,17 @@ fn build_reduced_graph_for_external_crate_def(&mut self, parent: Module<'a>, chi
             Def::Variant(..) | Def::TyAlias(..) => {
                 self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
             }
-            Def::Fn(..) | Def::Static(..) | Def::Const(..) |
-            Def::VariantCtor(..) | Def::StructCtor(..) => {
+            Def::Fn(..) | Def::Static(..) | Def::Const(..) | Def::VariantCtor(..) => {
+                self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
+            }
+            Def::StructCtor(..) => {
                 self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
+
+                if let Some(struct_def_id) =
+                        self.session.cstore.def_key(def_id).parent
+                            .map(|index| DefId { krate: def_id.krate, index: index }) {
+                    self.struct_constructors.insert(struct_def_id, (def, vis));
+                }
             }
             Def::Trait(..) => {
                 let module_kind = ModuleKind::Def(def, ident.name);
index b5e2715ab4f0b141d51d5776a365450a6c9432d8..676ff98e602d6714fe1204b2f625583f874a594d 100644 (file)
@@ -45,7 +45,7 @@
 use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
 use rustc::ty;
 use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
-use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet};
+use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet, DefIdMap};
 
 use syntax::ext::hygiene::{Mark, SyntaxContext};
 use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy};
@@ -1131,6 +1131,10 @@ pub struct Resolver<'a> {
     warned_proc_macros: FxHashSet<Name>,
 
     potentially_unused_imports: Vec<&'a ImportDirective<'a>>,
+
+    // This table maps struct IDs into struct constructor IDs,
+    // it's not used during normal resolution, only for better error reporting.
+    struct_constructors: DefIdMap<(Def, ty::Visibility)>,
 }
 
 pub struct ResolverArenas<'a> {
@@ -1310,6 +1314,7 @@ pub fn new(session: &'a Session,
             proc_macro_enabled: features.proc_macro,
             warned_proc_macros: FxHashSet(),
             potentially_unused_imports: Vec::new(),
+            struct_constructors: DefIdMap(),
         }
     }
 
@@ -2205,6 +2210,15 @@ fn smart_resolve_path_fragment(&mut self,
                         _ => {}
                     },
                     _ if ns == ValueNS && is_struct_like(def) => {
+                        if let Def::Struct(def_id) = def {
+                            if let Some((ctor_def, ctor_vis))
+                                    = this.struct_constructors.get(&def_id).cloned() {
+                                if is_expected(ctor_def) && !this.is_accessible(ctor_vis) {
+                                    err.span_label(span, &format!("constructor is not visible \
+                                                                   here due to private fields"));
+                                }
+                            }
+                        }
                         err.span_label(span, &format!("did you mean `{} {{ /* fields */ }}`?",
                                                        path_str));
                         return err;
@@ -2235,7 +2249,23 @@ fn smart_resolve_path_fragment(&mut self,
                 if is_expected(resolution.base_def) || resolution.base_def == Def::Err {
                     resolution
                 } else {
-                    report_errors(self, Some(resolution.base_def))
+                    // Add a temporary hack to smooth the transition to new struct ctor
+                    // visibility rules. See #38932 for more details.
+                    let mut res = None;
+                    if let Def::Struct(def_id) = resolution.base_def {
+                        if let Some((ctor_def, ctor_vis))
+                                = self.struct_constructors.get(&def_id).cloned() {
+                            if is_expected(ctor_def) && self.is_accessible(ctor_vis) {
+                                let lint = lint::builtin::LEGACY_CONSTRUCTOR_VISIBILITY;
+                                self.session.add_lint(lint, id, span,
+                                    "private struct constructors are not usable through \
+                                     reexports in outer modules".to_string());
+                                res = Some(PathResolution::new(ctor_def));
+                            }
+                        }
+                    }
+
+                    res.unwrap_or_else(|| report_errors(self, Some(resolution.base_def)))
                 }
             }
             Some(resolution) if source.defer_to_typeck() => {
index 8cc3b60a184064fba089f287f75d9955f05fa284..442a2f4074215a4f519ea4ec2c792520ca8ebf75 100644 (file)
@@ -660,8 +660,6 @@ fn t(s: &str,
         t("no_run",                false,        true,   false,  true,  false, false, Vec::new());
         t("test_harness",          false,        false,  false,  true,  true,  false, Vec::new());
         t("compile_fail",          false,        true,   false,  true,  false, true,  Vec::new());
-        t("E0450",                 false,        false,  false,  true,  false, false,
-                                   vec!["E0450".to_owned()]);
         t("{.no_run .example}",    false,        true,   false,  true,  false, false, Vec::new());
         t("{.sh .should_panic}",   true,         false,  false,  true,  false, false, Vec::new());
         t("{.example .rust}",      false,        false,  false,  true,  false, false, Vec::new());
index c2123ea5a079803a3897053afefec54656df786e..c278171aa109a81120433777fafd9a4504dedb53 100644 (file)
@@ -140,7 +140,7 @@ impl Keyword {
         $(
             #[allow(non_upper_case_globals)]
             pub const $konst: Keyword = Keyword {
-                ident: ast::Ident::with_empty_ctxt(ast::Name($index))
+                ident: ast::Ident::with_empty_ctxt(super::Symbol($index))
             };
         )*
     }
@@ -282,25 +282,24 @@ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
 #[cfg(test)]
 mod tests {
     use super::*;
-    use ast::Name;
 
     #[test]
     fn interner_tests() {
         let mut i: Interner = Interner::new();
         // first one is zero:
-        assert_eq!(i.intern("dog"), Name(0));
+        assert_eq!(i.intern("dog"), Symbol(0));
         // re-use gets the same entry:
-        assert_eq!(i.intern ("dog"), Name(0));
+        assert_eq!(i.intern ("dog"), Symbol(0));
         // different string gets a different #:
-        assert_eq!(i.intern("cat"), Name(1));
-        assert_eq!(i.intern("cat"), Name(1));
+        assert_eq!(i.intern("cat"), Symbol(1));
+        assert_eq!(i.intern("cat"), Symbol(1));
         // dog is still at zero
-        assert_eq!(i.intern("dog"), Name(0));
+        assert_eq!(i.intern("dog"), Symbol(0));
         // gensym gets 3
-        assert_eq!(i.gensym("zebra"), Name(2));
+        assert_eq!(i.gensym("zebra"), Symbol(2));
         // gensym of same string gets new number :
-        assert_eq!(i.gensym("zebra"), Name(3));
+        assert_eq!(i.gensym("zebra"), Symbol(3));
         // gensym of *existing* string gets new number:
-        assert_eq!(i.gensym("dog"), Name(4));
+        assert_eq!(i.gensym("dog"), Symbol(4));
     }
 }
index aab92575321e34704db011cf353753b2bf4c9c2e..b9839edea2dc4e5b4e39e6423e53525341c60b61 100644 (file)
 fn main() {
     // Okay
     let Record { .. } = Record::new();
-    // Okay (for now; see RFC Issue #902)
-    let Tuple(..) = Tuple::new();
 
     // Okay
     let Record { a_stable_pub: _, a_unstable_declared_pub: _, .. } = Record::new();
-    // Okay (for now; see RFC Issue #902)
-    let Tuple(_, _, ..) = Tuple::new(); // analogous to above
 
     let Record { a_stable_pub: _, a_unstable_declared_pub: _, a_unstable_undeclared_pub: _, .. } =
         Record::new();
     //~^^ ERROR use of unstable library feature 'unstable_undeclared'
 
-    let Tuple(_, _, _, ..) = Tuple::new(); // analogous to previous
-    //~^ ERROR use of unstable library feature 'unstable_undeclared'
-
     let r = Record::new();
     let t = Tuple::new();
 
diff --git a/src/test/compile-fail/E0450.rs b/src/test/compile-fail/E0450.rs
deleted file mode 100644 (file)
index 200b58a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 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.
-
-mod Bar {
-    pub struct Foo( bool, pub i32, f32, bool);
-    //~^ NOTE private field declared here
-    //~| NOTE private field declared here
-    //~| NOTE private field declared here
-}
-
-fn main() {
-    let f = Bar::Foo(false,1,0.1, true); //~ ERROR E0450
-                         //~^ NOTE cannot construct with a private field
-}
index f7b106d160dae78d1c0fdc87997a8314d639fbbf..ace96c9983e66612097228f6a949778e797cf0f0 100644 (file)
@@ -25,11 +25,6 @@ fn pat_match(foo: Bar::Foo) {
                                   //~^ NOTE field `b` is private
 }
 
-fn pat_match_tuple(foo: Bar::FooTuple) {
-    let Bar::FooTuple(a,b) = foo; //~ ERROR E0451
-                                  //~^ NOTE field `1` is private
-}
-
 fn main() {
     let f = Bar::Foo{ a: 0, b: 0 }; //~ ERROR E0451
                                     //~^ NOTE field `b` is private
index 00305eb2bc04bf2f3e9f7a31aacc5f4cf44a645a..3b62aaf2ab8e9450789eca11ffa54610af1bc333 100644 (file)
@@ -10,7 +10,8 @@
 
 fn main() {
     let Box(a) = loop { };
-    //~^ ERROR field `0` of struct `std::boxed::Box` is private
+    //~^ ERROR expected tuple struct/variant, found struct `Box`
+    //~| ERROR expected tuple struct/variant, found struct `Box`
 
     // (The below is a trick to allow compiler to infer a type for
     // variable `a` without attempting to ascribe a type to the
diff --git a/src/test/compile-fail/privacy/legacy-ctor-visibility.rs b/src/test/compile-fail/privacy/legacy-ctor-visibility.rs
new file mode 100644 (file)
index 0000000..fb65af2
--- /dev/null
@@ -0,0 +1,28 @@
+// Copyright 2017 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.
+
+#![allow(unused)]
+
+use m::S;
+
+mod m {
+    pub struct S(u8);
+
+    mod n {
+        use S;
+        fn f() {
+            S(10);
+            //~^ ERROR private struct constructors are not usable through reexports in outer modules
+            //~| WARN this was previously accepted
+        }
+    }
+}
+
+fn main() {}
index 9d6ae187cd381f0aa2f9d9c5257d6b0d93772475..599c1f871604406bd3f6f99470b3078d073c2603 100644 (file)
@@ -58,30 +58,31 @@ fn test() {
 }
 
 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 a = a::A(()); //~ ERROR tuple struct `A` is private
+    let b = a::B(2); //~ ERROR tuple struct `B` is private
+    let c = a::C(2, 3); //~ ERROR tuple struct `C` is private
     let d = a::D(4);
 
-    let a::A(()) = a; //~ ERROR: field `0` of struct `a::A` is private
-    let a::A(_) = a;
-    match a { a::A(()) => {} } //~ ERROR: field `0` of struct `a::A` is private
-    match a { a::A(_) => {} }
-
-    let a::B(_) = b;
-    let a::B(_b) = b; //~ ERROR: field `0` of struct `a::B` is private
-    match b { a::B(_) => {} }
-    match b { a::B(_b) => {} } //~ ERROR: field `0` of struct `a::B` is private
-    match b { a::B(1) => {} a::B(_) => {} } //~ ERROR: field `0` of struct `a::B` is private
-
-    let a::C(_, _) = c;
-    let a::C(_a, _) = c;
-    let a::C(_, _b) = c; //~ ERROR: field `1` of struct `a::C` is private
-    let a::C(_a, _b) = c; //~ ERROR: field `1` of struct `a::C` is private
-    match c { a::C(_, _) => {} }
-    match c { a::C(_a, _) => {} }
-    match c { a::C(_, _b) => {} } //~ ERROR: field `1` of struct `a::C` is private
-    match c { a::C(_a, _b) => {} } //~ ERROR: field `1` of struct `a::C` is private
+    let a::A(()) = a; //~ ERROR tuple struct `A` is private
+    let a::A(_) = a; //~ ERROR tuple struct `A` is private
+    match a { a::A(()) => {} } //~ ERROR tuple struct `A` is private
+    match a { a::A(_) => {} } //~ ERROR tuple struct `A` is private
+
+    let a::B(_) = b; //~ ERROR tuple struct `B` is private
+    let a::B(_b) = b; //~ ERROR tuple struct `B` is private
+    match b { a::B(_) => {} } //~ ERROR tuple struct `B` is private
+    match b { a::B(_b) => {} } //~ ERROR tuple struct `B` is private
+    match b { a::B(1) => {} a::B(_) => {} } //~ ERROR tuple struct `B` is private
+                                            //~^ ERROR tuple struct `B` is private
+
+    let a::C(_, _) = c; //~ ERROR tuple struct `C` is private
+    let a::C(_a, _) = c; //~ ERROR tuple struct `C` is private
+    let a::C(_, _b) = c; //~ ERROR tuple struct `C` is private
+    let a::C(_a, _b) = c; //~ ERROR tuple struct `C` is private
+    match c { a::C(_, _) => {} } //~ ERROR tuple struct `C` is private
+    match c { a::C(_a, _) => {} } //~ ERROR tuple struct `C` is private
+    match c { a::C(_, _b) => {} } //~ ERROR tuple struct `C` is private
+    match c { a::C(_a, _b) => {} } //~ ERROR tuple struct `C` is private
 
     let a::D(_) = d;
     let a::D(_d) = d;
@@ -89,42 +90,38 @@ fn this_crate() {
     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 a2 = a::A; //~ ERROR tuple struct `A` is private
+    let b2 = a::B; //~ ERROR tuple struct `B` is private
+    let c2 = a::C; //~ ERROR tuple struct `C` is private
     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 a = other::A(()); //~ ERROR tuple struct `A` is private
+    let b = other::B(2); //~ ERROR tuple struct `B` is private
+    let c = other::C(2, 3); //~ ERROR tuple struct `C` is private
     let d = other::D(4);
 
-    let other::A(()) = a; //~ ERROR: field `0` of struct `other::A` is private
-    let other::A(_) = a;
-    match a { other::A(()) => {} }
-    //~^ ERROR: field `0` of struct `other::A` is private
-    match a { other::A(_) => {} }
-
-    let other::B(_) = b;
-    let other::B(_b) = b; //~ ERROR: field `0` of struct `other::B` is private
-    match b { other::B(_) => {} }
-    match b { other::B(_b) => {} }
-    //~^ ERROR: field `0` of struct `other::B` is private
-    match b { other::B(1) => {} other::B(_) => {} }
-    //~^ ERROR: field `0` of struct `other::B` is private
-
-    let other::C(_, _) = c;
-    let other::C(_a, _) = c;
-    let other::C(_, _b) = c; //~ ERROR: field `1` of struct `other::C` is private
-    let other::C(_a, _b) = c; //~ ERROR: field `1` of struct `other::C` is private
-    match c { other::C(_, _) => {} }
-    match c { other::C(_a, _) => {} }
-    match c { other::C(_, _b) => {} }
-    //~^ ERROR: field `1` of struct `other::C` is private
-    match c { other::C(_a, _b) => {} }
-    //~^ ERROR: field `1` of struct `other::C` is private
+    let other::A(()) = a; //~ ERROR tuple struct `A` is private
+    let other::A(_) = a; //~ ERROR tuple struct `A` is private
+    match a { other::A(()) => {} } //~ ERROR tuple struct `A` is private
+    match a { other::A(_) => {} } //~ ERROR tuple struct `A` is private
+
+    let other::B(_) = b; //~ ERROR tuple struct `B` is private
+    let other::B(_b) = b; //~ ERROR tuple struct `B` is private
+    match b { other::B(_) => {} } //~ ERROR tuple struct `B` is private
+    match b { other::B(_b) => {} } //~ ERROR tuple struct `B` is private
+    match b { other::B(1) => {} other::B(_) => {} } //~ ERROR tuple struct `B` is private
+                                                    //~^ ERROR tuple struct `B` is private
+
+    let other::C(_, _) = c; //~ ERROR tuple struct `C` is private
+    let other::C(_a, _) = c; //~ ERROR tuple struct `C` is private
+    let other::C(_, _b) = c; //~ ERROR tuple struct `C` is private
+    let other::C(_a, _b) = c; //~ ERROR tuple struct `C` is private
+    match c { other::C(_, _) => {} } //~ ERROR tuple struct `C` is private
+    match c { other::C(_a, _) => {} } //~ ERROR tuple struct `C` is private
+    match c { other::C(_, _b) => {} } //~ ERROR tuple struct `C` is private
+    match c { other::C(_a, _b) => {} } //~ ERROR tuple struct `C` is private
 
     let other::D(_) = d;
     let other::D(_d) = d;
@@ -132,9 +129,9 @@ fn xcrate() {
     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 a2 = other::A; //~ ERROR tuple struct `A` is private
+    let b2 = other::B; //~ ERROR tuple struct `B` is private
+    let c2 = other::C; //~ ERROR tuple struct `C` is private
     let d2 = other::D;
 }
 
diff --git a/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs b/src/test/ui/resolve/auxiliary/privacy-struct-ctor.rs
new file mode 100644 (file)
index 0000000..f190f5d
--- /dev/null
@@ -0,0 +1,21 @@
+// Copyright 2016 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.
+
+#![feature(pub_restricted)]
+
+pub mod m {
+    pub struct S(u8);
+
+    pub mod n {
+        pub(m) struct Z(pub(m::n) u8);
+    }
+}
+
+pub use m::S;
diff --git a/src/test/ui/resolve/privacy-struct-ctor.rs b/src/test/ui/resolve/privacy-struct-ctor.rs
new file mode 100644 (file)
index 0000000..3d0c76c
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright 2016 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-struct-ctor.rs
+
+#![feature(pub_restricted)]
+
+extern crate privacy_struct_ctor as xcrate;
+
+mod m {
+    pub struct S(u8);
+
+    pub mod n {
+        pub(m) struct Z(pub(m::n) u8);
+    }
+
+    use m::n::Z; // OK, only the type is imported
+
+    fn f() {
+        n::Z; //~ ERROR tuple struct `Z` is private
+        Z;
+        //~^ ERROR expected value, found struct `Z`
+        //~| NOTE tuple struct constructors with private fields are invisible outside of their mod
+    }
+}
+
+use m::S; // OK, only the type is imported
+
+fn main() {
+    m::S; //~ ERROR tuple struct `S` is private
+    S;
+    //~^ ERROR expected value, found struct `S`
+    //~| NOTE constructor is not visible here due to private fields
+    m::n::Z; //~ ERROR tuple struct `Z` is private
+
+    xcrate::m::S; //~ ERROR tuple struct `S` is private
+    xcrate::S;
+    //~^ ERROR expected value, found struct `xcrate::S`
+    //~| NOTE constructor is not visible here due to private fields
+    xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private
+}
diff --git a/src/test/ui/resolve/privacy-struct-ctor.stderr b/src/test/ui/resolve/privacy-struct-ctor.stderr
new file mode 100644 (file)
index 0000000..30fdbb0
--- /dev/null
@@ -0,0 +1,68 @@
+error[E0423]: expected value, found struct `Z`
+  --> $DIR/privacy-struct-ctor.rs:28:9
+   |
+28 |         Z;
+   |         ^
+   |         |
+   |         did you mean `Z { /* fields */ }`?
+   |         constructor is not visible here due to private fields
+   |
+   = help: possible better candidate is found in another module, you can import it into scope:
+             `use m::n::Z;`
+
+error[E0423]: expected value, found struct `S`
+  --> $DIR/privacy-struct-ctor.rs:38:5
+   |
+38 |     S;
+   |     ^
+   |     |
+   |     did you mean `S { /* fields */ }`?
+   |     constructor is not visible here due to private fields
+   |
+   = help: possible better candidate is found in another module, you can import it into scope:
+             `use m::S;`
+
+error[E0423]: expected value, found struct `xcrate::S`
+  --> $DIR/privacy-struct-ctor.rs:44:5
+   |
+44 |     xcrate::S;
+   |     ^^^^^^^^^
+   |     |
+   |     did you mean `xcrate::S { /* fields */ }`?
+   |     constructor is not visible here due to private fields
+   |
+   = help: possible better candidate is found in another module, you can import it into scope:
+             `use m::S;`
+
+error: tuple struct `Z` is private
+  --> $DIR/privacy-struct-ctor.rs:27:9
+   |
+27 |         n::Z; //~ ERROR tuple struct `Z` is private
+   |         ^^^^
+
+error: tuple struct `S` is private
+  --> $DIR/privacy-struct-ctor.rs:37:5
+   |
+37 |     m::S; //~ ERROR tuple struct `S` is private
+   |     ^^^^
+
+error: tuple struct `Z` is private
+  --> $DIR/privacy-struct-ctor.rs:41:5
+   |
+41 |     m::n::Z; //~ ERROR tuple struct `Z` is private
+   |     ^^^^^^^
+
+error: tuple struct `S` is private
+  --> $DIR/privacy-struct-ctor.rs:43:5
+   |
+43 |     xcrate::m::S; //~ ERROR tuple struct `S` is private
+   |     ^^^^^^^^^^^^
+
+error: tuple struct `Z` is private
+  --> $DIR/privacy-struct-ctor.rs:47:5
+   |
+47 |     xcrate::m::n::Z; //~ ERROR tuple struct `Z` is private
+   |     ^^^^^^^^^^^^^^^
+
+error: aborting due to 8 previous errors
+