From 374f798ad2f10280f75a3561f2dc9449ccb5e5fe Mon Sep 17 00:00:00 2001
From: Guillaume Gomez <guillaume.gomez@huawei.com>
Date: Wed, 15 Feb 2023 00:00:51 +0100
Subject: [PATCH] Correctly handle reexports of `#[doc(hidden)]` is reexport
 does not use `#[doc(inline)]`

---
 src/librustdoc/clean/mod.rs          | 19 +++++++++++++++----
 tests/rustdoc/reexport-attr-merge.rs | 13 ++++++++++---
 2 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index a46e6a2ca6c..80f05863d0e 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2100,6 +2100,7 @@ fn get_all_import_attributes<'hir>(
     tcx: TyCtxt<'hir>,
     target_def_id: LocalDefId,
     attributes: &mut Vec<ast::Attribute>,
+    is_inline: bool,
 ) {
     let hir_map = tcx.hir();
     let mut visitor = OneLevelVisitor::new(hir_map, target_def_id);
@@ -2107,7 +2108,7 @@ fn get_all_import_attributes<'hir>(
     // If the item is an import and has at least a path with two parts, we go into it.
     while let hir::ItemKind::Use(path, _) = item.kind && visited.insert(item.hir_id()) {
         // We add the attributes from this import into the list.
-        add_without_unwanted_attributes(attributes, hir_map.attrs(item.hir_id()));
+        add_without_unwanted_attributes(attributes, hir_map.attrs(item.hir_id()), is_inline);
 
         let def_id = if path.segments.len() > 1 {
             match path.segments[path.segments.len() - 2].res {
@@ -2189,7 +2190,16 @@ fn filter_tokens_from_list(
 /// * `doc(inline)`
 /// * `doc(no_inline)`
 /// * `doc(hidden)`
-fn add_without_unwanted_attributes(attrs: &mut Vec<ast::Attribute>, new_attrs: &[ast::Attribute]) {
+fn add_without_unwanted_attributes(
+    attrs: &mut Vec<ast::Attribute>,
+    new_attrs: &[ast::Attribute],
+    is_inline: bool,
+) {
+    // If it's `#[doc(inline)]`, we don't want all attributes, otherwise we keep everything.
+    if !is_inline {
+        attrs.extend_from_slice(new_attrs);
+        return;
+    }
     for attr in new_attrs {
         let mut attr = attr.clone();
         match attr.kind {
@@ -2321,9 +2331,10 @@ fn clean_maybe_renamed_item<'tcx>(
         {
             // First, we add the attributes from the current import.
             extra_attrs.extend_from_slice(inline::load_attrs(cx, import_id.to_def_id()));
+            let is_inline = extra_attrs.lists(sym::doc).get_word_attr(sym::inline).is_some();
             // Then we get all the various imports' attributes.
-            get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs);
-            add_without_unwanted_attributes(&mut extra_attrs, inline::load_attrs(cx, def_id));
+            get_all_import_attributes(use_node, cx.tcx, item.owner_id.def_id, &mut extra_attrs, is_inline);
+            add_without_unwanted_attributes(&mut extra_attrs, inline::load_attrs(cx, def_id), is_inline);
         } else {
             // We only keep the item's attributes.
             extra_attrs.extend_from_slice(inline::load_attrs(cx, def_id));
diff --git a/tests/rustdoc/reexport-attr-merge.rs b/tests/rustdoc/reexport-attr-merge.rs
index f1aee08c9c0..f6c23a1365f 100644
--- a/tests/rustdoc/reexport-attr-merge.rs
+++ b/tests/rustdoc/reexport-attr-merge.rs
@@ -1,5 +1,6 @@
 // Regression test for <https://github.com/rust-lang/rust/issues/59368>.
-// The goal is to ensure that `doc(hidden)`, `doc(inline)` and `doc(no_inline`)
+// The goal is to ensure that `doc(hidden)`, `doc(inline)` and `doc(no_inline)`
+// are not copied from an item when inlined.
 
 #![crate_name = "foo"]
 #![feature(doc_cfg)]
@@ -15,8 +16,9 @@ pub use Foo as Foo1;
 #[doc(hidden, inline)]
 pub use Foo1 as Foo2;
 
-// First we ensure that none of the other items are generated.
-// @count - '//a[@class="struct"]' 1
+// First we ensure that only the reexport `Bar2` and the inlined struct `Bar`
+// are inlined.
+// @count - '//a[@class="struct"]' 2
 // Then we check that both `cfg` are displayed.
 // @has - '//*[@class="stab portability"]' 'foo'
 // @has - '//*[@class="stab portability"]' 'bar'
@@ -24,3 +26,8 @@ pub use Foo1 as Foo2;
 // @has - '//a[@class="struct"]' 'Bar'
 #[doc(inline)]
 pub use Foo2 as Bar;
+
+// This one should appear but `Bar2` won't be linked because there is no
+// `#[doc(inline)]`.
+// @has - '//*[@id="reexport.Bar2"]' 'pub use Foo2 as Bar2;'
+pub use Foo2 as Bar2;