Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/librustdoc/passes/strip_priv_imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ pub(super) fn strip_priv_imports(krate: clean::Crate, cx: &mut DocContext<'_>) -
}

let is_json_output = cx.is_json_output();
ImportStripper { tcx: cx.tcx, is_json_output, document_hidden: cx.document_hidden() }
.fold_crate(krate)
ImportStripper {
tcx: cx.tcx,
is_json_output,
document_hidden: cx.document_hidden(),
document_private: cx.document_private(),
}
.fold_crate(krate)
}
10 changes: 7 additions & 3 deletions src/librustdoc/passes/strip_private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,13 @@ pub(super) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) ->
is_json_output,
tcx: cx.tcx,
};
krate =
ImportStripper { tcx: cx.tcx, is_json_output, document_hidden: cx.document_hidden() }
.fold_crate(stripper.fold_crate(krate));
krate = ImportStripper {
tcx: cx.tcx,
is_json_output,
document_hidden: cx.document_hidden(),
document_private: cx.document_private(),
}
.fold_crate(stripper.fold_crate(krate));
}

// strip all impls referencing private items
Expand Down
2 changes: 2 additions & 0 deletions src/librustdoc/passes/stripper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ pub(crate) struct ImportStripper<'tcx> {
pub(crate) tcx: TyCtxt<'tcx>,
pub(crate) is_json_output: bool,
pub(crate) document_hidden: bool,
pub(crate) document_private: bool,
}

impl ImportStripper<'_> {
Expand All @@ -290,6 +291,7 @@ impl DocFolder for ImportStripper<'_> {
debug!("ImportStripper: stripping {:?}", i.name);
None
}
clean::ImportItem(imp) if self.document_private => Some(self.fold_item_recur(i)),
// clean::ImportItem(_) if !self.document_hidden && i.is_doc_hidden() => None,
clean::ExternCrateItem { .. } | clean::ImportItem(..)
if i.visibility(self.tcx) != Some(Visibility::Public) =>
Expand Down
12 changes: 10 additions & 2 deletions src/librustdoc/visit_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,15 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
let tcx = self.cx.tcx;

let def_id = item.owner_id.to_def_id();
let is_pub = tcx.visibility(def_id).is_public();
// Explanations: if the item is public, nothing more to check. If not, then we check if
// we're documenting private item. If we are, then we want all items, except if it's a
// `use`. In this case, we want to check if it's a reexport.
let is_pub = tcx.visibility(def_id).is_public()
|| (self.cx.document_private()
&& (!matches!(item.kind, hir::ItemKind::Use(..))
|| def_id.as_local().is_some_and(|def_id| {
tcx.visibility(def_id).is_accessible_from(CRATE_DEF_ID, tcx)
})));

if is_pub {
self.store_path(item.owner_id.to_def_id());
Expand Down Expand Up @@ -592,7 +600,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {

// If there was a private module in the current path then don't bother inlining
// anything as it will probably be stripped anyway.
if is_pub && self.inside_public_path {
if is_pub && (self.inside_public_path || self.cx.document_private()) {
let please_inline = if let Some(res_did) = res.opt_def_id()
&& matches!(tcx.def_kind(res_did), DefKind::Macro(MacroKinds::BANG))
{
Expand Down
52 changes: 52 additions & 0 deletions tests/rustdoc-html/inline_local/document-private-reexports.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Test ensures that when we use the `--document-private-items` option, reexports
// work the same as for "public" items.
// Regression test for <https://github.com/rust-lang/rust/issues/159109>.

//@ compile-flags: --document-private-items

#![crate_name = "foo"]

//@ has 'foo/index.html'
// The four reexports, the `not_hidden` and `foofoo` (private) modules.
//@ count - '//*[@class="item-table"]/dt' 6
//@ has - '//*[@class="item-table"]/dt/a[@href="not_hidden/index.html"]' 'not_hidden'
//@ has - '//*[@class="item-table"]/dt/a[@href="struct.Top.html"]' 'Top'
//@ has - '//*[@class="item-table"]/dt/a[@href="struct.NotHidden.html"]' 'NotHidden'
//@ has - '//*[@class="item-table"]/dt/a[@href="struct.Hidden2.html"]' 'Hidden2'
//@ has - '//*[@class="item-table"]/dt/a[@href="struct.X.html"]' 'X'
//@ has - '//*[@class="item-table"]/dt/a[@href="foofoo/index.html"]' 'foofoo'

#[doc(hidden)]
pub(crate) struct TopHidden;

#[doc(inline)]
pub(crate) use TopHidden as Top;

#[doc(hidden)]
mod hidden {
pub(crate) struct NotHidden;
}

pub(crate) use self::hidden::NotHidden;
// Even though there is no `pub` of any kind, we display it because we're at the
// crate root.
use self::hidden::NotHidden as X;

mod not_hidden {
#[doc(hidden)]
pub(crate) struct Hidden;
}

#[doc(inline)]
pub(crate) use self::not_hidden::Hidden as Hidden2;

//@ has 'foo/foofoo/index.html'
//@ count - '//*[@class="item-table"]/dt' 1
//@ has - '//*[@class="item-table"]/dt/a[@href="struct.Something.html"]' 'Something'
mod foofoo {
// Since there is no `pub` of any kind, we don't display it, even if there is `doc(inline)`.
#[doc(inline)]
use crate::not_hidden::Hidden;
#[doc(inline)]
pub(crate) use crate::not_hidden::Hidden as Something;
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,32 @@ pub use mod1::*;
//@ has foo/index.html
//@ hasraw - "mod1"
//@ hasraw - "Mod1Public"
//@ !hasraw - "Mod1Private"
//@ !hasraw - "mod2"
//@ hasraw - "Mod1Private"

@GuillaumeGomez GuillaumeGomez Aug 19, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fun fact: this test was added in 2016 in #37773. :)

View changes since the review

//@ hasraw - "mod2"
//@ hasraw - "Mod2Public"
//@ !hasraw - "Mod2Private"
//@ hasraw - "Mod2Private"
//@ has foo/struct.Mod1Public.html
//@ !has foo/struct.Mod1Private.html
//@ has foo/struct.Mod1Private.html
//@ has foo/struct.Mod2Public.html
//@ !has foo/struct.Mod2Private.html
//@ has foo/struct.Mod2Private.html

//@ has foo/mod1/index.html
//@ hasraw - "mod2"
//@ hasraw - "Mod1Public"
//@ hasraw - "Mod1Private"
//@ !hasraw - "Mod2Public"
//@ !hasraw - "Mod2Private"
//@ hasraw - "Mod2Public"
//@ hasraw - "Mod2Private"
//@ has foo/mod1/struct.Mod1Public.html
//@ has foo/mod1/struct.Mod1Private.html
//@ !has foo/mod1/struct.Mod2Public.html
//@ !has foo/mod1/struct.Mod2Private.html
//@ has foo/mod1/struct.Mod2Public.html
//@ has foo/mod1/struct.Mod2Private.html

//@ has foo/mod1/mod2/index.html
//@ hasraw - "Mod2Public"
//@ hasraw - "Mod2Private"
//@ has foo/mod1/mod2/struct.Mod2Public.html
//@ has foo/mod1/mod2/struct.Mod2Private.html

//@ !has foo/mod2/index.html
//@ !has foo/mod2/struct.Mod2Public.html
//@ !has foo/mod2/struct.Mod2Private.html
//@ has foo/mod2/index.html
//@ has foo/mod2/struct.Mod2Public.html
//@ has foo/mod2/struct.Mod2Private.html
Loading