Skip to content

Commit 377d5ba

Browse files
Rollup merge of #157039 - lcian:fix/glob-reexport-feature-combination, r=GuillaumeGomez
rustdoc: correctly propagate cfgs for glob reexports This fixes some cases of rustdoc not surfacing the correct required feature combination when using `#[cfg(feature = ...)]` in combination with glob reexports. See the example cases included as tests. Here's the generated HTML for those test cases before this change: <img width="150" height="115" alt="Screenshot_20260528_201140" src="https://github.com/user-attachments/assets/8d611f88-7149-49f6-8ee0-530c049ea858" /> and after: <img width="225" height="125" alt="Screenshot_20260528_201236" src="https://github.com/user-attachments/assets/85cc07c0-9a9a-455f-8ada-69d44d645516" /> My understanding is that this was basically an off-by-one type of oversight. We need to update `is_inline` before calling `get_all_import_attributes` to immediately reflect that the outermost import we're processing shall indeed be considered as inline, as it's a glob. Otherwise, we will end up calling `add_without_unwanted_attributes` with `is_inline == false` on the "intermediate" re-export, which will skip propagating its `cfg`s. I believe this fixes #96166, even though the description there is not super clear on the exact test case they used (there's a snippet but the author says their code is actually different). Refs #43781 @rustbot label +F-doc_cfg @rustbot r? @GuillaumeGomez
2 parents a5f7457 + 1f5a5a2 commit 377d5ba

2 files changed

Lines changed: 68 additions & 1 deletion

File tree

src/librustdoc/clean/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,8 @@ fn generate_item_with_correct_attrs(
243243
) || (is_glob_import(tcx, import_id)
244244
&& (cx.document_hidden() || !tcx.is_doc_hidden(def_id)))
245245
|| macro_reexport_is_inline(tcx, import_id, def_id);
246-
attrs.extend(get_all_import_attributes(cx, import_id, def_id, is_inline));
247246
is_inline = is_inline || import_is_inline;
247+
attrs.extend(get_all_import_attributes(cx, import_id, def_id, is_inline));
248248
}
249249
let keep_target_cfg = is_inline || matches!(kind, ItemKind::TypeAliasItem(..));
250250
add_without_unwanted_attributes(&mut attrs, target_attrs, keep_target_cfg, None);
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// This test ensures that `cfg`s are correctly propagated for re-export chains
2+
// where the outermost is a glob re-export.
3+
4+
#![crate_name = "foo"]
5+
#![feature(doc_cfg)]
6+
7+
//@ has 'foo/index.html'
8+
//@ count - '//*[@class="item-table"]/dt' 3
9+
10+
//@ has 'foo/index.html'
11+
//@ has - '//dt/a[@title="struct foo::A"]/../*[@class="stab portability"]' 'Non-bar and non-foo'
12+
13+
//@ has 'foo/struct.A.html'
14+
//@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
15+
// 'Available on non-crate feature bar and non-crate feature foo only.'
16+
17+
mod a {
18+
mod inner {
19+
pub struct A {}
20+
}
21+
#[cfg(not(feature = "bar"))]
22+
pub use self::inner::A;
23+
}
24+
#[cfg(not(feature = "foo"))]
25+
pub use a::*;
26+
27+
//@ has 'foo/index.html'
28+
//@ has - '//dt/a[@title="struct foo::B"]/../*[@class="stab portability"]' 'Non-bar and non-baz and non-foo'
29+
30+
//@ has 'foo/struct.B.html'
31+
//@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
32+
// 'Available on non-crate feature bar and non-crate feature baz and non-crate feature foo only.'
33+
34+
mod b {
35+
mod inner {
36+
mod innermost {
37+
pub struct B {}
38+
}
39+
#[cfg(not(feature = "baz"))]
40+
pub use self::innermost::B;
41+
}
42+
#[cfg(not(feature = "bar"))]
43+
pub use self::inner::*;
44+
}
45+
#[cfg(not(feature = "foo"))]
46+
pub use b::*;
47+
48+
//@ has 'foo/index.html'
49+
//@ has - '//dt/a[@title="struct foo::C"]/../*[@class="stab portability"]' 'Non-bar and non-baz and non-foo'
50+
51+
//@ has 'foo/struct.C.html'
52+
//@ has - '//*[@id="main-content"]/*[@class="item-info"]/*[@class="stab portability"]' \
53+
// 'Available on non-crate feature bar and non-crate feature baz and non-crate feature foo only.'
54+
55+
mod c {
56+
mod inner {
57+
mod innermost {
58+
#[cfg(not(feature = "baz"))]
59+
pub struct C {}
60+
}
61+
pub use self::innermost::*;
62+
}
63+
#[cfg(not(feature = "bar"))]
64+
pub use self::inner::*;
65+
}
66+
#[cfg(not(feature = "foo"))]
67+
pub use c::*;

0 commit comments

Comments
 (0)