From df4821698e867a468c9237af30cd5bc4a7bc2773 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Feb 2016 21:20:56 +0300 Subject: [PATCH 1/3] Permit `pub` items in blocks --- src/librustc_privacy/lib.rs | 64 +------------------- src/test/compile-fail/privacy-sanity.rs | 50 ++++++--------- src/test/compile-fail/unnecessary-private.rs | 27 --------- 3 files changed, 20 insertions(+), 121 deletions(-) delete mode 100644 src/test/compile-fail/unnecessary-private.rs diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 8908dac7a36..0b0753ac327 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1129,35 +1129,12 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> { struct SanePrivacyVisitor<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, - in_block: bool, } impl<'a, 'tcx, 'v> Visitor<'v> for SanePrivacyVisitor<'a, 'tcx> { - /// We want to visit items in the context of their containing - /// module and so forth, so supply a crate for doing a deep walk. - fn visit_nested_item(&mut self, item: hir::ItemId) { - self.visit_item(self.tcx.map.expect_item(item.id)) - } - fn visit_item(&mut self, item: &hir::Item) { self.check_sane_privacy(item); - if self.in_block { - self.check_all_inherited(item); - } - - let orig_in_block = self.in_block; - - // Modules turn privacy back on, otherwise we inherit - self.in_block = if let hir::ItemMod(..) = item.node { false } else { orig_in_block }; - intravisit::walk_item(self, item); - self.in_block = orig_in_block; - } - - fn visit_block(&mut self, b: &'v hir::Block) { - let orig_in_block = replace(&mut self.in_block, true); - intravisit::walk_block(self, b); - self.in_block = orig_in_block; } } @@ -1206,40 +1183,6 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { hir::ItemUse(..) | hir::ItemTy(..) => {} } } - - /// When inside of something like a function or a method, visibility has no - /// control over anything so this forbids any mention of any visibility - fn check_all_inherited(&self, item: &hir::Item) { - let check_inherited = |sp, vis| { - if vis != hir::Inherited { - span_err!(self.tcx.sess, sp, E0447, - "visibility has no effect inside functions or block expressions"); - } - }; - - check_inherited(item.span, item.vis); - match item.node { - hir::ItemImpl(_, _, _, _, _, ref impl_items) => { - for impl_item in impl_items { - check_inherited(impl_item.span, impl_item.vis); - } - } - hir::ItemForeignMod(ref fm) => { - for fi in &fm.items { - check_inherited(fi.span, fi.vis); - } - } - hir::ItemStruct(ref vdata, _) => { - for f in vdata.fields() { - check_inherited(f.span, f.node.kind.visibility()); - } - } - hir::ItemDefaultImpl(..) | hir::ItemEnum(..) | hir::ItemTrait(..) | - hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | - hir::ItemMod(..) | hir::ItemExternCrate(..) | - hir::ItemUse(..) | hir::ItemTy(..) => {} - } - } } /////////////////////////////////////////////////////////////////////////////// @@ -1823,11 +1766,8 @@ pub fn check_crate(tcx: &ty::ctxt, // Sanity check to make sure that all privacy usage and controls are // reasonable. - let mut visitor = SanePrivacyVisitor { - tcx: tcx, - in_block: false, - }; - intravisit::walk_crate(&mut visitor, krate); + let mut visitor = SanePrivacyVisitor { tcx: tcx }; + krate.visit_all_items(&mut visitor); // Figure out who everyone's parent is let mut visitor = ParentVisitor { diff --git a/src/test/compile-fail/privacy-sanity.rs b/src/test/compile-fail/privacy-sanity.rs index 336913b8772..063848f62aa 100644 --- a/src/test/compile-fail/privacy-sanity.rs +++ b/src/test/compile-fail/privacy-sanity.rs @@ -40,37 +40,30 @@ pub extern "C" { //~ ERROR unnecessary visibility qualifier const MAIN: u8 = { trait MarkerTr {} - pub trait Tr { //~ ERROR visibility has no effect inside functions or block + pub trait Tr { fn f(); const C: u8; type T; } - pub struct S { //~ ERROR visibility has no effect inside functions or block - pub a: u8 //~ ERROR visibility has no effect inside functions or block + pub struct S { + pub a: u8 } - struct Ts(pub u8); //~ ERROR visibility has no effect inside functions or block + struct Ts(pub u8); pub impl MarkerTr for .. {} //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block pub impl Tr for S { //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block pub fn f() {} //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block pub const C: u8 = 0; //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block pub type T = u8; //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block } pub impl S { //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block - pub fn f() {} //~ ERROR visibility has no effect inside functions or block - pub const C: u8 = 0; //~ ERROR visibility has no effect inside functions or block - // pub type T = u8; // ERROR visibility has no effect inside functions or block + pub fn f() {} + pub const C: u8 = 0; + // pub type T = u8; } pub extern "C" { //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block - pub fn f(); //~ ERROR visibility has no effect inside functions or block - pub static St: u8; //~ ERROR visibility has no effect inside functions or block + pub fn f(); + pub static St: u8; } 0 @@ -78,36 +71,29 @@ const MAIN: u8 = { fn main() { trait MarkerTr {} - pub trait Tr { //~ ERROR visibility has no effect inside functions or block + pub trait Tr { fn f(); const C: u8; type T; } - pub struct S { //~ ERROR visibility has no effect inside functions or block - pub a: u8 //~ ERROR visibility has no effect inside functions or block + pub struct S { + pub a: u8 } - struct Ts(pub u8); //~ ERROR visibility has no effect inside functions or block + struct Ts(pub u8); pub impl MarkerTr for .. {} //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block pub impl Tr for S { //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block pub fn f() {} //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block pub const C: u8 = 0; //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block pub type T = u8; //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block } pub impl S { //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block - pub fn f() {} //~ ERROR visibility has no effect inside functions or block - pub const C: u8 = 0; //~ ERROR visibility has no effect inside functions or block - // pub type T = u8; // ERROR visibility has no effect inside functions or block + pub fn f() {} + pub const C: u8 = 0; + // pub type T = u8; } pub extern "C" { //~ ERROR unnecessary visibility qualifier - //~^ ERROR visibility has no effect inside functions or block - pub fn f(); //~ ERROR visibility has no effect inside functions or block - pub static St: u8; //~ ERROR visibility has no effect inside functions or block + pub fn f(); + pub static St: u8; } } diff --git a/src/test/compile-fail/unnecessary-private.rs b/src/test/compile-fail/unnecessary-private.rs deleted file mode 100644 index 113393490cb..00000000000 --- a/src/test/compile-fail/unnecessary-private.rs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright 2013-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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -fn main() { - pub use std::usize; //~ ERROR: visibility has no effect - pub struct A; //~ ERROR: visibility has no effect - pub enum B {} //~ ERROR: visibility has no effect - pub trait C { //~ ERROR: visibility has no effect - fn foo(&self) {} - } - impl A { - pub fn foo(&self) {} //~ ERROR: visibility has no effect - } - - struct D { - pub foo: isize, //~ ERROR: visibility has no effect - } - pub fn foo() {} //~ ERROR: visibility has no effect - pub mod bar {} //~ ERROR: visibility has no effect -} From fa427266ee5241868332f0401cf7e86ce3c29cc9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 26 Feb 2016 22:06:39 +0300 Subject: [PATCH 2/3] Some drive-by improvements to SanePrivacyVisitor Check that variant fields are not marked public by syntax extensions --- src/librustc_privacy/lib.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index 0b0753ac327..e0ede288523 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -1139,10 +1139,9 @@ impl<'a, 'tcx, 'v> Visitor<'v> for SanePrivacyVisitor<'a, 'tcx> { } impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { - /// Validates all of the visibility qualifiers placed on the item given. This - /// ensures that there are no extraneous qualifiers that don't actually do - /// anything. In theory these qualifiers wouldn't parse, but that may happen - /// later on down the road... + /// Validate that items that shouldn't have visibility qualifiers don't have them. + /// Such qualifiers can be set by syntax extensions even if the parser doesn't allow them, + /// so we check things like variant fields too. fn check_sane_privacy(&self, item: &hir::Item) { let check_inherited = |sp, vis, note: &str| { if vis != hir::Inherited { @@ -1156,13 +1155,12 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { }; match item.node { - // implementations of traits don't need visibility qualifiers because - // that's controlled by having the trait in scope. hir::ItemImpl(_, _, _, Some(..), _, ref impl_items) => { check_inherited(item.span, item.vis, "visibility qualifiers have no effect on trait impls"); for impl_item in impl_items { - check_inherited(impl_item.span, impl_item.vis, ""); + check_inherited(impl_item.span, impl_item.vis, + "visibility qualifiers have no effect on trait impl items"); } } hir::ItemImpl(_, _, _, None, _, _) => { @@ -1177,7 +1175,15 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> { check_inherited(item.span, item.vis, "place qualifiers on individual functions instead"); } - hir::ItemStruct(..) | hir::ItemEnum(..) | hir::ItemTrait(..) | + hir::ItemEnum(ref def, _) => { + for variant in &def.variants { + for field in variant.node.data.fields() { + check_inherited(field.span, field.node.kind.visibility(), + "visibility qualifiers have no effect on variant fields"); + } + } + } + hir::ItemStruct(..) | hir::ItemTrait(..) | hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemExternCrate(..) | hir::ItemUse(..) | hir::ItemTy(..) => {} @@ -1764,8 +1770,7 @@ pub fn check_crate(tcx: &ty::ctxt, let krate = tcx.map.krate(); - // Sanity check to make sure that all privacy usage and controls are - // reasonable. + // Sanity check to make sure that all privacy usage is reasonable. let mut visitor = SanePrivacyVisitor { tcx: tcx }; krate.visit_all_items(&mut visitor); From b6f441d9861868eefd81460e0c3e4295fca12ffe Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 28 Feb 2016 14:50:58 +0300 Subject: [PATCH 3/3] Add some tests --- src/test/run-pass/issue-31776.rs | 64 ++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 src/test/run-pass/issue-31776.rs diff --git a/src/test/run-pass/issue-31776.rs b/src/test/run-pass/issue-31776.rs new file mode 100644 index 00000000000..a12e569df2b --- /dev/null +++ b/src/test/run-pass/issue-31776.rs @@ -0,0 +1,64 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Various scenarios in which `pub` is required in blocks + +struct S; + +mod m { + fn f() { + impl ::S { + pub fn s(&self) {} + } + } +} + +// ------------------------------------------------------ + +pub trait Tr { + type A; +} +pub struct S1; + +fn f() { + pub struct Z; + + impl ::Tr for ::S1 { + type A = Z; // Private-in-public error unless `struct Z` is pub + } +} + +// ------------------------------------------------------ + +trait Tr1 { + type A; + fn pull(&self) -> Self::A; +} +struct S2; + +mod m1 { + fn f() { + struct Z { + pub field: u8 + } + + impl ::Tr1 for ::S2 { + type A = Z; + fn pull(&self) -> Self::A { Z{field: 10} } + } + } +} + +// ------------------------------------------------------ + +fn main() { + S.s(); // Privacy error, unless `fn s` is pub + let a = S2.pull().field; // Privacy error unless `field: u8` is pub +}