Skip to content

Commit a9430a3

Browse files
committed
Auto merge of #31641 - petrochenkov:reach, r=alexcrichton
Fixes #16734 and probably some other issues This is a continuation of #29822, but the algorithm is mostly a copy of #29973, so r? @alexcrichton or @nikomatsakis
2 parents e18f7a1 + fadc95e commit a9430a3

File tree

4 files changed

+316
-11
lines changed

4 files changed

+316
-11
lines changed

src/librustc_privacy/lib.rs

+134-11
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@ struct EmbargoVisitor<'a, 'tcx: 'a> {
169169
changed: bool,
170170
}
171171

172+
struct ReachEverythingInTheInterfaceVisitor<'b, 'a: 'b, 'tcx: 'a> {
173+
ev: &'b mut EmbargoVisitor<'a, 'tcx>,
174+
}
175+
172176
impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
173177
fn ty_level(&self, ty: &hir::Ty) -> Option<AccessLevel> {
174178
if let hir::TyPath(..) = ty.node {
@@ -214,6 +218,10 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
214218
old_level
215219
}
216220
}
221+
222+
fn reach<'b>(&'b mut self) -> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
223+
ReachEverythingInTheInterfaceVisitor { ev: self }
224+
}
217225
}
218226

219227
impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
@@ -245,10 +253,10 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
245253
}
246254
};
247255

248-
// Update id of the item itself
256+
// Update level of the item itself
249257
let item_level = self.update(item.id, inherited_item_level);
250258

251-
// Update ids of nested things
259+
// Update levels of nested things
252260
match item.node {
253261
hir::ItemEnum(ref def, _) => {
254262
for variant in &def.variants {
@@ -292,19 +300,72 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
292300
}
293301
}
294302
}
295-
hir::ItemTy(ref ty, _) if item_level.is_some() => {
296-
if let hir::TyPath(..) = ty.node {
297-
match self.tcx.def_map.borrow().get(&ty.id).unwrap().full_def() {
298-
Def::PrimTy(..) | Def::SelfTy(..) | Def::TyParam(..) => {},
299-
def => {
300-
if let Some(node_id) = self.tcx.map.as_local_node_id(def.def_id()) {
301-
self.update(node_id, Some(AccessLevel::Reachable));
302-
}
303+
_ => {}
304+
}
305+
306+
// Mark all items in interfaces of reachable items as reachable
307+
match item.node {
308+
// The interface is empty
309+
hir::ItemExternCrate(..) => {}
310+
// All nested items are checked by visit_item
311+
hir::ItemMod(..) => {}
312+
// Reexports are handled in visit_mod
313+
hir::ItemUse(..) => {}
314+
// Visit everything
315+
hir::ItemConst(..) | hir::ItemStatic(..) | hir::ItemFn(..) |
316+
hir::ItemTrait(..) | hir::ItemTy(..) | hir::ItemImpl(_, _, _, Some(..), _, _) => {
317+
if item_level.is_some() {
318+
self.reach().visit_item(item);
319+
}
320+
}
321+
// Visit everything, but enum variants have their own levels
322+
hir::ItemEnum(ref def, ref generics) => {
323+
if item_level.is_some() {
324+
self.reach().visit_generics(generics);
325+
}
326+
for variant in &def.variants {
327+
if self.get(variant.node.data.id()).is_some() {
328+
for field in variant.node.data.fields() {
329+
self.reach().visit_struct_field(field);
330+
}
331+
// Corner case: if the variant is reachable, but its
332+
// enum is not, make the enum reachable as well.
333+
self.update(item.id, Some(AccessLevel::Reachable));
334+
}
335+
}
336+
}
337+
// Visit everything, but foreign items have their own levels
338+
hir::ItemForeignMod(ref foreign_mod) => {
339+
for foreign_item in &foreign_mod.items {
340+
if self.get(foreign_item.id).is_some() {
341+
self.reach().visit_foreign_item(foreign_item);
342+
}
343+
}
344+
}
345+
// Visit everything except for private fields
346+
hir::ItemStruct(ref struct_def, ref generics) => {
347+
if item_level.is_some() {
348+
self.reach().visit_generics(generics);
349+
for field in struct_def.fields() {
350+
if self.get(field.node.id).is_some() {
351+
self.reach().visit_struct_field(field);
352+
}
353+
}
354+
}
355+
}
356+
// The interface is empty
357+
hir::ItemDefaultImpl(..) => {}
358+
// Visit everything except for private impl items
359+
hir::ItemImpl(_, _, ref generics, None, _, ref impl_items) => {
360+
if item_level.is_some() {
361+
self.reach().visit_generics(generics);
362+
for impl_item in impl_items {
363+
if self.get(impl_item.id).is_some() {
364+
self.reach().visit_impl_item(impl_item);
303365
}
304366
}
305367
}
306368
}
307-
_ => {}
308369
}
309370

310371
let orig_level = self.prev_level;
@@ -347,6 +408,68 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> {
347408
}
348409
}
349410

411+
impl<'b, 'a, 'tcx: 'a> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
412+
// Make the type hidden under a type alias reachable
413+
fn reach_aliased_type(&mut self, item: &hir::Item, path: &hir::Path) {
414+
if let hir::ItemTy(ref ty, ref generics) = item.node {
415+
// See `fn is_public_type_alias` for details
416+
self.visit_ty(ty);
417+
let provided_params = path.segments.last().unwrap().parameters.types().len();
418+
for ty_param in &generics.ty_params[provided_params..] {
419+
if let Some(ref default_ty) = ty_param.default {
420+
self.visit_ty(default_ty);
421+
}
422+
}
423+
}
424+
}
425+
}
426+
427+
impl<'b, 'a, 'tcx: 'a, 'v> Visitor<'v> for ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
428+
fn visit_ty(&mut self, ty: &hir::Ty) {
429+
if let hir::TyPath(_, ref path) = ty.node {
430+
let def = self.ev.tcx.def_map.borrow().get(&ty.id).unwrap().full_def();
431+
match def {
432+
Def::Struct(def_id) | Def::Enum(def_id) | Def::TyAlias(def_id) |
433+
Def::Trait(def_id) | Def::AssociatedTy(def_id, _) => {
434+
if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
435+
let item = self.ev.tcx.map.expect_item(node_id);
436+
if let Def::TyAlias(..) = def {
437+
// Type aliases are substituted. Associated type aliases are not
438+
// substituted yet, but ideally they should be.
439+
if self.ev.get(item.id).is_none() {
440+
self.reach_aliased_type(item, path);
441+
}
442+
} else {
443+
self.ev.update(item.id, Some(AccessLevel::Reachable));
444+
}
445+
}
446+
}
447+
448+
_ => {}
449+
}
450+
}
451+
452+
intravisit::walk_ty(self, ty);
453+
}
454+
455+
fn visit_trait_ref(&mut self, trait_ref: &hir::TraitRef) {
456+
let def_id = self.ev.tcx.trait_ref_to_def_id(trait_ref);
457+
if let Some(node_id) = self.ev.tcx.map.as_local_node_id(def_id) {
458+
let item = self.ev.tcx.map.expect_item(node_id);
459+
self.ev.update(item.id, Some(AccessLevel::Reachable));
460+
}
461+
462+
intravisit::walk_trait_ref(self, trait_ref);
463+
}
464+
465+
// Don't recurse into function bodies
466+
fn visit_block(&mut self, _: &hir::Block) {}
467+
// Don't recurse into expressions in array sizes or const initializers
468+
fn visit_expr(&mut self, _: &hir::Expr) {}
469+
// Don't recurse into patterns in function arguments
470+
fn visit_pat(&mut self, _: &hir::Pat) {}
471+
}
472+
350473
////////////////////////////////////////////////////////////////////////////////
351474
/// The privacy visitor, where privacy checks take place (violations reported)
352475
////////////////////////////////////////////////////////////////////////////////
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2016 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+
use inner_private_module::*;
12+
13+
mod inner_private_module {
14+
pub struct Unnameable1;
15+
pub struct Unnameable2;
16+
#[derive(Clone, Copy)]
17+
pub struct Unnameable3;
18+
pub struct Unnameable4;
19+
pub struct Unnameable5;
20+
pub struct Unnameable6;
21+
pub struct Unnameable7;
22+
#[derive(Default)]
23+
pub struct Unnameable8;
24+
pub enum UnnameableEnum {
25+
NameableVariant
26+
}
27+
pub trait UnnameableTrait {
28+
type Alias: Default;
29+
}
30+
31+
impl Unnameable1 {
32+
pub fn method_of_unnameable_type1(&self) -> &'static str {
33+
"Hello1"
34+
}
35+
}
36+
impl Unnameable2 {
37+
pub fn method_of_unnameable_type2(&self) -> &'static str {
38+
"Hello2"
39+
}
40+
}
41+
impl Unnameable3 {
42+
pub fn method_of_unnameable_type3(&self) -> &'static str {
43+
"Hello3"
44+
}
45+
}
46+
impl Unnameable4 {
47+
pub fn method_of_unnameable_type4(&self) -> &'static str {
48+
"Hello4"
49+
}
50+
}
51+
impl Unnameable5 {
52+
pub fn method_of_unnameable_type5(&self) -> &'static str {
53+
"Hello5"
54+
}
55+
}
56+
impl Unnameable6 {
57+
pub fn method_of_unnameable_type6(&self) -> &'static str {
58+
"Hello6"
59+
}
60+
}
61+
impl Unnameable7 {
62+
pub fn method_of_unnameable_type7(&self) -> &'static str {
63+
"Hello7"
64+
}
65+
}
66+
impl Unnameable8 {
67+
pub fn method_of_unnameable_type8(&self) -> &'static str {
68+
"Hello8"
69+
}
70+
}
71+
impl UnnameableEnum {
72+
pub fn method_of_unnameable_enum(&self) -> &'static str {
73+
"HelloEnum"
74+
}
75+
}
76+
}
77+
78+
pub fn function_returning_unnameable_type() -> Unnameable1 {
79+
Unnameable1
80+
}
81+
82+
pub const CONSTANT_OF_UNNAMEABLE_TYPE: Unnameable2 =
83+
Unnameable2;
84+
85+
pub fn function_accepting_unnameable_type(_: Option<Unnameable3>) {}
86+
87+
pub type AliasOfUnnameableType = Unnameable4;
88+
89+
impl Unnameable1 {
90+
pub fn inherent_method_returning_unnameable_type(&self) -> Unnameable5 {
91+
Unnameable5
92+
}
93+
}
94+
95+
pub trait Tr {
96+
fn trait_method_returning_unnameable_type(&self) -> Unnameable6 {
97+
Unnameable6
98+
}
99+
}
100+
impl Tr for Unnameable1 {}
101+
102+
pub use inner_private_module::UnnameableEnum::NameableVariant;
103+
104+
pub struct Struct {
105+
pub field_of_unnameable_type: Unnameable7
106+
}
107+
108+
pub static STATIC: Struct = Struct { field_of_unnameable_type: Unnameable7 } ;
109+
110+
impl UnnameableTrait for AliasOfUnnameableType {
111+
type Alias = Unnameable8;
112+
}
113+
114+
pub fn generic_function<T: UnnameableTrait>() -> T::Alias {
115+
Default::default()
116+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2016 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+
// aux-build:reachable-unnameable-items.rs
12+
13+
#![feature(braced_empty_structs)]
14+
#![feature(recover)]
15+
16+
extern crate reachable_unnameable_items;
17+
use reachable_unnameable_items::*;
18+
19+
fn main() {
20+
let res1 = function_returning_unnameable_type().method_of_unnameable_type1();
21+
let res2 = CONSTANT_OF_UNNAMEABLE_TYPE.method_of_unnameable_type2();
22+
let res4 = AliasOfUnnameableType{}.method_of_unnameable_type4();
23+
let res5 = function_returning_unnameable_type().inherent_method_returning_unnameable_type().
24+
method_of_unnameable_type5();
25+
let res6 = function_returning_unnameable_type().trait_method_returning_unnameable_type().
26+
method_of_unnameable_type6();
27+
let res7 = STATIC.field_of_unnameable_type.method_of_unnameable_type7();
28+
let res8 = generic_function::<AliasOfUnnameableType>().method_of_unnameable_type8();
29+
let res_enum = NameableVariant.method_of_unnameable_enum();
30+
assert_eq!(res1, "Hello1");
31+
assert_eq!(res2, "Hello2");
32+
assert_eq!(res4, "Hello4");
33+
assert_eq!(res5, "Hello5");
34+
assert_eq!(res6, "Hello6");
35+
assert_eq!(res7, "Hello7");
36+
assert_eq!(res8, "Hello8");
37+
assert_eq!(res_enum, "HelloEnum");
38+
39+
let none = None;
40+
function_accepting_unnameable_type(none);
41+
let _guard = std::panic::recover(|| none.unwrap().method_of_unnameable_type3());
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2016 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(staged_api)]
12+
#![stable(feature = "a", since = "b")]
13+
14+
mod inner_private_module {
15+
// UnnameableTypeAlias isn't marked as reachable, so no stability annotation is required here
16+
pub type UnnameableTypeAlias = u8;
17+
}
18+
19+
#[stable(feature = "a", since = "b")]
20+
pub fn f() -> inner_private_module::UnnameableTypeAlias {
21+
0
22+
}
23+
24+
fn main() {}

0 commit comments

Comments
 (0)