diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index da88172c688f5..af7c6410a55b3 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -21,7 +21,7 @@ use rustc_hir::{ConstStability, StabilityLevel, StableSince};
use rustc_metadata::creader::CStore;
use rustc_middle::ty::{self, Ty, TyCtxt, TypingMode};
use rustc_span::symbol::kw;
-use rustc_span::{Ident, Symbol};
+use rustc_span::{Ident, Symbol, sym};
use tracing::{debug, trace};
use super::url_parts_builder::UrlPartsBuilder;
@@ -537,11 +537,25 @@ fn generate_item_def_id_path(
&& !def_id.is_local()
&& def_id.krate != original_def_id.krate;
} else {
+ // This hack is because primitive types are only documented in `core` and `std`.
+ // However, with `#[rustc_allow_incoherent_impl]`, a lot of primitive methods are
+ // implemented in `core`. Some of them are documented in `core` (like `[]::sort`) while
+ // others aren't (like `[]::to_vec`). So in case we're not documenting `core`, we link
+ // to `std`.
+ if !of_trait && crate_name != sym::core {
+ if ![sym::alloc, sym::std].contains(&crate_name) {
+ // We cannot link to this primitive's associated item as it's not part of
+ // `core`, `alloc` or `std` so returning early.
+ return Err(HrefError::UnnamableItem);
+ }
+ maybe_have_impl_not_in_def_crate = true;
+ }
prim = PrimitiveType::from_ty(ty);
}
}
let (shortty, fqp) = if let Some(prim) = prim {
+ let crate_name = if maybe_have_impl_not_in_def_crate { sym::std } else { crate_name };
(ItemType::Primitive, vec![crate_name, prim.as_sym()])
} else {
(
diff --git a/tests/rustdoc-html/jump-to-def/auxiliary/incoherent_impl_primitive.rs b/tests/rustdoc-html/jump-to-def/auxiliary/incoherent_impl_primitive.rs
new file mode 100644
index 0000000000000..98e9a5129417c
--- /dev/null
+++ b/tests/rustdoc-html/jump-to-def/auxiliary/incoherent_impl_primitive.rs
@@ -0,0 +1,7 @@
+#![feature(rustc_attrs)]
+#![allow(internal_features)]
+
+impl [T] {
+ #[rustc_allow_incoherent_impl]
+ pub fn f(&self) {}
+}
diff --git a/tests/rustdoc-html/jump-to-def/incoherent_impl-primitive.rs b/tests/rustdoc-html/jump-to-def/incoherent_impl-primitive.rs
new file mode 100644
index 0000000000000..9a4609953a178
--- /dev/null
+++ b/tests/rustdoc-html/jump-to-def/incoherent_impl-primitive.rs
@@ -0,0 +1,25 @@
+// This test checks that outside of `core`/`alloc`/`std`, we don't link to incoherent method impl
+// because there is no page to link to since primitive are only documented in `core` and `std`.
+
+//@ aux-build: incoherent_impl_primitive.rs
+//@ build-aux-docs
+//@ compile-flags: -Zunstable-options --generate-link-to-definition
+
+#![crate_name = "foo"]
+
+extern crate incoherent_impl_primitive;
+
+//@ has 'src/foo/incoherent_impl-primitive.rs.html'
+
+// It should contain only the link to "first". Sadly, because of the limit, we cannot test
+// if a link doesn't have an attribute so for now, we simply ensure that the number of ``
+// (including both line numbers and jump to def links) is superior by one to the number of
+// line ``. If so, we know there is only one jump to def link.
+//@ count - '//pre/code/a' 7
+//@ count - '//pre/code/a[@id]' 6
+//@ has - '//pre/code/a[@href="{{channel}}/core/primitive.slice.html#method.first"]' 'first'
+
+fn foo() {
+ let x = ["a"].f();
+ ["a"].first();
+}