@@ -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
442479impl < ' 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 ( ..) => {
0 commit comments