Skip to content

Commit ad3bd1b

Browse files
committed
Auto merge of #29726 - petrochenkov:privsan, r=alexcrichton
- Check privacy sanity in all blocks, not only function bodies - Check all fields, not only named - Check all impl items, not only methods - Check default impls - Move the sanity check in the beginning of privacy checking, so others could rely on it Technically it's a [breaking-change], but I expect no breakage because, well, it's *sane* privacy visitor, if code is broken it must be insane by definition!
2 parents 5f64201 + 41ccd44 commit ad3bd1b

File tree

4 files changed

+167
-77
lines changed

4 files changed

+167
-77
lines changed

src/doc/trpl/associated-constants.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,6 @@ for a `struct` or an `enum` works fine too:
7474
struct Foo;
7575

7676
impl Foo {
77-
pub const FOO: u32 = 3;
77+
const FOO: u32 = 3;
7878
}
7979
```

src/librustc_privacy/lib.rs

+53-70
Original file line numberDiff line numberDiff line change
@@ -1031,32 +1031,29 @@ impl<'a, 'tcx, 'v> Visitor<'v> for PrivacyVisitor<'a, 'tcx> {
10311031

10321032
struct SanePrivacyVisitor<'a, 'tcx: 'a> {
10331033
tcx: &'a ty::ctxt<'tcx>,
1034-
in_fn: bool,
1034+
in_block: bool,
10351035
}
10361036

10371037
impl<'a, 'tcx, 'v> Visitor<'v> for SanePrivacyVisitor<'a, 'tcx> {
10381038
fn visit_item(&mut self, item: &hir::Item) {
1039-
if self.in_fn {
1039+
self.check_sane_privacy(item);
1040+
if self.in_block {
10401041
self.check_all_inherited(item);
1041-
} else {
1042-
self.check_sane_privacy(item);
10431042
}
10441043

1045-
let in_fn = self.in_fn;
1046-
let orig_in_fn = replace(&mut self.in_fn, match item.node {
1047-
hir::ItemMod(..) => false, // modules turn privacy back on
1048-
_ => in_fn, // otherwise we inherit
1049-
});
1044+
let orig_in_block = self.in_block;
1045+
1046+
// Modules turn privacy back on, otherwise we inherit
1047+
self.in_block = if let hir::ItemMod(..) = item.node { false } else { orig_in_block };
1048+
10501049
visit::walk_item(self, item);
1051-
self.in_fn = orig_in_fn;
1050+
self.in_block = orig_in_block;
10521051
}
10531052

1054-
fn visit_fn(&mut self, fk: visit::FnKind<'v>, fd: &'v hir::FnDecl,
1055-
b: &'v hir::Block, s: Span, _: ast::NodeId) {
1056-
// This catches both functions and methods
1057-
let orig_in_fn = replace(&mut self.in_fn, true);
1058-
visit::walk_fn(self, fk, fd, b, s);
1059-
self.in_fn = orig_in_fn;
1053+
fn visit_block(&mut self, b: &'v hir::Block) {
1054+
let orig_in_block = replace(&mut self.in_block, true);
1055+
visit::walk_block(self, b);
1056+
self.in_block = orig_in_block;
10601057
}
10611058
}
10621059

@@ -1066,89 +1063,75 @@ impl<'a, 'tcx> SanePrivacyVisitor<'a, 'tcx> {
10661063
/// anything. In theory these qualifiers wouldn't parse, but that may happen
10671064
/// later on down the road...
10681065
fn check_sane_privacy(&self, item: &hir::Item) {
1069-
let tcx = self.tcx;
1070-
let check_inherited = |sp: Span, vis: hir::Visibility, note: &str| {
1066+
let check_inherited = |sp, vis, note: &str| {
10711067
if vis != hir::Inherited {
1072-
span_err!(tcx.sess, sp, E0449,
1073-
"unnecessary visibility qualifier");
1068+
span_err!(self.tcx.sess, sp, E0449, "unnecessary visibility qualifier");
10741069
if !note.is_empty() {
1075-
tcx.sess.span_note(sp, note);
1070+
self.tcx.sess.span_note(sp, note);
10761071
}
10771072
}
10781073
};
1074+
10791075
match item.node {
10801076
// implementations of traits don't need visibility qualifiers because
10811077
// that's controlled by having the trait in scope.
10821078
hir::ItemImpl(_, _, _, Some(..), _, ref impl_items) => {
10831079
check_inherited(item.span, item.vis,
1084-
"visibility qualifiers have no effect on trait \
1085-
impls");
1080+
"visibility qualifiers have no effect on trait impls");
10861081
for impl_item in impl_items {
10871082
check_inherited(impl_item.span, impl_item.vis, "");
10881083
}
10891084
}
1090-
1091-
hir::ItemImpl(..) => {
1085+
hir::ItemImpl(_, _, _, None, _, _) => {
10921086
check_inherited(item.span, item.vis,
10931087
"place qualifiers on individual methods instead");
10941088
}
1089+
hir::ItemDefaultImpl(..) => {
1090+
check_inherited(item.span, item.vis,
1091+
"visibility qualifiers have no effect on trait impls");
1092+
}
10951093
hir::ItemForeignMod(..) => {
10961094
check_inherited(item.span, item.vis,
1097-
"place qualifiers on individual functions \
1098-
instead");
1095+
"place qualifiers on individual functions instead");
10991096
}
1100-
1101-
hir::ItemEnum(..) |
1102-
hir::ItemTrait(..) | hir::ItemDefaultImpl(..) |
1103-
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemStruct(..) |
1104-
hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemTy(..) |
1105-
hir::ItemExternCrate(_) | hir::ItemUse(_) => {}
1097+
hir::ItemStruct(..) | hir::ItemEnum(..) | hir::ItemTrait(..) |
1098+
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
1099+
hir::ItemMod(..) | hir::ItemExternCrate(..) |
1100+
hir::ItemUse(..) | hir::ItemTy(..) => {}
11061101
}
11071102
}
11081103

11091104
/// When inside of something like a function or a method, visibility has no
11101105
/// control over anything so this forbids any mention of any visibility
11111106
fn check_all_inherited(&self, item: &hir::Item) {
1112-
let tcx = self.tcx;
1113-
fn check_inherited(tcx: &ty::ctxt, sp: Span, vis: hir::Visibility) {
1107+
let check_inherited = |sp, vis| {
11141108
if vis != hir::Inherited {
1115-
span_err!(tcx.sess, sp, E0447,
1116-
"visibility has no effect inside functions");
1117-
}
1118-
}
1119-
let check_struct = |def: &hir::VariantData| {
1120-
for f in def.fields() {
1121-
match f.node.kind {
1122-
hir::NamedField(_, p) => check_inherited(tcx, f.span, p),
1123-
hir::UnnamedField(..) => {}
1124-
}
1109+
span_err!(self.tcx.sess, sp, E0447,
1110+
"visibility has no effect inside functions or block expressions");
11251111
}
11261112
};
1127-
check_inherited(tcx, item.span, item.vis);
1113+
1114+
check_inherited(item.span, item.vis);
11281115
match item.node {
11291116
hir::ItemImpl(_, _, _, _, _, ref impl_items) => {
11301117
for impl_item in impl_items {
1131-
match impl_item.node {
1132-
hir::MethodImplItem(..) => {
1133-
check_inherited(tcx, impl_item.span, impl_item.vis);
1134-
}
1135-
_ => {}
1136-
}
1118+
check_inherited(impl_item.span, impl_item.vis);
11371119
}
11381120
}
11391121
hir::ItemForeignMod(ref fm) => {
1140-
for i in &fm.items {
1141-
check_inherited(tcx, i.span, i.vis);
1122+
for fi in &fm.items {
1123+
check_inherited(fi.span, fi.vis);
11421124
}
11431125
}
1144-
1145-
hir::ItemStruct(ref def, _) => check_struct(def),
1146-
1147-
hir::ItemEnum(..) |
1148-
hir::ItemExternCrate(_) | hir::ItemUse(_) |
1149-
hir::ItemTrait(..) | hir::ItemDefaultImpl(..) |
1150-
hir::ItemStatic(..) | hir::ItemConst(..) |
1151-
hir::ItemFn(..) | hir::ItemMod(..) | hir::ItemTy(..) => {}
1126+
hir::ItemStruct(ref vdata, _) => {
1127+
for f in vdata.fields() {
1128+
check_inherited(f.span, f.node.kind.visibility());
1129+
}
1130+
}
1131+
hir::ItemDefaultImpl(..) | hir::ItemEnum(..) | hir::ItemTrait(..) |
1132+
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
1133+
hir::ItemMod(..) | hir::ItemExternCrate(..) |
1134+
hir::ItemUse(..) | hir::ItemTy(..) => {}
11521135
}
11531136
}
11541137
}
@@ -1492,6 +1475,14 @@ pub fn check_crate(tcx: &ty::ctxt,
14921475
-> (ExportedItems, PublicItems) {
14931476
let krate = tcx.map.krate();
14941477

1478+
// Sanity check to make sure that all privacy usage and controls are
1479+
// reasonable.
1480+
let mut visitor = SanePrivacyVisitor {
1481+
tcx: tcx,
1482+
in_block: false,
1483+
};
1484+
visit::walk_crate(&mut visitor, krate);
1485+
14951486
// Figure out who everyone's parent is
14961487
let mut visitor = ParentVisitor {
14971488
parents: NodeMap(),
@@ -1509,14 +1500,6 @@ pub fn check_crate(tcx: &ty::ctxt,
15091500
};
15101501
visit::walk_crate(&mut visitor, krate);
15111502

1512-
// Sanity check to make sure that all privacy usage and controls are
1513-
// reasonable.
1514-
let mut visitor = SanePrivacyVisitor {
1515-
in_fn: false,
1516-
tcx: tcx,
1517-
};
1518-
visit::walk_crate(&mut visitor, krate);
1519-
15201503
tcx.sess.abort_if_errors();
15211504

15221505
// Build up a set of all exported items in the AST. This is a set of all
+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(associated_consts)]
12+
#![feature(optin_builtin_traits)]
13+
14+
trait MarkerTr {}
15+
pub trait Tr {
16+
fn f();
17+
const C: u8;
18+
type T;
19+
}
20+
pub struct S {
21+
pub a: u8
22+
}
23+
struct Ts(pub u8);
24+
25+
pub impl MarkerTr for .. {} //~ ERROR unnecessary visibility qualifier
26+
pub impl Tr for S { //~ ERROR unnecessary visibility qualifier
27+
pub fn f() {} //~ ERROR unnecessary visibility qualifier
28+
pub const C: u8 = 0; //~ ERROR unnecessary visibility qualifier
29+
pub type T = u8; //~ ERROR unnecessary visibility qualifier
30+
}
31+
pub impl S { //~ ERROR unnecessary visibility qualifier
32+
pub fn f() {}
33+
pub const C: u8 = 0;
34+
// pub type T = u8;
35+
}
36+
pub extern "C" { //~ ERROR unnecessary visibility qualifier
37+
pub fn f();
38+
pub static St: u8;
39+
}
40+
41+
const MAIN: u8 = {
42+
trait MarkerTr {}
43+
pub trait Tr { //~ ERROR visibility has no effect inside functions or block
44+
fn f();
45+
const C: u8;
46+
type T;
47+
}
48+
pub struct S { //~ ERROR visibility has no effect inside functions or block
49+
pub a: u8 //~ ERROR visibility has no effect inside functions or block
50+
}
51+
struct Ts(pub u8); //~ ERROR visibility has no effect inside functions or block
52+
53+
pub impl MarkerTr for .. {} //~ ERROR unnecessary visibility qualifier
54+
//~^ ERROR visibility has no effect inside functions or block
55+
pub impl Tr for S { //~ ERROR unnecessary visibility qualifier
56+
//~^ ERROR visibility has no effect inside functions or block
57+
pub fn f() {} //~ ERROR unnecessary visibility qualifier
58+
//~^ ERROR visibility has no effect inside functions or block
59+
pub const C: u8 = 0; //~ ERROR unnecessary visibility qualifier
60+
//~^ ERROR visibility has no effect inside functions or block
61+
pub type T = u8; //~ ERROR unnecessary visibility qualifier
62+
//~^ ERROR visibility has no effect inside functions or block
63+
}
64+
pub impl S { //~ ERROR unnecessary visibility qualifier
65+
//~^ ERROR visibility has no effect inside functions or block
66+
pub fn f() {} //~ ERROR visibility has no effect inside functions or block
67+
pub const C: u8 = 0; //~ ERROR visibility has no effect inside functions or block
68+
// pub type T = u8; // ERROR visibility has no effect inside functions or block
69+
}
70+
pub extern "C" { //~ ERROR unnecessary visibility qualifier
71+
//~^ ERROR visibility has no effect inside functions or block
72+
pub fn f(); //~ ERROR visibility has no effect inside functions or block
73+
pub static St: u8; //~ ERROR visibility has no effect inside functions or block
74+
}
75+
76+
0
77+
};
78+
79+
fn main() {
80+
trait MarkerTr {}
81+
pub trait Tr { //~ ERROR visibility has no effect inside functions or block
82+
fn f();
83+
const C: u8;
84+
type T;
85+
}
86+
pub struct S { //~ ERROR visibility has no effect inside functions or block
87+
pub a: u8 //~ ERROR visibility has no effect inside functions or block
88+
}
89+
struct Ts(pub u8); //~ ERROR visibility has no effect inside functions or block
90+
91+
pub impl MarkerTr for .. {} //~ ERROR unnecessary visibility qualifier
92+
//~^ ERROR visibility has no effect inside functions or block
93+
pub impl Tr for S { //~ ERROR unnecessary visibility qualifier
94+
//~^ ERROR visibility has no effect inside functions or block
95+
pub fn f() {} //~ ERROR unnecessary visibility qualifier
96+
//~^ ERROR visibility has no effect inside functions or block
97+
pub const C: u8 = 0; //~ ERROR unnecessary visibility qualifier
98+
//~^ ERROR visibility has no effect inside functions or block
99+
pub type T = u8; //~ ERROR unnecessary visibility qualifier
100+
//~^ ERROR visibility has no effect inside functions or block
101+
}
102+
pub impl S { //~ ERROR unnecessary visibility qualifier
103+
//~^ ERROR visibility has no effect inside functions or block
104+
pub fn f() {} //~ ERROR visibility has no effect inside functions or block
105+
pub const C: u8 = 0; //~ ERROR visibility has no effect inside functions or block
106+
// pub type T = u8; // ERROR visibility has no effect inside functions or block
107+
}
108+
pub extern "C" { //~ ERROR unnecessary visibility qualifier
109+
//~^ ERROR visibility has no effect inside functions or block
110+
pub fn f(); //~ ERROR visibility has no effect inside functions or block
111+
pub static St: u8; //~ ERROR visibility has no effect inside functions or block
112+
}
113+
}

src/test/run-pass/const-block-item.rs

-6
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@ static BLOCK_USE: usize = {
2020
100
2121
};
2222

23-
static BLOCK_PUB_USE: usize = {
24-
pub use foo::Value;
25-
200
26-
};
27-
2823
static BLOCK_STRUCT_DEF: usize = {
2924
struct Foo {
3025
a: usize
@@ -48,7 +43,6 @@ static BLOCK_MACRO_RULES: usize = {
4843

4944
pub fn main() {
5045
assert_eq!(BLOCK_USE, 100);
51-
assert_eq!(BLOCK_PUB_USE, 200);
5246
assert_eq!(BLOCK_STRUCT_DEF, 300);
5347
assert_eq!(BLOCK_FN_DEF(390), 400);
5448
assert_eq!(BLOCK_MACRO_RULES, 412);

0 commit comments

Comments
 (0)