Skip to content

Commit ae34f21

Browse files
authored
Rollup merge of rust-lang#57922 - davidtwco:issue-57410, r=petrochenkov
Update visibility of intermediate use items. Fixes rust-lang#57410 and fixes rust-lang#53925 and fixes rust-lang#47816. Currently, the target of a use statement will be updated with the visibility of the use statement itself (if the use statement was visible). This PR ensures that if the path to the target item is via another use statement then that intermediate use statement will also have the visibility updated like the target. This silences incorrect `unreachable_pub` lints with inactionable suggestions.
2 parents b194206 + ad22de4 commit ae34f21

File tree

8 files changed

+106
-9
lines changed

8 files changed

+106
-9
lines changed

src/libcore/iter/adapters/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod flatten;
1111
mod zip;
1212

1313
pub use self::chain::Chain;
14+
#[stable(feature = "rust1", since = "1.0.0")]
1415
pub use self::flatten::{FlatMap, Flatten};
1516
pub use self::zip::Zip;
1617
pub(crate) use self::zip::TrustedRandomAccess;

src/libcore/iter/traits/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ mod collect;
55
mod accum;
66
mod marker;
77

8+
#[stable(feature = "rust1", since = "1.0.0")]
89
pub use self::iterator::Iterator;
910
pub use self::double_ended::DoubleEndedIterator;
1011
pub use self::exact_size::ExactSizeIterator;
1112
pub use self::collect::{FromIterator, IntoIterator, Extend};
1213
pub use self::accum::{Sum, Product};
14+
#[stable(feature = "rust1", since = "1.0.0")]
1315
pub use self::marker::{FusedIterator, TrustedLen};

src/librustc/hir/def.rs

+10
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,14 @@ impl NonMacroAttrKind {
252252
}
253253

254254
impl Def {
255+
/// Return the `DefId` of this `Def` if it has an id, else panic.
255256
pub fn def_id(&self) -> DefId {
256257
self.opt_def_id().unwrap_or_else(|| {
257258
bug!("attempted .def_id() on invalid def: {:?}", self)
258259
})
259260
}
260261

262+
/// Return `Some(..)` with the `DefId` of this `Def` if it has a id, else `None`.
261263
pub fn opt_def_id(&self) -> Option<DefId> {
262264
match *self {
263265
Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) |
@@ -284,6 +286,14 @@ impl Def {
284286
}
285287
}
286288

289+
/// Return the `DefId` of this `Def` if it represents a module.
290+
pub fn mod_def_id(&self) -> Option<DefId> {
291+
match *self {
292+
Def::Mod(id) => Some(id),
293+
_ => None,
294+
}
295+
}
296+
287297
/// A human readable name for the def kind ("function", "module", etc.).
288298
pub fn kind_name(&self) -> &'static str {
289299
match *self {

src/librustc/middle/privacy.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,16 @@ use syntax::ast::NodeId;
1111
// Accessibility levels, sorted in ascending order
1212
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1313
pub enum AccessLevel {
14-
// Superset of Reachable used to mark impl Trait items.
14+
/// Superset of `AccessLevel::Reachable` used to mark impl Trait items.
1515
ReachableFromImplTrait,
16-
// Exported items + items participating in various kinds of public interfaces,
17-
// but not directly nameable. For example, if function `fn f() -> T {...}` is
18-
// public, then type `T` is reachable. Its values can be obtained by other crates
19-
// even if the type itself is not nameable.
16+
/// Exported items + items participating in various kinds of public interfaces,
17+
/// but not directly nameable. For example, if function `fn f() -> T {...}` is
18+
/// public, then type `T` is reachable. Its values can be obtained by other crates
19+
/// even if the type itself is not nameable.
2020
Reachable,
21-
// Public items + items accessible to other crates with help of `pub use` re-exports
21+
/// Public items + items accessible to other crates with help of `pub use` re-exports
2222
Exported,
23-
// Items accessible to other crates directly, without help of re-exports
23+
/// Items accessible to other crates directly, without help of re-exports
2424
Public,
2525
}
2626

@@ -31,12 +31,17 @@ pub struct AccessLevels<Id = NodeId> {
3131
}
3232

3333
impl<Id: Hash + Eq> AccessLevels<Id> {
34+
/// See `AccessLevel::Reachable`.
3435
pub fn is_reachable(&self, id: Id) -> bool {
3536
self.map.get(&id) >= Some(&AccessLevel::Reachable)
3637
}
38+
39+
/// See `AccessLevel::Exported`.
3740
pub fn is_exported(&self, id: Id) -> bool {
3841
self.map.get(&id) >= Some(&AccessLevel::Exported)
3942
}
43+
44+
/// See `AccessLevel::Public`.
4045
pub fn is_public(&self, id: Id) -> bool {
4146
self.map.get(&id) >= Some(&AccessLevel::Public)
4247
}

src/librustc_privacy/lib.rs

+45-2
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,43 @@ impl<'a, 'tcx> EmbargoVisitor<'a, 'tcx> {
436436
ev: self,
437437
}
438438
}
439+
440+
441+
/// Given the path segments of a `ItemKind::Use`, then we need
442+
/// to update the visibility of the intermediate use so that it isn't linted
443+
/// by `unreachable_pub`.
444+
///
445+
/// This isn't trivial as `path.def` has the `DefId` of the eventual target
446+
/// of the use statement not of the next intermediate use statement.
447+
///
448+
/// To do this, consider the last two segments of the path to our intermediate
449+
/// use statement. We expect the penultimate segment to be a module and the
450+
/// last segment to be the name of the item we are exporting. We can then
451+
/// look at the items contained in the module for the use statement with that
452+
/// name and update that item's visibility.
453+
///
454+
/// FIXME: This solution won't work with glob imports and doesn't respect
455+
/// namespaces. See <https://github.com/rust-lang/rust/pull/57922#discussion_r251234202>.
456+
fn update_visibility_of_intermediate_use_statements(&mut self, segments: &[hir::PathSegment]) {
457+
if let Some([module, segment]) = segments.rchunks_exact(2).next() {
458+
if let Some(item) = module.def
459+
.and_then(|def| def.mod_def_id())
460+
.and_then(|def_id| self.tcx.hir().as_local_node_id(def_id))
461+
.map(|module_node_id| self.tcx.hir().expect_item(module_node_id))
462+
{
463+
if let hir::ItemKind::Mod(m) = &item.node {
464+
for item_id in m.item_ids.as_ref() {
465+
let item = self.tcx.hir().expect_item(item_id.id);
466+
let def_id = self.tcx.hir().local_def_id(item_id.id);
467+
if !self.tcx.hygienic_eq(segment.ident, item.ident, def_id) { continue; }
468+
if let hir::ItemKind::Use(..) = item.node {
469+
self.update(item.id, Some(AccessLevel::Exported));
470+
}
471+
}
472+
}
473+
}
474+
}
475+
}
439476
}
440477

441478
impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
@@ -522,8 +559,14 @@ impl<'a, 'tcx> Visitor<'tcx> for EmbargoVisitor<'a, 'tcx> {
522559
hir::ItemKind::ExternCrate(..) => {}
523560
// All nested items are checked by `visit_item`.
524561
hir::ItemKind::Mod(..) => {}
525-
// Re-exports are handled in `visit_mod`.
526-
hir::ItemKind::Use(..) => {}
562+
// Re-exports are handled in `visit_mod`. However, in order to avoid looping over
563+
// all of the items of a mod in `visit_mod` looking for use statements, we handle
564+
// making sure that intermediate use statements have their visibilities updated here.
565+
hir::ItemKind::Use(ref path, _) => {
566+
if item_level.is_some() {
567+
self.update_visibility_of_intermediate_use_statements(path.segments.as_ref());
568+
}
569+
}
527570
// The interface is empty.
528571
hir::ItemKind::GlobalAsm(..) => {}
529572
hir::ItemKind::Existential(..) => {

src/libstd/sys/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ cfg_if! {
5454
cfg_if! {
5555
if #[cfg(any(unix, target_os = "redox"))] {
5656
// On unix we'll document what's already available
57+
#[stable(feature = "rust1", since = "1.0.0")]
5758
pub use self::ext as unix_ext;
5859
} else if #[cfg(any(target_os = "cloudabi",
5960
target_arch = "wasm32",

src/test/ui/issues/issue-57410-1.rs

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// compile-pass
2+
3+
// Originally from #53925.
4+
// Tests that the `unreachable_pub` lint doesn't fire for `pub self::bar::Bar`.
5+
6+
#![deny(unreachable_pub)]
7+
8+
mod foo {
9+
mod bar {
10+
pub struct Bar;
11+
}
12+
13+
pub use self::bar::Bar;
14+
}
15+
16+
pub use foo::Bar;
17+
18+
fn main() {}

src/test/ui/issues/issue-57410.rs

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// compile-pass
2+
3+
// Tests that the `unreachable_pub` lint doesn't fire for `pub self::imp::f`.
4+
5+
#![deny(unreachable_pub)]
6+
7+
mod m {
8+
mod imp {
9+
pub fn f() {}
10+
}
11+
12+
pub use self::imp::f;
13+
}
14+
15+
pub use self::m::f;
16+
17+
fn main() {}

0 commit comments

Comments
 (0)