Skip to content

Commit 42b8c77

Browse files
committed
Auto merge of #57922 - davidtwco:issue-57410, r=petrochenkov
Update visibility of intermediate use items. Fixes #57410 and fixes #53925 and fixes #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 fc6e9a2 + 7102339 commit 42b8c77

File tree

8 files changed

+107
-9
lines changed

8 files changed

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

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

src/libstd/sys/mod.rs

+2
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",
@@ -77,6 +78,7 @@ cfg_if! {
7778
if #[cfg(windows)] {
7879
// On windows we'll just be documenting what's already available
7980
#[allow(missing_docs)]
81+
#[stable(feature = "rust1", since = "1.0.0")]
8082
pub use self::ext as windows_ext;
8183
} else if #[cfg(any(target_os = "cloudabi",
8284
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)