about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs31
-rw-r--r--src/test/rustdoc/primitive-slice-auto-trait.rs14
2 files changed, 43 insertions, 2 deletions
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index aa7028247be..6ea33d763b1 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -9,7 +9,7 @@ use crate::visit::DocVisitor;
 
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::DefId;
-use rustc_middle::ty::DefIdTree;
+use rustc_middle::ty::{self, DefIdTree};
 use rustc_span::symbol::sym;
 
 pub(crate) const COLLECT_TRAIT_IMPLS: Pass = Pass {
@@ -81,8 +81,35 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
             // Do not calculate blanket impl list for docs that are not going to be rendered.
             // While the `impl` blocks themselves are only in `libcore`, the module with `doc`
             // attached is directly included in `libstd` as well.
+            let tcx = cx.tcx;
             if did.is_local() {
-                for def_id in prim.impls(cx.tcx) {
+                for def_id in prim.impls(tcx).filter(|def_id| {
+                    // Avoid including impl blocks with filled-in generics.
+                    // https://github.com/rust-lang/rust/issues/94937
+                    //
+                    // FIXME(notriddle): https://github.com/rust-lang/rust/issues/97129
+                    //
+                    // This tactic of using inherent impl blocks for getting
+                    // auto traits and blanket impls is a hack. What we really
+                    // want is to check if `[T]` impls `Send`, which has
+                    // nothing to do with the inherent impl.
+                    //
+                    // Rustdoc currently uses these `impl` block as a source of
+                    // the `Ty`, as well as the `ParamEnv`, `SubstsRef`, and
+                    // `Generics`. To avoid relying on the `impl` block, these
+                    // things would need to be created from wholecloth, in a
+                    // form that is valid for use in type inference.
+                    let ty = tcx.type_of(def_id);
+                    match ty.kind() {
+                        ty::Slice(ty)
+                        | ty::Ref(_, ty, _)
+                        | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
+                            matches!(ty.kind(), ty::Param(..))
+                        }
+                        ty::Tuple(tys) => tys.iter().all(|ty| matches!(ty.kind(), ty::Param(..))),
+                        _ => true,
+                    }
+                }) {
                     let impls = get_auto_trait_and_blanket_impls(cx, def_id);
                     new_items_external.extend(impls.filter(|i| cx.inlined.insert(i.item_id)));
                 }
diff --git a/src/test/rustdoc/primitive-slice-auto-trait.rs b/src/test/rustdoc/primitive-slice-auto-trait.rs
new file mode 100644
index 00000000000..b3f511bc1f1
--- /dev/null
+++ b/src/test/rustdoc/primitive-slice-auto-trait.rs
@@ -0,0 +1,14 @@
+// compile-flags: --crate-type lib --edition 2018
+
+#![crate_name = "foo"]
+#![feature(rustdoc_internals)]
+
+// @has foo/primitive.slice.html '//a[@class="primitive"]' 'slice'
+// @has - '//span[@class="in-band"]' 'Primitive Type slice'
+// @has - '//section[@id="main-content"]//div[@class="docblock"]//p' 'this is a test!'
+// @has - '//h2[@id="synthetic-implementations"]' 'Auto Trait Implementations'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Send for [T] where T: Send'
+// @has - '//div[@id="synthetic-implementations-list"]//h3' 'impl<T> Sync for [T] where T: Sync'
+#[doc(primitive = "slice")]
+/// this is a test!
+mod slice_prim {}