Skip to content

Commit 0b96be7

Browse files
authored
Rollup merge of #96536 - rust-lang:notriddle/deref-slice-core, r=GuillaumeGomez
rustdoc: fix missing method list for primitive deref target This change makes it so that local impls count when listing primitives that need retained. Fixes #95325
2 parents 041f3b6 + 8743ce8 commit 0b96be7

File tree

2 files changed

+72
-38
lines changed

2 files changed

+72
-38
lines changed

src/librustdoc/passes/collect_trait_impls.rs

Lines changed: 50 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,50 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
3333
coll.items
3434
};
3535

36-
let mut new_items = Vec::new();
36+
let mut new_items_external = Vec::new();
37+
let mut new_items_local = Vec::new();
3738

3839
// External trait impls.
3940
cx.with_all_trait_impls(|cx, all_trait_impls| {
4041
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls");
4142
for &impl_def_id in all_trait_impls.iter().skip_while(|def_id| def_id.is_local()) {
42-
inline::build_impl(cx, None, impl_def_id, None, &mut new_items);
43+
inline::build_impl(cx, None, impl_def_id, None, &mut new_items_external);
44+
}
45+
});
46+
47+
// Local trait impls.
48+
cx.with_all_trait_impls(|cx, all_trait_impls| {
49+
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
50+
let mut attr_buf = Vec::new();
51+
for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) {
52+
let mut parent = cx.tcx.parent(impl_def_id);
53+
while let Some(did) = parent {
54+
attr_buf.extend(
55+
cx.tcx
56+
.get_attrs(did)
57+
.iter()
58+
.filter(|attr| attr.has_name(sym::doc))
59+
.filter(|attr| {
60+
if let Some([attr]) = attr.meta_item_list().as_deref() {
61+
attr.has_name(sym::cfg)
62+
} else {
63+
false
64+
}
65+
})
66+
.cloned(),
67+
);
68+
parent = cx.tcx.parent(did);
69+
}
70+
inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items_local);
71+
attr_buf.clear();
4372
}
4473
});
4574

4675
cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| {
4776
for def_id in PrimitiveType::all_impls(cx.tcx) {
4877
// Try to inline primitive impls from other crates.
4978
if !def_id.is_local() {
50-
inline::build_impl(cx, None, def_id, None, &mut new_items);
79+
inline::build_impl(cx, None, def_id, None, &mut new_items_external);
5180
}
5281
}
5382
for (prim, did) in PrimitiveType::primitive_locations(cx.tcx) {
@@ -57,7 +86,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
5786
if did.is_local() {
5887
for def_id in prim.impls(cx.tcx) {
5988
let impls = get_auto_trait_and_blanket_impls(cx, def_id);
60-
new_items.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
89+
new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
6190
}
6291
}
6392
}
@@ -71,6 +100,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
71100
cx: &DocContext<'_>,
72101
map: &FxHashMap<DefId, &Type>,
73102
cleaner: &mut BadImplStripper<'_>,
103+
targets: &mut FxHashSet<DefId>,
74104
type_did: DefId,
75105
) {
76106
if let Some(target) = map.get(&type_did) {
@@ -79,18 +109,18 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
79109
cleaner.prims.insert(target_prim);
80110
} else if let Some(target_did) = target.def_id(&cx.cache) {
81111
// `impl Deref<Target = S> for S`
82-
if target_did == type_did {
112+
if !targets.insert(target_did) {
83113
// Avoid infinite cycles
84114
return;
85115
}
86116
cleaner.items.insert(target_did.into());
87-
add_deref_target(cx, map, cleaner, target_did);
117+
add_deref_target(cx, map, cleaner, targets, target_did);
88118
}
89119
}
90120
}
91121

92122
// scan through included items ahead of time to splice in Deref targets to the "valid" sets
93-
for it in &new_items {
123+
for it in new_items_external.iter().chain(new_items_local.iter()) {
94124
if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind {
95125
if trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait()
96126
&& cleaner.keep_impl(for_, true)
@@ -114,15 +144,24 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
114144
// `Deref` target type and the impl for type positions, this map of types is keyed by
115145
// `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly.
116146
if cleaner.keep_impl_with_def_id(for_did.into()) {
117-
add_deref_target(cx, &type_did_to_deref_target, &mut cleaner, for_did);
147+
let mut targets = FxHashSet::default();
148+
targets.insert(for_did);
149+
add_deref_target(
150+
cx,
151+
&type_did_to_deref_target,
152+
&mut cleaner,
153+
&mut targets,
154+
for_did,
155+
);
118156
}
119157
}
120158
}
121159
}
122160
}
123161
}
124162

125-
new_items.retain(|it| {
163+
// Filter out external items that are not needed
164+
new_items_external.retain(|it| {
126165
if let ImplItem(Impl { ref for_, ref trait_, ref kind, .. }) = *it.kind {
127166
cleaner.keep_impl(
128167
for_,
@@ -134,37 +173,10 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate
134173
}
135174
});
136175

137-
// Local trait impls.
138-
cx.with_all_trait_impls(|cx, all_trait_impls| {
139-
let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls");
140-
let mut attr_buf = Vec::new();
141-
for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) {
142-
let mut parent = cx.tcx.parent(impl_def_id);
143-
while let Some(did) = parent {
144-
attr_buf.extend(
145-
cx.tcx
146-
.get_attrs(did)
147-
.iter()
148-
.filter(|attr| attr.has_name(sym::doc))
149-
.filter(|attr| {
150-
if let Some([attr]) = attr.meta_item_list().as_deref() {
151-
attr.has_name(sym::cfg)
152-
} else {
153-
false
154-
}
155-
})
156-
.cloned(),
157-
);
158-
parent = cx.tcx.parent(did);
159-
}
160-
inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items);
161-
attr_buf.clear();
162-
}
163-
});
164-
165176
if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind {
166177
items.extend(synth_impls);
167-
items.extend(new_items);
178+
items.extend(new_items_external);
179+
items.extend(new_items_local);
168180
} else {
169181
panic!("collect-trait-impls can't run");
170182
};

src/test/rustdoc/deref-slice-core.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// https://github.com/rust-lang/rust/issues/95325
2+
//
3+
// Show methods reachable from Deref of primitive.
4+
#![no_std]
5+
6+
use core::ops::Deref;
7+
8+
// @has 'deref_slice_core/struct.MyArray.html'
9+
// @has '-' '//*[@id="deref-methods-%5BT%5D"]' 'Methods from Deref<Target = [T]>'
10+
// @has '-' '//*[@class="impl-items"]//*[@id="method.len"]' 'pub fn len(&self)'
11+
12+
pub struct MyArray<T> {
13+
array: [T; 10],
14+
}
15+
16+
impl<T> Deref for MyArray<T> {
17+
type Target = [T];
18+
19+
fn deref(&self) -> &Self::Target {
20+
&self.array
21+
}
22+
}

0 commit comments

Comments
 (0)