diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 5ac68da150a..071a85f4da6 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -10,6 +10,7 @@ use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; @@ -87,6 +88,7 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> { inside_public_path: bool, exact_paths: DefIdMap>, modules: Vec>, + is_importable_from_parent: bool, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { @@ -107,6 +109,7 @@ pub(crate) fn new(cx: &'a mut core::DocContext<'tcx>) -> RustdocVisitor<'a, 'tcx inside_public_path: true, exact_paths: Default::default(), modules: vec![om], + is_importable_from_parent: true, } } @@ -319,11 +322,23 @@ fn add_to_current_mod( renamed: Option, parent_id: Option, ) { - self.modules - .last_mut() - .unwrap() - .items - .insert((item.owner_id.def_id, renamed), (item, renamed, parent_id)); + if self.is_importable_from_parent + // If we're inside an item, only impl blocks and `macro_rules!` with the `macro_export` + // attribute can still be visible. + || match item.kind { + hir::ItemKind::Impl(..) => true, + hir::ItemKind::Macro(_, MacroKind::Bang) => { + self.cx.tcx.has_attr(item.owner_id.def_id, sym::macro_export) + } + _ => false, + } + { + self.modules + .last_mut() + .unwrap() + .items + .insert((item.owner_id.def_id, renamed), (item, renamed, parent_id)); + } } fn visit_item_inner( @@ -485,7 +500,22 @@ fn nested_visit_map(&mut self) -> Self::Map { fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { self.visit_item_inner(i, None, None); + let new_value = if self.is_importable_from_parent { + matches!( + i.kind, + hir::ItemKind::Mod(..) + | hir::ItemKind::ForeignMod { .. } + | hir::ItemKind::Impl(..) + | hir::ItemKind::Trait(..) + ) + } else { + // Whatever the context, if it's an impl block, the items inside it can be used so they + // should be visible. + matches!(i.kind, hir::ItemKind::Impl(..)) + }; + let prev = mem::replace(&mut self.is_importable_from_parent, new_value); walk_item(self, i); + self.is_importable_from_parent = prev; } fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: hir::HirId) {