Change:
If we run with the option on this code: Both and are documented, but not being accessible outside of , it shouldn't be documented.
probably knows this, but for others seeing this issue, I think it's probably due to (which was reverted in , and later re-applied in ). It has to do with the fact that we're using a HIR visitor now, so we're visiting nested items unconditionally.
Yes I know where it's coming from. :smile: I was just thinking today that since we were going through the whole HIR without checking whether or not we were in a block, all elements inside the block could be visible. Tested and... :fearful: Should be pretty easy to fix.
For reference, I put up because this was causing documentation to become really verbose with serde + . If you fix this such that we no longer document those items, we could probably revert that PR.
Indeed. Don't hesitate to come to me if you have such issues with rustdoc. Such problems should definitely not go unnoticed.
The thing is, it was not particularly clear from the PRs whether this was intentional or not.
Unfortunately it wasn't. The goal was to retrieve the missing impl blocks. But if anything isn't clear, don't hesitate to ask too. :wink:

Discussion:
use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CRATE_DEF_ID, LOCAL_CRATE}; <ins> use rustc_span::hygiene::MacroKind; </ins> use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span;

inside_public_path: bool, exact_paths: DefIdMap<Vec<Symbol>>, modules: Vec<Module<'tcx>>, <ins> is_importable_from_parent: bool, </ins> } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {

inside_public_path: true, exact_paths: Default::default(), modules: vec![om], <ins> is_importable_from_parent: true, </ins> } }

renamed: Option<Symbol>, parent_id: Option<LocalDefId>, ) { <del> self.modules .last_mut() .unwrap() .items .insert((item.owner_id.def_id, renamed), (item, renamed, parent_id)); </del> <ins> 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)); } </ins> } fn visit_item_inner(

item: &'tcx hir::Item<'_>, renamed: Option<Symbol>, import_id: Option<LocalDefId>, <del> ) -> bool { </del> <ins> ) { </ins> debug!("visiting item {:?}", item); let name = renamed.unwrap_or(item.ident.name); let tcx = self.cx.tcx;

} } } <del> true </del> } fn visit_foreign_item_inner(

} fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { <del> if self.visit_item_inner(i, None, None) { walk_item(self, i); } </del> <ins> 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; </ins> } fn visit_mod(&mut self, _: &hir::Mod<'tcx>, _: Span, _: hir::HirId) {

<ins> // check-pass </ins> fn f() -> impl Sized { <del> enum E { //~ ERROR </del> <ins> enum E { </ins> V(E), } unimplemented!() }

<del> error[E0072]: recursive type `f::E` has infinite size --> $DIR/infinite-recursive-type-impl-trait.rs:2:5 | LL |     enum E { |     ^^^^^^ LL |         V(E), |           - recursive without indirection | help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle | LL |         V(Box<E>), |           ++++ + error: aborting due to previous error For more information about this error, try `rustc --explain E0072`. </del>

<ins> // Regression test for <https://github.com/rust-lang/rust/issues/110422>. // This test ensures that inner items (except for implementations and macros) // don't appear in documentation. // compile-flags: --document-private-items #![crate_name = "foo"] // @has 'foo/index.html' // Checking there is no "trait" entry. // @count - '//*[@id="main-content"]/*[@class="small-section-header"]' 4 // @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Structs' // @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Constants' // @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Functions' // @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Macros' // @has - '//a[@href="fn.foo.html"]' 'foo' fn foo() { fn bar() {} // @has - '//a[@class="macro"]' 'visible_macro' // @!has - '//a[@class="macro"]' 'non_visible_macro' // @has 'foo/macro.visible_macro.html' // @!has 'foo/macro.non_visible_macro.html' #[macro_export] macro_rules! visible_macro { () => {} } macro_rules! non_visible_macro { () => {} } } // @has 'foo/index.html' // @has - '//a[@href="struct.Bar.html"]' 'Bar' struct Bar; const BAR: i32 = { // @!has - '//a[@href="fn.yo.html"]' 'yo' // @!has 'foo/fn.yo.html' fn yo() {} // @!has 'foo/index.html' '//a[@href="trait.Foo.html"]' 'Foo' // @!has 'foo/trait.Foo.html' trait Foo { fn babar() {} } impl Foo for Bar {} // @has 'foo/struct.Bar.html' // @has - '//*[@id="method.foo"]/*[@class="code-header"]' 'pub(crate) fn foo()' // @count - '//*[@id="main-content"]/*[@class="small-section-header"]' 3 // We now check that the `Foo` trait is not documented nor visible on `Bar` page. // @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Implementations' // @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Auto Trait Implementations' // @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Blanket Implementations' // @!has - '//*[@href="trait.Foo.html#method.babar"]/*[@class="code-header"]' 'fn babar()' impl Bar { fn foo() {} } 1 }; </ins>