Skip to content

Forbid privacy in inner functions #10443

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 1 commit into from
Nov 18, 2013
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
1 change: 1 addition & 0 deletions doc/rust.md
Original file line number Diff line number Diff line change
Expand Up @@ -1548,6 +1548,7 @@ keyword for struct fields and enum variants). When an item is declared as `pub`,
it can be thought of as being accessible to the outside world. For example:

~~~~
# fn main() {}
// Declare a private struct
struct Foo;

Expand Down
2 changes: 2 additions & 0 deletions doc/tutorial-container.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ Reaching the end of the iterator is signalled by returning `None` instead of
`Some(item)`:

~~~
# fn main() {}
/// A stream of N zeroes
struct ZeroStream {
priv remaining: uint
Expand Down Expand Up @@ -301,6 +302,7 @@ the iterator can provide better information.
The `ZeroStream` from earlier can provide an exact lower and upper bound:

~~~
# fn main() {}
/// A stream of N zeroes
struct ZeroStream {
priv remaining: uint
Expand Down
6 changes: 3 additions & 3 deletions doc/tutorial-macros.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ Now consider code like the following:

~~~~
# enum t1 { good_1(t2, uint), bad_1 };
# pub struct t2 { body: t3 }
# struct t2 { body: t3 }
# enum t3 { good_2(uint), bad_2};
# fn f(x: t1) -> uint {
match x {
Expand Down Expand Up @@ -262,7 +262,7 @@ macro_rules! biased_match (
)

# enum t1 { good_1(t2, uint), bad_1 };
# pub struct t2 { body: t3 }
# struct t2 { body: t3 }
# enum t3 { good_2(uint), bad_2};
# fn f(x: t1) -> uint {
biased_match!((x) ~ (good_1(g1, val)) else { return 0 };
Expand Down Expand Up @@ -364,7 +364,7 @@ macro_rules! biased_match (


# enum t1 { good_1(t2, uint), bad_1 };
# pub struct t2 { body: t3 }
# struct t2 { body: t3 }
# enum t3 { good_2(uint), bad_2};
# fn f(x: t1) -> uint {
biased_match!(
Expand Down
7 changes: 5 additions & 2 deletions doc/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -2568,6 +2568,7 @@ pub fn foo() { bar(); }
~~~
// c.rs
pub fn bar() { println("Baz!"); }
# fn main() {}
~~~

There also exist two short forms for importing multiple names at once:
Expand Down Expand Up @@ -2743,7 +2744,7 @@ Therefore, if you plan to compile your crate as a library, you should annotate i
#[link(name = "farm", vers = "2.5")];

// ...
# pub fn farm() {}
# fn farm() {}
~~~~

You can also in turn require in a `extern mod` statement that certain link metadata items match some criteria.
Expand All @@ -2769,7 +2770,7 @@ or setting the crate type (library or executable) explicitly:

// Turn on a warning
#[warn(non_camel_case_types)]
# pub fn farm() {}
# fn farm() {}
~~~~

If you're compiling your crate with `rustpkg`,
Expand All @@ -2790,7 +2791,9 @@ We define two crates, and use one of them as a library in the other.
~~~~
// world.rs
#[link(name = "world", vers = "0.42")];
# extern mod extra;
pub fn explore() -> &'static str { "world" }
# fn main() {}
~~~~

~~~~ {.xfail-test}
Expand Down
4 changes: 2 additions & 2 deletions src/libextra/sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,7 @@ mod tests {

fn check_sort(v1: &[int], v2: &[int]) {
let len = v1.len();
pub fn le(a: &int, b: &int) -> bool { *a <= *b }
fn le(a: &int, b: &int) -> bool { *a <= *b }
let f = le;
let v3 = merge_sort::<int>(v1, f);
let mut i = 0u;
Expand Down Expand Up @@ -876,7 +876,7 @@ mod tests {

#[test]
fn test_merge_sort_mutable() {
pub fn le(a: &int, b: &int) -> bool { *a <= *b }
fn le(a: &int, b: &int) -> bool { *a <= *b }
let v1 = ~[3, 2, 1];
let v2 = merge_sort(v1, le);
assert_eq!(v2, ~[1, 2, 3]);
Expand Down
82 changes: 79 additions & 3 deletions src/librustc/middle/privacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//! which are available for use externally when compiled as a library.

use std::hashmap::{HashSet, HashMap};
use std::util;

use middle::resolve;
use middle::ty;
Expand Down Expand Up @@ -275,6 +276,7 @@ impl<'self> Visitor<()> for EmbargoVisitor<'self> {
struct PrivacyVisitor<'self> {
tcx: ty::ctxt,
curitem: ast::NodeId,
in_fn: bool,

// See comments on the same field in `EmbargoVisitor`.
path_all_public_items: &'self ExportedItems,
Expand Down Expand Up @@ -688,6 +690,63 @@ impl<'self> PrivacyVisitor<'self> {
}
}
}

/// 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: @ast::item) {
let tcx = self.tcx;
let check_inherited = |sp: Span, vis: ast::visibility| {
if vis != ast::inherited {
tcx.sess.span_err(sp, "visibility has no effect inside functions");
}
};
let check_struct = |def: &@ast::struct_def| {
for f in def.fields.iter() {
match f.node.kind {
ast::named_field(_, p) => check_inherited(f.span, p),
ast::unnamed_field => {}
}
}
};
check_inherited(item.span, item.vis);
match item.node {
ast::item_impl(_, _, _, ref methods) => {
for m in methods.iter() {
check_inherited(m.span, m.vis);
}
}
ast::item_foreign_mod(ref fm) => {
for i in fm.items.iter() {
check_inherited(i.span, i.vis);
}
}
ast::item_enum(ref def, _) => {
for v in def.variants.iter() {
check_inherited(v.span, v.node.vis);

match v.node.kind {
ast::struct_variant_kind(ref s) => check_struct(s),
ast::tuple_variant_kind(*) => {}
}
}
}

ast::item_struct(ref def, _) => check_struct(def),

ast::item_trait(_, _, ref methods) => {
for m in methods.iter() {
match *m {
ast::required(*) => {}
ast::provided(ref m) => check_inherited(m.span, m.vis),
}
}
}

ast::item_static(*) |
ast::item_fn(*) | ast::item_mod(*) | ast::item_ty(*) |
ast::item_mac(*) => {}
}
}
}

impl<'self> Visitor<()> for PrivacyVisitor<'self> {
Expand All @@ -699,12 +758,28 @@ impl<'self> Visitor<()> for PrivacyVisitor<'self> {
}

// Disallow unnecessary visibility qualifiers
self.check_sane_privacy(item);
if self.in_fn {
self.check_all_inherited(item);
} else {
self.check_sane_privacy(item);
}

let orig_curitem = self.curitem;
self.curitem = item.id;
let orig_curitem = util::replace(&mut self.curitem, item.id);
let orig_in_fn = util::replace(&mut self.in_fn, match item.node {
ast::item_mod(*) => false, // modules turn privacy back on
_ => self.in_fn, // otherwise we inherit
});
visit::walk_item(self, item, ());
self.curitem = orig_curitem;
self.in_fn = orig_in_fn;
}

fn visit_fn(&mut self, fk: &visit::fn_kind, fd: &ast::fn_decl,
b: &ast::Block, s: Span, n: ast::NodeId, _: ()) {
// This catches both functions and methods
let orig_in_fn = util::replace(&mut self.in_fn, true);
visit::walk_fn(self, fk, fd, b, s, n, ());
self.in_fn = orig_in_fn;
}

fn visit_expr(&mut self, expr: @ast::Expr, _: ()) {
Expand Down Expand Up @@ -907,6 +982,7 @@ pub fn check_crate(tcx: ty::ctxt,
{
let mut visitor = PrivacyVisitor {
curitem: ast::DUMMY_NODE_ID,
in_fn: false,
tcx: tcx,
path_all_public_items: &path_all_public_items,
parents: &parents,
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1409,7 +1409,7 @@ pub fn subst_tps(tcx: ctxt, tps: &[t], self_ty_opt: Option<t>, typ: t) -> t {
let mut subst = TpsSubst { tcx: tcx, self_ty_opt: self_ty_opt, tps: tps };
return subst.fold_ty(typ);

pub struct TpsSubst<'self> {
struct TpsSubst<'self> {
tcx: ctxt,
self_ty_opt: Option<t>,
tps: &'self [t],
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax/ext/expand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,

let span = e.span;

pub fn mk_expr(_: @ExtCtxt, span: Span, node: Expr_)
fn mk_expr(_: @ExtCtxt, span: Span, node: Expr_)
-> @ast::Expr {
@ast::Expr {
id: ast::DUMMY_NODE_ID,
Expand Down
26 changes: 26 additions & 0 deletions src/test/compile-fail/unnecessary-private.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

fn main() {
pub struct A; //~ ERROR: visibility has no effect
pub enum B {} //~ ERROR: visibility has no effect
pub trait C { //~ ERROR: visibility has no effect
pub fn foo() {} //~ ERROR: visibility has no effect
}
impl A {
pub fn foo() {} //~ ERROR: visibility has no effect
}

struct D {
priv foo: int, //~ ERROR: visibility has no effect
}
pub fn foo() {} //~ ERROR: visibility has no effect
pub mod bar {} //~ ERROR: visibility has no effect
}
2 changes: 1 addition & 1 deletion src/test/run-pass/nested-class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub fn main() {
}

impl b {
pub fn do_stuff(&self) -> int { return 37; }
fn do_stuff(&self) -> int { return 37; }
}

fn b(i:int) -> b {
Expand Down