From f7321becd23a07f83fee52b8b244367270290530 Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 29 May 2025 15:08:24 -0500 Subject: [PATCH 1/2] rustdoc: add regression test for issue 135092 --- src/librustdoc/clean/mod.rs | 4 ++-- tests/rustdoc/reexport/extern-135092.rs | 26 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 tests/rustdoc/reexport/extern-135092.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d77bdf09d010a..d44fc0c18594b 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -89,7 +89,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< Some(item) })); - // Split up imports from all other items. + // Split up glob imports from all other items. // // This covers the case where somebody does an import which should pull in an item, // but there's already an item with the same namespace and same name. Rust gives @@ -2761,7 +2761,6 @@ fn clean_maybe_renamed_item<'tcx>( import_id: Option, ) -> Vec { use hir::ItemKind; - fn get_name( cx: &DocContext<'_>, item: &hir::Item<'_>, @@ -2973,6 +2972,7 @@ fn clean_extern_crate<'tcx>( && !cx.is_json_output(); let krate_owner_def_id = krate.owner_id.def_id; + if please_inline && let Some(items) = inline::try_inline( cx, diff --git a/tests/rustdoc/reexport/extern-135092.rs b/tests/rustdoc/reexport/extern-135092.rs new file mode 100644 index 0000000000000..fb5c71d56d595 --- /dev/null +++ b/tests/rustdoc/reexport/extern-135092.rs @@ -0,0 +1,26 @@ +// Test to make sure reexports of extern items are combined +// + +#![crate_name = "foo"] + +mod native { + extern "C" { + /// bar. + pub fn bar(); + } + + /// baz. + pub fn baz() {} +} + +//@ has 'foo/fn.bar.html' +//@ has - '//div[@class="docblock"]' 'bar.' +//@ has - '//div[@class="docblock"]' 'foo' +/// foo +pub use native::bar; + +//@ has 'foo/fn.baz.html' +//@ has - '//div[@class="docblock"]' 'baz.' +//@ has - '//div[@class="docblock"]' 'foo' +/// foo +pub use native::baz; From 3ed1c87ec159c0b993b45c8f3cfc8c1fe7552e84 Mon Sep 17 00:00:00 2001 From: binarycat Date: Sat, 31 May 2025 14:45:57 -0500 Subject: [PATCH 2/2] rustdoc: fix attrs of locally reexported foreign items --- src/librustdoc/clean/mod.rs | 15 +++++++++------ src/librustdoc/visit_ast.rs | 20 +++++++++++++++----- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index d44fc0c18594b..2b0a68c6204e0 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -66,8 +66,8 @@ use crate::visit_ast::Module as DocModule; pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item { let mut items: Vec = vec![]; let mut inserted = FxHashSet::default(); - items.extend(doc.foreigns.iter().map(|(item, renamed)| { - let item = clean_maybe_renamed_foreign_item(cx, item, *renamed); + items.extend(doc.foreigns.iter().map(|(item, renamed, import_id)| { + let item = clean_maybe_renamed_foreign_item(cx, item, *renamed, *import_id); if let Some(name) = item.name && (cx.render_options.document_hidden || !item.is_doc_hidden()) { @@ -3134,6 +3134,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( cx: &mut DocContext<'tcx>, item: &hir::ForeignItem<'tcx>, renamed: Option, + import_id: Option, ) -> Item { let def_id = item.owner_id.to_def_id(); cx.with_param_env(def_id, |cx| { @@ -3149,11 +3150,13 @@ fn clean_maybe_renamed_foreign_item<'tcx>( hir::ForeignItemKind::Type => ForeignTypeItem, }; - Item::from_def_id_and_parts( - item.owner_id.def_id.to_def_id(), - Some(renamed.unwrap_or(item.ident.name)), - kind, + generate_item_with_correct_attrs( cx, + kind, + item.owner_id.def_id.to_def_id(), + item.ident.name, + import_id, + renamed, ) }) } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 5b52e785b8f59..2889bfae7b000 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -38,9 +38,18 @@ pub(crate) struct Module<'hir> { (LocalDefId, Option), (&'hir hir::Item<'hir>, Option, Option), >, - /// Same as for `items`. + + /// (def_id, renamed) -> (res, local_import_id) + /// + /// `inlined_foreigns` only contains `extern` items + /// that are cross-crate inlined. + /// + /// Locally inlined `extern` items are + /// stored in `foreigns` with the `import_id` set, + /// analogous to how `items` is. pub(crate) inlined_foreigns: FxIndexMap<(DefId, Option), (Res, LocalDefId)>, - pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option)>, + /// (item, renamed, import_id) + pub(crate) foreigns: Vec<(&'hir hir::ForeignItem<'hir>, Option, Option)>, } impl Module<'_> { @@ -327,7 +336,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } Node::ForeignItem(it) if !glob => { let prev = mem::replace(&mut self.inlining, true); - self.visit_foreign_item_inner(it, renamed); + self.visit_foreign_item_inner(it, renamed, Some(def_id)); self.inlining = prev; true } @@ -432,7 +441,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { hir::ItemKind::ForeignMod { items, .. } => { for item in items { let item = tcx.hir_foreign_item(item.id); - self.visit_foreign_item_inner(item, None); + self.visit_foreign_item_inner(item, None, None); } } // If we're inlining, skip private items. @@ -527,10 +536,11 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &mut self, item: &'tcx hir::ForeignItem<'_>, renamed: Option, + import_id: Option, ) { // If inlining we only want to include public functions. if !self.inlining || self.cx.tcx.visibility(item.owner_id).is_public() { - self.modules.last_mut().unwrap().foreigns.push((item, renamed)); + self.modules.last_mut().unwrap().foreigns.push((item, renamed, import_id)); } }