Skip to content

privacy: Permit pub items in blocks #31919

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 2, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 15 additions & 70 deletions src/librustc_privacy/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1129,43 +1129,19 @@ 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;
}
}

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 {
Expand All @@ -1179,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, _, _) => {
Expand All @@ -1200,41 +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::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
hir::ItemMod(..) | hir::ItemExternCrate(..) |
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::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::ItemDefaultImpl(..) | hir::ItemEnum(..) | hir::ItemTrait(..) |
hir::ItemStruct(..) | hir::ItemTrait(..) |
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
hir::ItemMod(..) | hir::ItemExternCrate(..) |
hir::ItemUse(..) | hir::ItemTy(..) => {}
Expand Down Expand Up @@ -1821,13 +1770,9 @@ 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.
let mut visitor = SanePrivacyVisitor {
tcx: tcx,
in_block: false,
};
intravisit::walk_crate(&mut visitor, krate);
// Sanity check to make sure that all privacy usage is reasonable.
let mut visitor = SanePrivacyVisitor { tcx: tcx };
krate.visit_all_items(&mut visitor);

// Figure out who everyone's parent is
let mut visitor = ParentVisitor {
Expand Down
50 changes: 18 additions & 32 deletions src/test/compile-fail/privacy-sanity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,74 +40,60 @@ 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
};

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;
}
}
27 changes: 0 additions & 27 deletions src/test/compile-fail/unnecessary-private.rs

This file was deleted.

64 changes: 64 additions & 0 deletions src/test/run-pass/issue-31776.rs
Original file line number Diff line number Diff line change
@@ -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 <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.

// 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
}