diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 6962b5c7ee302..9644e3d15fdfa 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -33,13 +33,42 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate coll.items }; - let mut new_items = Vec::new(); + let mut new_items_external = Vec::new(); + let mut new_items_local = Vec::new(); // External trait impls. cx.with_all_trait_impls(|cx, all_trait_impls| { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_extern_trait_impls"); for &impl_def_id in all_trait_impls.iter().skip_while(|def_id| def_id.is_local()) { - inline::build_impl(cx, None, impl_def_id, None, &mut new_items); + inline::build_impl(cx, None, impl_def_id, None, &mut new_items_external); + } + }); + + // Local trait impls. + cx.with_all_trait_impls(|cx, all_trait_impls| { + let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls"); + let mut attr_buf = Vec::new(); + for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) { + let mut parent = cx.tcx.parent(impl_def_id); + while let Some(did) = parent { + attr_buf.extend( + cx.tcx + .get_attrs(did) + .iter() + .filter(|attr| attr.has_name(sym::doc)) + .filter(|attr| { + if let Some([attr]) = attr.meta_item_list().as_deref() { + attr.has_name(sym::cfg) + } else { + false + } + }) + .cloned(), + ); + parent = cx.tcx.parent(did); + } + inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items_local); + attr_buf.clear(); } }); @@ -47,7 +76,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate for def_id in PrimitiveType::all_impls(cx.tcx) { // Try to inline primitive impls from other crates. if !def_id.is_local() { - inline::build_impl(cx, None, def_id, None, &mut new_items); + inline::build_impl(cx, None, def_id, None, &mut new_items_external); } } 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 if did.is_local() { for def_id in prim.impls(cx.tcx) { let impls = get_auto_trait_and_blanket_impls(cx, def_id); - new_items.extend(impls.filter(|i| cx.inlined.insert(i.item_id))); + new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id))); } } } @@ -71,6 +100,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate cx: &DocContext<'_>, map: &FxHashMap, cleaner: &mut BadImplStripper<'_>, + targets: &mut FxHashSet, type_did: DefId, ) { if let Some(target) = map.get(&type_did) { @@ -79,18 +109,18 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate cleaner.prims.insert(target_prim); } else if let Some(target_did) = target.def_id(&cx.cache) { // `impl Deref for S` - if target_did == type_did { + if !targets.insert(target_did) { // Avoid infinite cycles return; } cleaner.items.insert(target_did.into()); - add_deref_target(cx, map, cleaner, target_did); + add_deref_target(cx, map, cleaner, targets, target_did); } } } // scan through included items ahead of time to splice in Deref targets to the "valid" sets - for it in &new_items { + for it in new_items_external.iter().chain(new_items_local.iter()) { if let ImplItem(Impl { ref for_, ref trait_, ref items, .. }) = *it.kind { if trait_.as_ref().map(|t| t.def_id()) == cx.tcx.lang_items().deref_trait() && cleaner.keep_impl(for_, true) @@ -114,7 +144,15 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate // `Deref` target type and the impl for type positions, this map of types is keyed by // `DefId` and for convenience uses a special cleaner that accepts `DefId`s directly. if cleaner.keep_impl_with_def_id(for_did.into()) { - add_deref_target(cx, &type_did_to_deref_target, &mut cleaner, for_did); + let mut targets = FxHashSet::default(); + targets.insert(for_did); + add_deref_target( + cx, + &type_did_to_deref_target, + &mut cleaner, + &mut targets, + for_did, + ); } } } @@ -122,7 +160,8 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate } } - new_items.retain(|it| { + // Filter out external items that are not needed + new_items_external.retain(|it| { if let ImplItem(Impl { ref for_, ref trait_, ref kind, .. }) = *it.kind { cleaner.keep_impl( for_, @@ -134,37 +173,10 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate } }); - // Local trait impls. - cx.with_all_trait_impls(|cx, all_trait_impls| { - let _prof_timer = cx.tcx.sess.prof.generic_activity("build_local_trait_impls"); - let mut attr_buf = Vec::new(); - for &impl_def_id in all_trait_impls.iter().take_while(|def_id| def_id.is_local()) { - let mut parent = cx.tcx.parent(impl_def_id); - while let Some(did) = parent { - attr_buf.extend( - cx.tcx - .get_attrs(did) - .iter() - .filter(|attr| attr.has_name(sym::doc)) - .filter(|attr| { - if let Some([attr]) = attr.meta_item_list().as_deref() { - attr.has_name(sym::cfg) - } else { - false - } - }) - .cloned(), - ); - parent = cx.tcx.parent(did); - } - inline::build_impl(cx, None, impl_def_id, Some(&attr_buf), &mut new_items); - attr_buf.clear(); - } - }); - if let ModuleItem(Module { items, .. }) = &mut *krate.module.kind { items.extend(synth_impls); - items.extend(new_items); + items.extend(new_items_external); + items.extend(new_items_local); } else { panic!("collect-trait-impls can't run"); }; diff --git a/src/test/rustdoc/deref-slice-core.rs b/src/test/rustdoc/deref-slice-core.rs new file mode 100644 index 0000000000000..cccf273a82028 --- /dev/null +++ b/src/test/rustdoc/deref-slice-core.rs @@ -0,0 +1,22 @@ +// https://github.com/rust-lang/rust/issues/95325 +// +// Show methods reachable from Deref of primitive. +#![no_std] + +use core::ops::Deref; + +// @has 'deref_slice_core/struct.MyArray.html' +// @has '-' '//*[@id="deref-methods-%5BT%5D"]' 'Methods from Deref' +// @has '-' '//*[@class="impl-items"]//*[@id="method.len"]' 'pub fn len(&self)' + +pub struct MyArray { + array: [T; 10], +} + +impl Deref for MyArray { + type Target = [T]; + + fn deref(&self) -> &Self::Target { + &self.array + } +}