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