summaryrefslogtreecommitdiffstats
path: root/src/test/rustdoc/intra-doc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /src/test/rustdoc/intra-doc
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/rustdoc/intra-doc')
-rw-r--r--src/test/rustdoc/intra-doc/anchors.rs24
-rw-r--r--src/test/rustdoc/intra-doc/associated-defaults.rs26
-rw-r--r--src/test/rustdoc/intra-doc/associated-items.rs68
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/empty.rs1
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/empty2.rs1
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs28
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs11
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs3
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs4
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs6
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs6
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/issue-66159-1.rs2
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/my-core.rs23
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs34
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs1
-rw-r--r--src/test/rustdoc/intra-doc/basic.rs84
-rw-r--r--src/test/rustdoc/intra-doc/builtin-macros.rs3
-rw-r--r--src/test/rustdoc/intra-doc/crate-relative-assoc.rs17
-rw-r--r--src/test/rustdoc/intra-doc/crate-relative.rs13
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs10
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs6
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs19
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs7
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs5
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs10
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs7
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs20
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs12
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs13
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs16
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/basic.rs9
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/crate.rs6
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/hidden.rs10
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/macro.rs11
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/module.rs8
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs8
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs16
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/traits.rs14
-rw-r--r--src/test/rustdoc/intra-doc/disambiguators-removed.rs50
-rw-r--r--src/test/rustdoc/intra-doc/email-address.rs10
-rw-r--r--src/test/rustdoc/intra-doc/enum-struct-field.rs14
-rw-r--r--src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs11
-rw-r--r--src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs19
-rw-r--r--src/test/rustdoc/intra-doc/extern-crate.rs9
-rw-r--r--src/test/rustdoc/intra-doc/extern-inherent-impl.rs8
-rw-r--r--src/test/rustdoc/intra-doc/extern-reference-link.rs7
-rw-r--r--src/test/rustdoc/intra-doc/extern-type.rs37
-rw-r--r--src/test/rustdoc/intra-doc/external-traits.rs12
-rw-r--r--src/test/rustdoc/intra-doc/field.rs4
-rw-r--r--src/test/rustdoc/intra-doc/generic-params.rs62
-rw-r--r--src/test/rustdoc/intra-doc/generic-trait-impl.rs20
-rw-r--r--src/test/rustdoc/intra-doc/in-bodies.rs30
-rw-r--r--src/test/rustdoc/intra-doc/issue-66159.rs10
-rw-r--r--src/test/rustdoc/intra-doc/issue-82209.rs11
-rw-r--r--src/test/rustdoc/intra-doc/libstd-re-export.rs4
-rw-r--r--src/test/rustdoc/intra-doc/macros-disambiguators.rs25
-rw-r--r--src/test/rustdoc/intra-doc/mod-ambiguity.rs16
-rw-r--r--src/test/rustdoc/intra-doc/mod-relative.rs17
-rw-r--r--src/test/rustdoc/intra-doc/non-path-primitives.rs46
-rw-r--r--src/test/rustdoc/intra-doc/prim-assoc.rs4
-rw-r--r--src/test/rustdoc/intra-doc/prim-associated-traits.rs46
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods-external-core.rs17
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods-local.rs29
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods.rs7
-rw-r--r--src/test/rustdoc/intra-doc/prim-precedence.rs16
-rw-r--r--src/test/rustdoc/intra-doc/prim-self.rs41
-rw-r--r--src/test/rustdoc/intra-doc/primitive-disambiguators.rs4
-rw-r--r--src/test/rustdoc/intra-doc/primitive-non-default-impl.rs31
-rw-r--r--src/test/rustdoc/intra-doc/private-failures-ignored.rs8
-rw-r--r--src/test/rustdoc/intra-doc/private.rs20
-rw-r--r--src/test/rustdoc/intra-doc/proc-macro.rs27
-rw-r--r--src/test/rustdoc/intra-doc/pub-use.rs17
-rw-r--r--src/test/rustdoc/intra-doc/raw-ident-self.rs13
-rw-r--r--src/test/rustdoc/intra-doc/reexport-additional-docs.rs23
-rw-r--r--src/test/rustdoc/intra-doc/self-cache.rs14
-rw-r--r--src/test/rustdoc/intra-doc/self.rs116
-rw-r--r--src/test/rustdoc/intra-doc/trait-impl.rs34
-rw-r--r--src/test/rustdoc/intra-doc/trait-item.rs11
-rw-r--r--src/test/rustdoc/intra-doc/true-false.rs8
-rw-r--r--src/test/rustdoc/intra-doc/type-alias.rs19
80 files changed, 1489 insertions, 0 deletions
diff --git a/src/test/rustdoc/intra-doc/anchors.rs b/src/test/rustdoc/intra-doc/anchors.rs
new file mode 100644
index 000000000..3d4c46496
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/anchors.rs
@@ -0,0 +1,24 @@
+/// I want...
+///
+/// # Anchor!
+pub struct Something;
+
+// @has anchors/struct.SomeOtherType.html
+// @has - '//a/@href' 'struct.Something.html#Anchor!'
+
+/// I want...
+///
+/// To link to [Something#Anchor!]
+pub struct SomeOtherType;
+
+/// Primitives?
+///
+/// [u32#hello]
+// @has anchors/fn.x.html
+// @has - '//a/@href' '{{channel}}/std/primitive.u32.html#hello'
+pub fn x() {}
+
+/// [prim@usize#x]
+// @has anchors/usize/index.html
+// @has - '//a/@href' '{{channel}}/std/primitive.usize.html#x'
+pub mod usize {}
diff --git a/src/test/rustdoc/intra-doc/associated-defaults.rs b/src/test/rustdoc/intra-doc/associated-defaults.rs
new file mode 100644
index 000000000..c7e66c826
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/associated-defaults.rs
@@ -0,0 +1,26 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(associated_type_defaults)]
+
+pub trait TraitWithDefault {
+ type T = usize;
+ fn f() -> Self::T {
+ 0
+ }
+}
+
+/// Link to [UsesDefaults::T] and [UsesDefaults::f]
+// @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="struct.UsesDefaults.html#associatedtype.T"]' 'UsesDefaults::T'
+// @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="struct.UsesDefaults.html#method.f"]' 'UsesDefaults::f'
+pub struct UsesDefaults;
+impl TraitWithDefault for UsesDefaults {}
+
+/// Link to [OverridesDefaults::T] and [OverridesDefaults::f]
+// @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="struct.OverridesDefaults.html#associatedtype.T"]' 'OverridesDefaults::T'
+// @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="struct.OverridesDefaults.html#method.f"]' 'OverridesDefaults::f'
+pub struct OverridesDefaults;
+impl TraitWithDefault for OverridesDefaults {
+ type T = bool;
+ fn f() -> bool {
+ true
+ }
+}
diff --git a/src/test/rustdoc/intra-doc/associated-items.rs b/src/test/rustdoc/intra-doc/associated-items.rs
new file mode 100644
index 000000000..0b958eb8e
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/associated-items.rs
@@ -0,0 +1,68 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+/// [`std::collections::BTreeMap::into_iter`]
+/// [`String::from`] is ambiguous as to which `From` impl
+/// [Vec::into_iter()] uses a disambiguator
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/string/struct.String.html#method.from"]' 'String::from'
+// @has 'associated_items/fn.foo.html' '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter'
+pub fn foo() {}
+
+/// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input]
+// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html"]' 'MyStruct'
+// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from struct'
+// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.clone"]' 'MyStruct::clone'
+// @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#associatedtype.Input"]' 'MyStruct::Input'
+pub struct MyStruct { foo: () }
+
+impl Clone for MyStruct {
+ fn clone(&self) -> Self {
+ MyStruct
+ }
+}
+
+pub trait T {
+ type Input;
+ fn method(i: Self::Input);
+}
+
+impl T for MyStruct {
+ type Input = usize;
+
+ /// [link from method][MyStruct::method] on method
+ // @has 'associated_items/struct.MyStruct.html' '//a[@href="struct.MyStruct.html#method.method"]' 'link from method'
+ fn method(i: usize) {
+ }
+}
+
+/// Ambiguity between which trait to use
+pub trait T1 {
+ fn ambiguous_method();
+}
+
+pub trait T2 {
+ fn ambiguous_method();
+}
+
+/// Link to [S::ambiguous_method]
+// FIXME: there is no way to disambiguate these.
+// Since we have `#[deny(intra_doc_failure)]`, we still know it was one or the other.
+pub struct S;
+
+impl T1 for S {
+ fn ambiguous_method() {}
+}
+
+impl T2 for S {
+ fn ambiguous_method() {}
+}
+
+// @has associated_items/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.MyVariant'
+/// Link to [MyEnumAlias::MyVariant]
+pub enum MyEnum {
+ MyVariant,
+}
+
+pub type MyEnumAlias = MyEnum;
+
+fn main() {}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/empty.rs b/src/test/rustdoc/intra-doc/auxiliary/empty.rs
new file mode 100644
index 000000000..d11c69f81
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/empty.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc/intra-doc/auxiliary/empty2.rs b/src/test/rustdoc/intra-doc/auxiliary/empty2.rs
new file mode 100644
index 000000000..d11c69f81
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/empty2.rs
@@ -0,0 +1 @@
+// intentionally empty
diff --git a/src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs b/src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs
new file mode 100644
index 000000000..d9a08cb41
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs
@@ -0,0 +1,28 @@
+// no-prefer-dynamic
+
+#![feature(lang_items, rustc_attrs)]
+#![crate_type = "rlib"]
+#![no_std]
+
+pub struct DerefsToF64(f64);
+
+impl core::ops::Deref for DerefsToF64 {
+ type Target = f64;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+mod inner {
+ impl f64 {
+ /// [f64::clone]
+ #[rustc_allow_incoherent_impl]
+ pub fn method() {}
+ }
+}
+
+#[lang = "eh_personality"]
+fn foo() {}
+
+#[panic_handler]
+fn bar(_: &core::panic::PanicInfo) -> ! { loop {} }
diff --git a/src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs b/src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs
new file mode 100644
index 000000000..ee4138b68
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/extern-inherent-impl-dep.rs
@@ -0,0 +1,11 @@
+#[derive(Clone)]
+pub struct PublicStruct;
+
+mod inner {
+ use super::PublicStruct;
+
+ impl PublicStruct {
+ /// [PublicStruct::clone]
+ pub fn method() {}
+ }
+}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs
new file mode 100644
index 000000000..db3bb38ad
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs
@@ -0,0 +1,3 @@
+#![crate_name="inner"]
+
+//! ooh, i'm a rebel just for [kicks]
diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs
new file mode 100644
index 000000000..a4db2ffc4
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs
@@ -0,0 +1,4 @@
+#![crate_name = "inner"]
+
+/// Documentation, including a link to [std::ptr]
+pub fn f() {}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs
new file mode 100644
index 000000000..fc51995a9
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs
@@ -0,0 +1,6 @@
+#![crate_name = "inner"]
+
+/// Links to [f()]
+pub struct Inner;
+
+pub fn f() {}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs
new file mode 100644
index 000000000..6142dcda9
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs
@@ -0,0 +1,6 @@
+pub trait ThisTrait {
+ fn asdf(&self);
+
+ /// let's link to [`asdf`](ThisTrait::asdf)
+ fn qwop(&self);
+}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/issue-66159-1.rs b/src/test/rustdoc/intra-doc/auxiliary/issue-66159-1.rs
new file mode 100644
index 000000000..2f3d069bd
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/issue-66159-1.rs
@@ -0,0 +1,2 @@
+/// This will be referred to by the test docstring
+pub struct Something;
diff --git a/src/test/rustdoc/intra-doc/auxiliary/my-core.rs b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs
new file mode 100644
index 000000000..e22feb03a
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs
@@ -0,0 +1,23 @@
+#![feature(no_core, lang_items, rustdoc_internals, rustc_attrs)]
+#![no_core]
+#![rustc_coherence_is_core]
+#![crate_type="rlib"]
+
+#[doc(primitive = "char")]
+/// Some char docs
+mod char {}
+
+impl char {
+ pub fn len_utf8(self) -> usize {
+ 42
+ }
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "clone"]
+pub trait Clone: Sized {}
+
+#[lang = "copy"]
+pub trait Copy: Clone {}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs b/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs
new file mode 100644
index 000000000..5ba132f25
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs
@@ -0,0 +1,34 @@
+// force-host
+// no-prefer-dynamic
+// compile-flags: --crate-type proc-macro
+
+#![crate_type="proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(DeriveA)]
+pub fn a_derive(input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_derive(DeriveB)]
+pub fn b_derive(input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_derive(DeriveTrait)]
+pub fn trait_derive(input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_attribute]
+pub fn attr_a(input: TokenStream, _args: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_attribute]
+pub fn attr_b(input: TokenStream, _args: TokenStream) -> TokenStream {
+ input
+}
diff --git a/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs b/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs
new file mode 100644
index 000000000..75d428932
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/pub-struct.rs
@@ -0,0 +1 @@
+pub struct SomeStruct;
diff --git a/src/test/rustdoc/intra-doc/basic.rs b/src/test/rustdoc/intra-doc/basic.rs
new file mode 100644
index 000000000..39f5c298b
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/basic.rs
@@ -0,0 +1,84 @@
+// @has basic/index.html
+// @has - '//a/@href' 'struct.ThisType.html'
+// @has - '//a/@href' 'struct.ThisType.html#method.this_method'
+// @has - '//a/@href' 'enum.ThisEnum.html'
+// @has - '//a/@href' 'enum.ThisEnum.html#variant.ThisVariant'
+// @has - '//a/@href' 'trait.ThisTrait.html'
+// @has - '//a/@href' 'trait.ThisTrait.html#tymethod.this_associated_method'
+// @has - '//a/@href' 'trait.ThisTrait.html#associatedtype.ThisAssociatedType'
+// @has - '//a/@href' 'trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST'
+// @has - '//a/@href' 'trait.ThisTrait.html'
+// @has - '//a/@href' 'type.ThisAlias.html'
+// @has - '//a/@href' 'union.ThisUnion.html'
+// @has - '//a/@href' 'fn.this_function.html'
+// @has - '//a/@href' 'constant.THIS_CONST.html'
+// @has - '//a/@href' 'static.THIS_STATIC.html'
+// @has - '//a/@href' 'macro.this_macro.html'
+// @has - '//a/@href' 'trait.SoAmbiguous.html'
+// @has - '//a/@href' 'fn.SoAmbiguous.html'
+//! In this crate we would like to link to:
+//!
+//! * [`ThisType`](ThisType)
+//! * [`ThisType::this_method`](ThisType::this_method)
+//! * [`ThisEnum`](ThisEnum)
+//! * [`ThisEnum::ThisVariant`](ThisEnum::ThisVariant)
+//! * [`ThisEnum::ThisVariantCtor`](ThisEnum::ThisVariantCtor)
+//! * [`ThisTrait`](ThisTrait)
+//! * [`ThisTrait::this_associated_method`](ThisTrait::this_associated_method)
+//! * [`ThisTrait::ThisAssociatedType`](ThisTrait::ThisAssociatedType)
+//! * [`ThisTrait::THIS_ASSOCIATED_CONST`](ThisTrait::THIS_ASSOCIATED_CONST)
+//! * [`ThisAlias`](ThisAlias)
+//! * [`ThisUnion`](ThisUnion)
+//! * [`this_function`](this_function())
+//! * [`THIS_CONST`](const@THIS_CONST)
+//! * [`THIS_STATIC`](static@THIS_STATIC)
+//! * [`this_macro`](this_macro!)
+//!
+//! In addition, there's some specifics we want to look at. There's [a trait called
+//! SoAmbiguous][ambig-trait], but there's also [a function called SoAmbiguous][ambig-fn] too!
+//! Whatever shall we do?
+//!
+//! [ambig-trait]: trait@SoAmbiguous
+//! [ambig-fn]: SoAmbiguous()
+
+#[macro_export]
+macro_rules! this_macro {
+ () => {};
+}
+
+// @has basic/struct.ThisType.html '//a/@href' 'macro.this_macro.html'
+/// another link to [`this_macro!()`]
+pub struct ThisType;
+
+impl ThisType {
+ pub fn this_method() {}
+}
+pub enum ThisEnum { ThisVariant, ThisVariantCtor(u32), }
+pub trait ThisTrait {
+ type ThisAssociatedType;
+ const THIS_ASSOCIATED_CONST: u8;
+ fn this_associated_method();
+}
+pub type ThisAlias = Result<(), ()>;
+pub union ThisUnion { this_field: usize, }
+
+pub fn this_function() {}
+pub const THIS_CONST: usize = 5usize;
+pub static THIS_STATIC: usize = 5usize;
+
+pub trait SoAmbiguous {}
+
+#[allow(nonstandard_style)]
+pub fn SoAmbiguous() {}
+
+
+// @has basic/struct.SomeOtherType.html '//a/@href' 'struct.ThisType.html'
+// @has - '//a/@href' 'struct.ThisType.html#method.this_method'
+// @has - '//a/@href' 'enum.ThisEnum.html'
+// @has - '//a/@href' 'enum.ThisEnum.html#variant.ThisVariant'
+/// Shortcut links for:
+/// * [`ThisType`]
+/// * [`ThisType::this_method`]
+/// * [ThisEnum]
+/// * [ThisEnum::ThisVariant]
+pub struct SomeOtherType;
diff --git a/src/test/rustdoc/intra-doc/builtin-macros.rs b/src/test/rustdoc/intra-doc/builtin-macros.rs
new file mode 100644
index 000000000..bbdbe246b
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/builtin-macros.rs
@@ -0,0 +1,3 @@
+// @has builtin_macros/index.html
+// @has - '//a/@href' '{{channel}}/core/macro.cfg.html'
+//! [cfg]
diff --git a/src/test/rustdoc/intra-doc/crate-relative-assoc.rs b/src/test/rustdoc/intra-doc/crate-relative-assoc.rs
new file mode 100644
index 000000000..d4a0ecc35
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/crate-relative-assoc.rs
@@ -0,0 +1,17 @@
+pub mod io {
+ pub trait Read {
+ fn read(&mut self);
+ }
+}
+
+pub mod bufreader {
+ // @has crate_relative_assoc/bufreader/index.html '//a/@href' 'struct.TcpStream.html#method.read'
+ //! [`crate::TcpStream::read`]
+ use crate::io::Read;
+}
+
+pub struct TcpStream;
+
+impl crate::io::Read for TcpStream {
+ fn read(&mut self) {}
+}
diff --git a/src/test/rustdoc/intra-doc/crate-relative.rs b/src/test/rustdoc/intra-doc/crate-relative.rs
new file mode 100644
index 000000000..bacbcabfc
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/crate-relative.rs
@@ -0,0 +1,13 @@
+pub struct Test<'a> {
+ data: &'a (),
+}
+
+impl<'a> Test<'a> {
+ pub fn do_test(&self) {}
+}
+
+// @has crate_relative/demo/index.html
+// @has - '//a/@href' '../struct.Test.html#method.do_test'
+pub mod demo {
+ //! [`crate::Test::do_test`]
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs
new file mode 100644
index 000000000..e52fb9b1c
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs
@@ -0,0 +1,10 @@
+// aux-build:additional_doc.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate my_rand;
+
+// @has 'additional_doc/trait.Rng.html' '//a[@href="trait.Rng.html"]' 'Rng'
+// @has 'additional_doc/trait.Rng.html' '//a[@href="../my_rand/trait.RngCore.html"]' 'RngCore'
+/// This is an [`Rng`].
+pub use my_rand::Rng;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs
new file mode 100644
index 000000000..684fdd449
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs
@@ -0,0 +1,6 @@
+#![crate_name = "my_rand"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub trait RngCore {}
+/// Rng extends [`RngCore`].
+pub trait Rng: RngCore {}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs
new file mode 100644
index 000000000..34f4e9f63
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs
@@ -0,0 +1,19 @@
+#![crate_name = "hidden_dep"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+#[doc(hidden)]
+pub mod __reexport {
+ pub use crate::*;
+}
+
+pub mod future {
+ mod ready {
+
+ /// Link to [`ready`](function@ready)
+ pub struct Ready;
+ pub fn ready() {}
+
+ }
+ pub use self::ready::{ready, Ready};
+
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs
new file mode 100644
index 000000000..d6a829966
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs
@@ -0,0 +1,7 @@
+#![crate_name = "a"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub struct Foo;
+
+/// Link to [Foo]
+pub struct Bar;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs
new file mode 100644
index 000000000..a37848e23
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs
@@ -0,0 +1,5 @@
+#![crate_name = "inner"]
+
+/// Links to [crate::g]
+pub fn f() {}
+pub fn g() {}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs
new file mode 100644
index 000000000..cb7a8afb6
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs
@@ -0,0 +1,10 @@
+#![crate_name = "macro_inner"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub struct Foo;
+
+/// See also [`Foo`]
+#[macro_export]
+macro_rules! my_macro {
+ () => {}
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs
new file mode 100644
index 000000000..018fdedd9
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs
@@ -0,0 +1,7 @@
+#![crate_name = "module_inner"]
+#![deny(rustdoc::broken_intra_doc_links)]
+/// [SomeType] links to [bar]
+pub struct SomeType;
+pub trait SomeTrait {}
+/// [bar] links to [SomeTrait] and also [SomeType]
+pub mod bar {}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs
new file mode 100644
index 000000000..0d5a95407
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs
@@ -0,0 +1,20 @@
+// force-host
+// no-prefer-dynamic
+// compile-flags: --crate-type proc-macro
+#![crate_type="proc-macro"]
+#![crate_name="proc_macro_inner"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+
+/// Links to [`OtherDerive`]
+#[proc_macro_derive(DeriveA)]
+pub fn a_derive(input: TokenStream) -> TokenStream {
+ input
+}
+
+#[proc_macro_derive(OtherDerive)]
+pub fn other_derive(input: TokenStream) -> TokenStream {
+ input
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs
new file mode 100644
index 000000000..0612f53d6
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs
@@ -0,0 +1,12 @@
+#![crate_name = "a"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub mod bar {
+ pub struct Bar;
+}
+
+pub mod foo {
+ use crate::bar;
+ /// link to [bar::Bar]
+ pub struct Foo;
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs
new file mode 100644
index 000000000..105eb8e11
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs
@@ -0,0 +1,13 @@
+#![crate_name = "bar"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub trait Foo {
+ /// [`Bar`] [`Baz`]
+ fn foo();
+}
+
+pub trait Bar {
+}
+
+pub trait Baz {
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs
new file mode 100644
index 000000000..c16e39d56
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs
@@ -0,0 +1,16 @@
+#![crate_name = "inner"]
+/// this is a trait
+pub trait SomeTrait {
+ /// this is a method for [a trait][SomeTrait]
+ fn foo();
+}
+
+pub mod bar {
+ use super::SomeTrait;
+
+ pub struct BarStruct;
+
+ impl SomeTrait for BarStruct {
+ fn foo() {}
+ }
+}
diff --git a/src/test/rustdoc/intra-doc/cross-crate/basic.rs b/src/test/rustdoc/intra-doc/cross-crate/basic.rs
new file mode 100644
index 000000000..ad7454918
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/basic.rs
@@ -0,0 +1,9 @@
+// aux-build:intra-doc-basic.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// from https://github.com/rust-lang/rust/issues/65983
+extern crate a;
+
+// @has 'basic/struct.Bar.html' '//a[@href="../a/struct.Foo.html"]' 'Foo'
+pub use a::Bar;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/crate.rs b/src/test/rustdoc/intra-doc/cross-crate/crate.rs
new file mode 100644
index 000000000..edf544708
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/crate.rs
@@ -0,0 +1,6 @@
+// aux-build:intra-link-cross-crate-crate.rs
+// build-aux-docs
+#![crate_name = "outer"]
+extern crate inner;
+// @has outer/fn.f.html '//a[@href="../inner/fn.g.html"]' "crate::g"
+pub use inner::f;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs
new file mode 100644
index 000000000..4f7d075ba
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs
@@ -0,0 +1,10 @@
+// aux-build:hidden.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// tests https://github.com/rust-lang/rust/issues/73363
+
+extern crate hidden_dep;
+
+// @has 'hidden/struct.Ready.html' '//a/@href' 'fn.ready.html'
+pub use hidden_dep::future::{ready, Ready};
diff --git a/src/test/rustdoc/intra-doc/cross-crate/macro.rs b/src/test/rustdoc/intra-doc/cross-crate/macro.rs
new file mode 100644
index 000000000..32f0a55d3
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/macro.rs
@@ -0,0 +1,11 @@
+// aux-build:macro_inner.rs
+// aux-build:proc_macro.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+extern crate macro_inner;
+extern crate proc_macro_inner;
+
+// @has 'macro/macro.my_macro.html' '//a[@href="../macro_inner/struct.Foo.html"]' 'Foo'
+pub use macro_inner::my_macro;
+// @has 'macro/derive.DeriveA.html' '//a[@href="../proc_macro_inner/derive.OtherDerive.html"]' 'OtherDerive'
+pub use proc_macro_inner::DeriveA;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/module.rs b/src/test/rustdoc/intra-doc/cross-crate/module.rs
new file mode 100644
index 000000000..fde932265
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/module.rs
@@ -0,0 +1,8 @@
+// outer.rs
+// aux-build: module.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+extern crate module_inner;
+// @has 'module/bar/index.html' '//a[@href="../../module_inner/trait.SomeTrait.html"]' 'SomeTrait'
+// @has 'module/bar/index.html' '//a[@href="../../module_inner/struct.SomeType.html"]' 'SomeType'
+pub use module_inner::bar;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs
new file mode 100644
index 000000000..577fe78a5
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs
@@ -0,0 +1,8 @@
+// aux-build:submodule-inner.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate a;
+
+// @has 'submodule_inner/struct.Foo.html' '//a[@href="../a/bar/struct.Bar.html"]' 'Bar'
+pub use a::foo::Foo;
diff --git a/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs
new file mode 100644
index 000000000..d0c0b7e85
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs
@@ -0,0 +1,16 @@
+// aux-build:submodule-outer.rs
+// edition:2018
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate bar as bar_;
+
+// from https://github.com/rust-lang/rust/issues/60883
+pub mod bar {
+ pub use ::bar_::Bar;
+}
+
+// NOTE: we re-exported both `Foo` and `Bar` here,
+// NOTE: so they are inlined and therefore we link to the current module.
+// @has 'submodule_outer/trait.Foo.html' '//a[@href="bar/trait.Bar.html"]' 'Bar'
+// @has 'submodule_outer/trait.Foo.html' '//a[@href="trait.Baz.html"]' 'Baz'
+pub use ::bar_::{Foo, Baz};
diff --git a/src/test/rustdoc/intra-doc/cross-crate/traits.rs b/src/test/rustdoc/intra-doc/cross-crate/traits.rs
new file mode 100644
index 000000000..7b9554bfd
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/traits.rs
@@ -0,0 +1,14 @@
+// aux-build:traits.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate inner;
+use inner::SomeTrait;
+
+pub struct SomeStruct;
+
+ // @has 'traits/struct.SomeStruct.html' '//a[@href="../inner/trait.SomeTrait.html"]' 'SomeTrait'
+impl SomeTrait for SomeStruct {
+ // @has 'traits/struct.SomeStruct.html' '//a[@href="../inner/trait.SomeTrait.html"]' 'a trait'
+ fn foo() {}
+}
diff --git a/src/test/rustdoc/intra-doc/disambiguators-removed.rs b/src/test/rustdoc/intra-doc/disambiguators-removed.rs
new file mode 100644
index 000000000..331a31413
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/disambiguators-removed.rs
@@ -0,0 +1,50 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+// first try backticks
+/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`]
+// @has disambiguators_removed/struct.AtDisambiguator.html
+// @has - '//a[@href="trait.Name.html"][code]' "Name"
+// @has - '//a[@href="fn.Name.html"][code]' "Name"
+// @has - '//a[@href="macro.Name.html"][code]' "Name"
+pub struct AtDisambiguator;
+
+/// fn: [`Name()`], macro: [`Name!`]
+// @has disambiguators_removed/struct.SymbolDisambiguator.html
+// @has - '//a[@href="fn.Name.html"][code]' "Name()"
+// @has - '//a[@href="macro.Name.html"][code]' "Name!"
+pub struct SymbolDisambiguator;
+
+// Now make sure that backticks aren't added if they weren't already there
+/// [fn@Name]
+// @has disambiguators_removed/trait.Name.html
+// @has - '//a[@href="fn.Name.html"]' "Name"
+// @!has - '//a[@href="fn.Name.html"][code]' "Name"
+
+// FIXME: this will turn !() into ! alone
+/// [Name!()]
+// @has - '//a[@href="macro.Name.html"]' "Name!"
+pub trait Name {}
+
+#[allow(non_snake_case)]
+
+// Try collapsed reference links
+/// [macro@Name][]
+// @has disambiguators_removed/fn.Name.html
+// @has - '//a[@href="macro.Name.html"]' "Name"
+
+// Try links that have the same text as a generated URL
+/// Weird URL aligned [macro.Name.html][trait@Name]
+// @has - '//a[@href="trait.Name.html"]' "macro.Name.html"
+pub fn Name() {}
+
+#[macro_export]
+// Rustdoc doesn't currently handle links that have weird interspersing of inline code blocks.
+/// [fn@Na`m`e]
+// @has disambiguators_removed/macro.Name.html
+// @has - '//a[@href="fn.Name.html"]' "fn@Name"
+
+// It also doesn't handle any case where the code block isn't the whole link text:
+/// [trait@`Name`]
+// @has - '//a[@href="trait.Name.html"]' "trait@Name"
+macro_rules! Name {
+ () => ()
+}
diff --git a/src/test/rustdoc/intra-doc/email-address.rs b/src/test/rustdoc/intra-doc/email-address.rs
new file mode 100644
index 000000000..24161c3bb
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/email-address.rs
@@ -0,0 +1,10 @@
+#![forbid(rustdoc::broken_intra_doc_links)]
+
+//! Email me at <hello@example.com>.
+//! Email me at <hello-world@example.com>.
+//! Email me at <hello@localhost>.
+//! Email me at <prim@i32>.
+// @has email_address/index.html '//a[@href="mailto:hello@example.com"]' 'hello@example.com'
+// @has email_address/index.html '//a[@href="mailto:hello-world@example.com"]' 'hello-world@example.com'
+// @has email_address/index.html '//a[@href="mailto:hello@localhost"]' 'hello@localhost'
+// @has email_address/index.html '//a[@href="mailto:prim@i32"]' 'prim@i32'
diff --git a/src/test/rustdoc/intra-doc/enum-struct-field.rs b/src/test/rustdoc/intra-doc/enum-struct-field.rs
new file mode 100644
index 000000000..2270a1faf
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/enum-struct-field.rs
@@ -0,0 +1,14 @@
+#![crate_name = "foo"]
+
+pub enum Foo {
+ X {
+ y: u8,
+ }
+}
+
+/// Hello
+///
+/// I want [Foo::X::y].
+pub fn foo() {}
+
+// @has foo/fn.foo.html '//a/@href' 'enum.Foo.html#variant.X.field.y'
diff --git a/src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs b/src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs
new file mode 100644
index 000000000..7bb1ded3f
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs
@@ -0,0 +1,11 @@
+// Reexport of a structure that derefs to a type with lang item impls having doc links in their
+// comments. The doc link points to an associated item, so we check that traits in scope for that
+// link are populated.
+
+// aux-build:extern-builtin-type-impl-dep.rs
+
+#![no_std]
+
+extern crate extern_builtin_type_impl_dep;
+
+pub use extern_builtin_type_impl_dep::DerefsToF64;
diff --git a/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs b/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs
new file mode 100644
index 000000000..5d8dcf8bc
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-crate-only-used-in-link.rs
@@ -0,0 +1,19 @@
+// This test is just a little cursed.
+// aux-build:issue-66159-1.rs
+// aux-crate:priv:issue_66159_1=issue-66159-1.rs
+// aux-build:empty.rs
+// aux-crate:priv:empty=empty.rs
+// aux-build:empty2.rs
+// aux-crate:priv:empty2=empty2.rs
+// build-aux-docs
+// compile-flags:-Z unstable-options --edition 2018
+
+// @has extern_crate_only_used_in_link/index.html
+// @has - '//a[@href="../issue_66159_1/struct.Something.html"]' 'issue_66159_1::Something'
+//! [issue_66159_1::Something]
+
+// @has - '//a[@href="../empty/index.html"]' 'empty'
+//! [`empty`]
+
+// @has - '//a[@href="../empty2/index.html"]' 'empty2'
+//! [empty2<x>]
diff --git a/src/test/rustdoc/intra-doc/extern-crate.rs b/src/test/rustdoc/intra-doc/extern-crate.rs
new file mode 100644
index 000000000..4e4438dea
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-crate.rs
@@ -0,0 +1,9 @@
+// aux-build:intra-link-extern-crate.rs
+
+// When loading `extern crate` statements, we would pull in their docs at the same time, even
+// though they would never actually get displayed. This tripped intra-doc-link resolution failures,
+// for items that aren't under our control, and not actually getting documented!
+
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate inner;
diff --git a/src/test/rustdoc/intra-doc/extern-inherent-impl.rs b/src/test/rustdoc/intra-doc/extern-inherent-impl.rs
new file mode 100644
index 000000000..2e41c2214
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-inherent-impl.rs
@@ -0,0 +1,8 @@
+// Reexport of a structure with public inherent impls having doc links in their comments. The doc
+// link points to an associated item, so we check that traits in scope for that link are populated.
+
+// aux-build:extern-inherent-impl-dep.rs
+
+extern crate extern_inherent_impl_dep;
+
+pub use extern_inherent_impl_dep::PublicStruct;
diff --git a/src/test/rustdoc/intra-doc/extern-reference-link.rs b/src/test/rustdoc/intra-doc/extern-reference-link.rs
new file mode 100644
index 000000000..bad6ec755
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-reference-link.rs
@@ -0,0 +1,7 @@
+// compile-flags: --extern pub_struct
+// aux-build:pub-struct.rs
+
+/// [SomeStruct]
+///
+/// [SomeStruct]: pub_struct::SomeStruct
+pub fn foo() {}
diff --git a/src/test/rustdoc/intra-doc/extern-type.rs b/src/test/rustdoc/intra-doc/extern-type.rs
new file mode 100644
index 000000000..ab088ab78
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-type.rs
@@ -0,0 +1,37 @@
+#![feature(extern_types)]
+
+extern {
+ pub type ExternType;
+}
+
+pub trait T {
+ fn test(&self) {}
+}
+
+pub trait G<N> {
+ fn g(&self, n: N) {}
+}
+
+impl ExternType {
+ pub fn f(&self) {}
+}
+
+impl T for ExternType {
+ fn test(&self) {}
+}
+
+impl G<usize> for ExternType {
+ fn g(&self, n: usize) {}
+}
+
+// @has 'extern_type/foreigntype.ExternType.html'
+// @has 'extern_type/fn.links_to_extern_type.html' \
+// 'href="foreigntype.ExternType.html#method.f"'
+// @has 'extern_type/fn.links_to_extern_type.html' \
+// 'href="foreigntype.ExternType.html#method.test"'
+// @has 'extern_type/fn.links_to_extern_type.html' \
+// 'href="foreigntype.ExternType.html#method.g"'
+/// See also [ExternType::f]
+/// See also [ExternType::test]
+/// See also [ExternType::g]
+pub fn links_to_extern_type() {}
diff --git a/src/test/rustdoc/intra-doc/external-traits.rs b/src/test/rustdoc/intra-doc/external-traits.rs
new file mode 100644
index 000000000..a0a66f242
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/external-traits.rs
@@ -0,0 +1,12 @@
+// aux-build:intra-links-external-traits.rs
+// ignore-cross-compile
+
+#![crate_name = "outer"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// using a trait that has intra-doc links on it from another crate (whether re-exporting or just
+// implementing it) used to give spurious resolution failure warnings
+
+extern crate intra_links_external_traits;
+
+pub use intra_links_external_traits::ThisTrait;
diff --git a/src/test/rustdoc/intra-doc/field.rs b/src/test/rustdoc/intra-doc/field.rs
new file mode 100644
index 000000000..001143489
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/field.rs
@@ -0,0 +1,4 @@
+// @has field/index.html '//a[@href="{{channel}}/core/ops/range/struct.Range.html#structfield.start"]' 'start'
+// @has field/index.html '//a[@href="{{channel}}/std/io/error/enum.ErrorKind.html#variant.NotFound"]' 'not_found'
+//! [start][std::ops::Range::start]
+//! [not_found][std::io::ErrorKind::NotFound]
diff --git a/src/test/rustdoc/intra-doc/generic-params.rs b/src/test/rustdoc/intra-doc/generic-params.rs
new file mode 100644
index 000000000..fbc9fc6a9
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/generic-params.rs
@@ -0,0 +1,62 @@
+// ignore-tidy-linelength
+
+#![crate_name = "foo"]
+
+//! Here's a link to [`Vec<T>`] and one to [`Box<Vec<Option<T>>>`].
+//! Here's a link to [`Iterator<Box<T>>::Item`].
+//!
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html"]' 'Vec<T>'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
+// @has foo/index.html '//a[@href="{{channel}}/core/iter/traits/iterator/trait.Iterator.html#associatedtype.Item"]' 'Iterator<Box<T>>::Item'
+
+//! And what about a link to [just `Option`](Option) and, [with the generic, `Option<T>`](Option<T>)?
+//!
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'just Option'
+// @has foo/index.html '//a[@href="{{channel}}/core/option/enum.Option.html"]' 'with the generic, Option<T>'
+
+//! We should also try linking to [`Result<T, E>`]; it has *two* generics!
+//! And [`Result<T, !>`] and [`Result<!, E>`].
+//!
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, E>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<T, !>'
+// @has foo/index.html '//a[@href="{{channel}}/core/result/enum.Result.html"]' 'Result<!, E>'
+
+//! Now let's test a trickier case: [`Vec::<T>::new`], or you could write it
+//! [with parentheses as `Vec::<T>::new()`][Vec::<T>::new()].
+//! And what about something even harder? That would be [`Vec::<Box<T>>::new()`].
+//!
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<Box<T>>::new()'
+
+//! This is also pretty tricky: [`TypeId::of::<String>()`].
+//! And this too: [`Vec::<std::error::Error>::len`].
+//!
+// @has foo/index.html '//a[@href="{{channel}}/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
+// @has foo/index.html '//a[@href="{{channel}}/alloc/vec/struct.Vec.html#method.len"]' 'Vec::<std::error::Error>::len'
+
+//! We unofficially and implicitly support things that aren't valid in the actual Rust syntax, like
+//! [`Box::<T>new()`]. We may not support them in the future!
+//!
+// @has foo/index.html '//a[@href="{{channel}}/alloc/boxed/struct.Box.html#method.new"]' 'Box::<T>new()'
+
+//! These will be resolved as regular links:
+//! - [`this is <invalid syntax> first`](https://www.rust-lang.org)
+//! - [`this is <invalid syntax> twice`]
+//! - [`<invalid syntax> thrice`](https://www.rust-lang.org)
+//! - [`<invalid syntax> four times`][rlo]
+//! - [a < b][rlo]
+//! - [c > d]
+//!
+//! [`this is <invalid syntax> twice`]: https://www.rust-lang.org
+//! [rlo]: https://www.rust-lang.org
+//! [c > d]: https://www.rust-lang.org
+//!
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> first'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'this is <invalid syntax> twice'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> thrice'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' '<invalid syntax> four times'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'a < b'
+// @has foo/index.html '//a[@href="https://www.rust-lang.org"]' 'c > d'
+
+use std::any::TypeId;
diff --git a/src/test/rustdoc/intra-doc/generic-trait-impl.rs b/src/test/rustdoc/intra-doc/generic-trait-impl.rs
new file mode 100644
index 000000000..ba8595abf
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/generic-trait-impl.rs
@@ -0,0 +1,20 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// Test intra-doc links on trait implementations with generics
+// regression test for issue #92662
+
+use std::marker::PhantomData;
+
+pub trait Bar<T> {
+ fn bar(&self);
+}
+
+pub struct Foo<U>(PhantomData<U>);
+
+impl<T, U> Bar<T> for Foo<U> {
+ fn bar(&self) {}
+}
+
+// @has generic_trait_impl/fn.main.html '//a[@href="struct.Foo.html#method.bar"]' 'Foo::bar'
+/// link to [`Foo::bar`]
+pub fn main() {}
diff --git a/src/test/rustdoc/intra-doc/in-bodies.rs b/src/test/rustdoc/intra-doc/in-bodies.rs
new file mode 100644
index 000000000..55169e5d3
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/in-bodies.rs
@@ -0,0 +1,30 @@
+// we need to make sure that intra-doc links on trait impls get resolved in the right scope
+
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub mod inner {
+ pub struct SomethingOutOfScope;
+}
+
+pub mod other {
+ use inner::SomethingOutOfScope;
+ use SomeTrait;
+
+ pub struct OtherStruct;
+
+ /// Let's link to [SomethingOutOfScope] while we're at it.
+ impl SomeTrait for OtherStruct {}
+}
+
+pub trait SomeTrait {}
+
+pub struct SomeStruct;
+
+fn __implementation_details() {
+ use inner::SomethingOutOfScope;
+
+ // FIXME: intra-links resolve in their nearest module scope, not their actual scope in cases
+ // like this
+ // Let's link to [SomethingOutOfScope] while we're at it.
+ impl SomeTrait for SomeStruct {}
+}
diff --git a/src/test/rustdoc/intra-doc/issue-66159.rs b/src/test/rustdoc/intra-doc/issue-66159.rs
new file mode 100644
index 000000000..56742b397
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/issue-66159.rs
@@ -0,0 +1,10 @@
+// aux-crate:priv:pub_struct=pub-struct.rs
+// compile-flags:-Z unstable-options
+
+// The issue was an ICE which meant that we never actually generated the docs
+// so if we have generated the docs, we're okay.
+// Since we don't generate the docs for the auxiliary files, we can't actually
+// verify that the struct is linked correctly.
+
+// @has issue_66159/index.html
+//! [pub_struct::SomeStruct]
diff --git a/src/test/rustdoc/intra-doc/issue-82209.rs b/src/test/rustdoc/intra-doc/issue-82209.rs
new file mode 100644
index 000000000..a5fe855cb
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/issue-82209.rs
@@ -0,0 +1,11 @@
+#![crate_name = "foo"]
+#![deny(rustdoc::broken_intra_doc_links)]
+pub enum Foo {
+ Bar {
+ abc: i32,
+ /// [Self::Bar::abc]
+ xyz: i32,
+ },
+}
+
+// @has foo/enum.Foo.html '//a/@href' 'enum.Foo.html#variant.Bar.field.abc'
diff --git a/src/test/rustdoc/intra-doc/libstd-re-export.rs b/src/test/rustdoc/intra-doc/libstd-re-export.rs
new file mode 100644
index 000000000..6c41eb2b5
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/libstd-re-export.rs
@@ -0,0 +1,4 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(intra_doc_pointers)]
+
+pub use std::*;
diff --git a/src/test/rustdoc/intra-doc/macros-disambiguators.rs b/src/test/rustdoc/intra-doc/macros-disambiguators.rs
new file mode 100644
index 000000000..cd4caa6a8
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/macros-disambiguators.rs
@@ -0,0 +1,25 @@
+#![crate_name = "foo"]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+//! [foo!()]
+// @has foo/index.html '//a[@href="macro.foo.html"]' 'foo!()'
+
+//! [foo!{}]
+// @has - '//a[@href="macro.foo.html"]' 'foo!{}'
+
+//! [foo![]](foo![])
+// @has - '//a[@href="macro.foo.html"]' 'foo![]'
+
+//! [foo1](foo!())
+// @has - '//a[@href="macro.foo.html"]' 'foo1'
+
+//! [foo2](foo!{})
+// @has - '//a[@href="macro.foo.html"]' 'foo2'
+
+//! [foo3](foo![])
+// @has - '//a[@href="macro.foo.html"]' 'foo3'
+
+#[macro_export]
+macro_rules! foo {
+ () => {};
+}
diff --git a/src/test/rustdoc/intra-doc/mod-ambiguity.rs b/src/test/rustdoc/intra-doc/mod-ambiguity.rs
new file mode 100644
index 000000000..0c7acbaf0
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/mod-ambiguity.rs
@@ -0,0 +1,16 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+
+pub fn foo() {
+
+}
+
+pub mod foo {}
+// @has mod_ambiguity/struct.A.html '//a/@href' 'foo/index.html'
+/// Module is [`module@foo`]
+pub struct A;
+
+
+// @has mod_ambiguity/struct.B.html '//a/@href' 'fn.foo.html'
+/// Function is [`fn@foo`]
+pub struct B;
diff --git a/src/test/rustdoc/intra-doc/mod-relative.rs b/src/test/rustdoc/intra-doc/mod-relative.rs
new file mode 100644
index 000000000..49d3399b9
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/mod-relative.rs
@@ -0,0 +1,17 @@
+pub mod wrapper {
+
+ pub struct Test<'a> {
+ data: &'a (),
+ }
+
+ impl<'a> Test<'a> {
+ pub fn do_test(&self) {}
+ }
+
+ // @has mod_relative/wrapper/demo/index.html
+ // @has - '//a/@href' '../struct.Test.html#method.do_test'
+ /// [`Test::do_test`]
+ pub mod demo {
+ }
+
+}
diff --git a/src/test/rustdoc/intra-doc/non-path-primitives.rs b/src/test/rustdoc/intra-doc/non-path-primitives.rs
new file mode 100644
index 000000000..be4b44b31
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/non-path-primitives.rs
@@ -0,0 +1,46 @@
+#![crate_name = "foo"]
+#![feature(intra_doc_pointers)]
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// @has foo/index.html '//a[@href="{{channel}}/std/primitive.slice.html#method.rotate_left"]' 'slice::rotate_left'
+//! [slice::rotate_left]
+
+// @has - '//a[@href="{{channel}}/std/primitive.array.html#method.map"]' 'array::map'
+//! [array::map]
+
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'owned str'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html"]' 'str ref'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.is_empty"]' 'str::is_empty'
+// @has - '//a[@href="{{channel}}/std/primitive.str.html#method.len"]' '&str::len'
+//! [owned str][str]
+//! [str ref][&str]
+//! [str::is_empty]
+//! [&str::len]
+
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' 'pointer::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*const::is_null'
+// @has - '//a[@href="{{channel}}/std/primitive.pointer.html#method.is_null"]' '*mut::is_null'
+//! [pointer::is_null]
+//! [*const::is_null]
+//! [*mut::is_null]
+
+// @has - '//a[@href="{{channel}}/std/primitive.unit.html"]' 'unit'
+//! [unit]
+
+// @has - '//a[@href="{{channel}}/std/primitive.tuple.html"]' 'tuple'
+//! [tuple]
+
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' 'reference'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&'
+// @has - '//a[@href="{{channel}}/std/primitive.reference.html"]' '&mut'
+//! [reference]
+//! [&]
+//! [&mut]
+
+// @has - '//a[@href="{{channel}}/std/primitive.fn.html"]' 'fn'
+//! [fn]
+
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' 'never'
+// @has - '//a[@href="{{channel}}/std/primitive.never.html"]' '!'
+//! [never]
+//! [!]
diff --git a/src/test/rustdoc/intra-doc/prim-assoc.rs b/src/test/rustdoc/intra-doc/prim-assoc.rs
new file mode 100644
index 000000000..dfa7db8a5
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-assoc.rs
@@ -0,0 +1,4 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+//! [i32::MAX]
+// @has prim_assoc/index.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
diff --git a/src/test/rustdoc/intra-doc/prim-associated-traits.rs b/src/test/rustdoc/intra-doc/prim-associated-traits.rs
new file mode 100644
index 000000000..8639a24f7
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-associated-traits.rs
@@ -0,0 +1,46 @@
+#![feature(never_type)]
+use std::str::FromStr;
+
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f64.html#method.from_str"]' 'f64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.f32.html#method.from_str"]' 'f32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.isize.html#method.from_str"]' 'isize::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i8.html#method.from_str"]' 'i8::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i16.html#method.from_str"]' 'i16::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i32.html#method.from_str"]' 'i32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i64.html#method.from_str"]' 'i64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.i128.html#method.from_str"]' 'i128::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.usize.html#method.from_str"]' 'usize::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u8.html#method.from_str"]' 'u8::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u16.html#method.from_str"]' 'u16::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u32.html#method.from_str"]' 'u32::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u64.html#method.from_str"]' 'u64::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.u128.html#method.from_str"]' 'u128::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.char.html#method.from_str"]' 'char::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.bool.html#method.from_str"]' 'bool::from_str()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.str.html#method.eq"]' 'str::eq()'
+// @has 'prim_associated_traits/struct.Number.html' '//a[@href="{{channel}}/std/primitive.never.html#method.eq"]' 'never::eq()'
+/// [`f64::from_str()`] [`f32::from_str()`] [`isize::from_str()`] [`i8::from_str()`]
+/// [`i16::from_str()`] [`i32::from_str()`] [`i64::from_str()`] [`i128::from_str()`]
+/// [`u16::from_str()`] [`u32::from_str()`] [`u64::from_str()`] [`u128::from_str()`]
+/// [`usize::from_str()`] [`u8::from_str()`] [`char::from_str()`] [`bool::from_str()`]
+/// [`str::eq()`] [`never::eq()`]
+pub struct Number {
+ pub f_64: f64,
+ pub f_32: f32,
+ pub i_size: isize,
+ pub i_8: i8,
+ pub i_16: i16,
+ pub i_32: i32,
+ pub i_64: i64,
+ pub i_128: i128,
+ pub u_size: usize,
+ pub u_8: u8,
+ pub u_16: u16,
+ pub u_32: u32,
+ pub u_64: u64,
+ pub u_128: u128,
+ pub ch: char,
+ pub boolean: bool,
+ pub string: str,
+ pub n: !,
+}
diff --git a/src/test/rustdoc/intra-doc/prim-methods-external-core.rs b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs
new file mode 100644
index 000000000..c3340af33
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs
@@ -0,0 +1,17 @@
+// aux-build:my-core.rs
+// build-aux-docs
+// ignore-cross-compile
+// only-linux
+
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(no_core, lang_items)]
+#![no_core]
+#![crate_type = "rlib"]
+
+// @has prim_methods_external_core/index.html
+// @has - '//*[@id="main-content"]//a[@href="../my_core/primitive.char.html"]' 'char'
+// @has - '//*[@id="main-content"]//a[@href="../my_core/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+
+//! A [`char`] and its [`char::len_utf8`].
+
+extern crate my_core;
diff --git a/src/test/rustdoc/intra-doc/prim-methods-local.rs b/src/test/rustdoc/intra-doc/prim-methods-local.rs
new file mode 100644
index 000000000..79d8df045
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-methods-local.rs
@@ -0,0 +1,29 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![feature(no_core, lang_items, rustc_attrs, rustdoc_internals)]
+#![no_core]
+#![rustc_coherence_is_core]
+#![crate_type = "rlib"]
+
+// @has prim_methods_local/index.html
+// @has - '//*[@id="main-content"]//a[@href="primitive.char.html"]' 'char'
+// @has - '//*[@id="main-content"]//a[@href="primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+
+//! A [prim@`char`] and its [`char::len_utf8`].
+
+#[doc(primitive = "char")]
+mod char {}
+
+impl char {
+ pub fn len_utf8(self) -> usize {
+ 42
+ }
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "clone"]
+pub trait Clone: Sized {}
+
+#[lang = "copy"]
+pub trait Copy: Clone {}
diff --git a/src/test/rustdoc/intra-doc/prim-methods.rs b/src/test/rustdoc/intra-doc/prim-methods.rs
new file mode 100644
index 000000000..a412a23fd
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-methods.rs
@@ -0,0 +1,7 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+// @has prim_methods/index.html
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+
+//! A [`char`] and its [`char::len_utf8`].
diff --git a/src/test/rustdoc/intra-doc/prim-precedence.rs b/src/test/rustdoc/intra-doc/prim-precedence.rs
new file mode 100644
index 000000000..25625b952
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-precedence.rs
@@ -0,0 +1,16 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+pub mod char {
+ /// [char]
+ // @has prim_precedence/char/struct.Inner.html '//a/@href' '{{channel}}/std/primitive.char.html'
+ pub struct Inner;
+}
+
+/// See [prim@char]
+// @has prim_precedence/struct.MyString.html '//a/@href' '{{channel}}/std/primitive.char.html'
+pub struct MyString;
+
+/// See also [crate::char] and [mod@char]
+// @has prim_precedence/struct.MyString2.html '//*[@href="char/index.html"]' 'crate::char'
+// @has - '//*[@href="char/index.html"]' 'mod@char'
+pub struct MyString2;
diff --git a/src/test/rustdoc/intra-doc/prim-self.rs b/src/test/rustdoc/intra-doc/prim-self.rs
new file mode 100644
index 000000000..c7ce71b15
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-self.rs
@@ -0,0 +1,41 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![rustc_coherence_is_core]
+#![allow(incomplete_features)] // inherent_associated_types
+#![feature(rustc_attrs)]
+#![feature(no_core)]
+#![feature(rustdoc_internals)]
+#![feature(inherent_associated_types)]
+#![feature(lang_items)]
+#![no_core]
+
+/// [Self::f]
+/// [Self::MAX]
+// @has prim_self/primitive.usize.html
+// @has - '//a[@href="primitive.usize.html#method.f"]' 'Self::f'
+// @has - '//a[@href="primitive.usize.html#associatedconstant.MAX"]' 'Self::MAX'
+impl usize {
+ /// Some docs
+ pub fn f() {}
+
+ /// 10 and 2^32 are basically the same.
+ pub const MAX: usize = 10;
+
+ // @has - '//a[@href="primitive.usize.html#associatedtype.ME"]' 'Self::ME'
+ /// [Self::ME]
+ pub type ME = usize;
+}
+
+#[doc(primitive = "usize")]
+/// This has some docs.
+mod usize {}
+
+/// [S::f]
+/// [Self::f]
+pub struct S;
+
+impl S {
+ pub fn f() {}
+}
+
+#[lang = "sized"]
+pub trait Sized {}
diff --git a/src/test/rustdoc/intra-doc/primitive-disambiguators.rs b/src/test/rustdoc/intra-doc/primitive-disambiguators.rs
new file mode 100644
index 000000000..adcab767d
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/primitive-disambiguators.rs
@@ -0,0 +1,4 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+// @has primitive_disambiguators/index.html
+// @has - '//a/@href' '{{channel}}/std/primitive.str.html#method.trim'
+//! [str::trim()]
diff --git a/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs
new file mode 100644
index 000000000..474bf3477
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs
@@ -0,0 +1,31 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+
+// @has primitive_non_default_impl/fn.str_methods.html
+/// [`str::trim`]
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.trim"]' 'str::trim'
+/// [`str::to_lowercase`]
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
+/// [`str::into_boxed_bytes`]
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
+/// [`str::replace`]
+// @has - '//*[@href="{{channel}}/std/primitive.str.html#method.replace"]' 'str::replace'
+pub fn str_methods() {}
+
+// @has primitive_non_default_impl/fn.f32_methods.html
+/// [f32::powi]
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.powi"]' 'f32::powi'
+/// [f32::sqrt]
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
+/// [f32::mul_add]
+// @has - '//*[@href="{{channel}}/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
+pub fn f32_methods() {}
+
+// @has primitive_non_default_impl/fn.f64_methods.html
+/// [`f64::powi`]
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.powi"]' 'f64::powi'
+/// [`f64::sqrt`]
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
+/// [`f64::mul_add`]
+// @has - '//*[@href="{{channel}}/std/primitive.f64.html#method.mul_add"]' 'f64::mul_add'
+pub fn f64_methods() {}
diff --git a/src/test/rustdoc/intra-doc/private-failures-ignored.rs b/src/test/rustdoc/intra-doc/private-failures-ignored.rs
new file mode 100644
index 000000000..b272bfb5a
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/private-failures-ignored.rs
@@ -0,0 +1,8 @@
+// Rustdoc would previously report resolution failures on items that weren't in the public docs.
+// These failures were legitimate, but not truly relevant - the docs in question couldn't be
+// checked for accuracy anyway.
+
+#![deny(rustdoc::broken_intra_doc_links)]
+
+/// ooh, i'm a [rebel] just for kicks
+struct SomeStruct;
diff --git a/src/test/rustdoc/intra-doc/private.rs b/src/test/rustdoc/intra-doc/private.rs
new file mode 100644
index 000000000..349091e93
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/private.rs
@@ -0,0 +1,20 @@
+// compile-flags: --document-private-items
+
+// make sure to update `rustdoc-ui/intra-doc/private.rs` if you update this file
+
+#![allow(rustdoc::private_intra_doc_links)]
+
+#![crate_name = "private"]
+
+/// docs [DontDocMe] [DontDocMe::f] [DontDocMe::x]
+// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html"]' 'DontDocMe'
+// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html#method.f"]' 'DontDocMe::f'
+// @has private/struct.DocMe.html '//*a[@href="struct.DontDocMe.html#structfield.x"]' 'DontDocMe::x'
+pub struct DocMe;
+struct DontDocMe {
+ x: usize,
+}
+
+impl DontDocMe {
+ fn f() {}
+}
diff --git a/src/test/rustdoc/intra-doc/proc-macro.rs b/src/test/rustdoc/intra-doc/proc-macro.rs
new file mode 100644
index 000000000..78379a902
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/proc-macro.rs
@@ -0,0 +1,27 @@
+// aux-build:proc-macro-macro.rs
+// build-aux-docs
+#![deny(rustdoc::broken_intra_doc_links)]
+
+extern crate proc_macro_macro;
+
+
+pub use proc_macro_macro::{DeriveA, attr_a};
+use proc_macro_macro::{DeriveB, attr_b};
+
+// @has proc_macro/struct.Foo.html
+// @has - '//a/@href' 'derive.DeriveA.html'
+// @has - '//a/@href' 'attr.attr_a.html'
+// @has - '//a/@href' 'trait.DeriveTrait.html'
+// @has - '//a/@href' '../proc_macro_macro/derive.DeriveB.html'
+// @has - '//a/@href' '../proc_macro_macro/attr.attr_b.html'
+/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait]
+pub struct Foo;
+
+// @has proc_macro/struct.Bar.html
+// @has - '//a/@href' 'derive.DeriveA.html'
+// @has - '//a/@href' 'attr.attr_a.html'
+/// Link to [deriveA](derive@DeriveA) [attr](macro@attr_a)
+pub struct Bar;
+
+// this should not cause ambiguity errors
+pub trait DeriveTrait {}
diff --git a/src/test/rustdoc/intra-doc/pub-use.rs b/src/test/rustdoc/intra-doc/pub-use.rs
new file mode 100644
index 000000000..8a998496c
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/pub-use.rs
@@ -0,0 +1,17 @@
+// aux-build: intra-link-pub-use.rs
+#![deny(rustdoc::broken_intra_doc_links)]
+#![crate_name = "outer"]
+
+extern crate inner;
+
+/// [mod@std::env] [g]
+// @has outer/index.html
+// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env"
+// @has - '//a[@href="fn.f.html"]' "g"
+pub use f as g;
+
+// Make sure the documentation is actually correct by documenting an inlined re-export
+/// [mod@std::env]
+// @has outer/fn.f.html
+// @has - '//a[@href="{{channel}}/std/env/index.html"]' "std::env"
+pub use inner::f;
diff --git a/src/test/rustdoc/intra-doc/raw-ident-self.rs b/src/test/rustdoc/intra-doc/raw-ident-self.rs
new file mode 100644
index 000000000..1ed33db93
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/raw-ident-self.rs
@@ -0,0 +1,13 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+pub mod r#impl {
+ pub struct S;
+
+ impl S {
+ /// See [Self::b].
+ // @has raw_ident_self/impl/struct.S.html
+ // @has - '//a[@href="struct.S.html#method.b"]' 'Self::b'
+ pub fn a() {}
+
+ pub fn b() {}
+ }
+}
diff --git a/src/test/rustdoc/intra-doc/reexport-additional-docs.rs b/src/test/rustdoc/intra-doc/reexport-additional-docs.rs
new file mode 100644
index 000000000..64683bacd
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/reexport-additional-docs.rs
@@ -0,0 +1,23 @@
+// aux-build:intra-link-reexport-additional-docs.rs
+// build-aux-docs
+#![crate_name = "foo"]
+extern crate inner;
+
+// @has foo/struct.Inner.html '//a[@href="fn.with_code.html"]' 'crate::with_code'
+/// [crate::with_code]
+// @has - '//a[@href="fn.with_code.html"]' 'different text'
+/// [different text][with_code]
+// @has - '//a[@href="fn.me_too.html"]' 'me_too'
+#[doc = "[me_too]"]
+// @has - '//a[@href="fn.me_three.html"]' 'reference link'
+/// This [reference link]
+#[doc = "has an attr in the way"]
+///
+/// [reference link]: me_three
+// Should still resolve links from the original module in that scope
+// @has - '//a[@href="../inner/fn.f.html"]' 'f()'
+pub use inner::Inner;
+
+pub fn with_code() {}
+pub fn me_too() {}
+pub fn me_three() {}
diff --git a/src/test/rustdoc/intra-doc/self-cache.rs b/src/test/rustdoc/intra-doc/self-cache.rs
new file mode 100644
index 000000000..63bf7fa57
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/self-cache.rs
@@ -0,0 +1,14 @@
+#![crate_name = "foo"]
+// @has foo/enum.E1.html '//a/@href' 'enum.E1.html#variant.A'
+
+/// [Self::A::b]
+pub enum E1 {
+ A { b: usize }
+}
+
+// @has foo/enum.E2.html '//a/@href' 'enum.E2.html#variant.A'
+
+/// [Self::A::b]
+pub enum E2 {
+ A { b: usize }
+}
diff --git a/src/test/rustdoc/intra-doc/self.rs b/src/test/rustdoc/intra-doc/self.rs
new file mode 100644
index 000000000..0ba7df8a7
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/self.rs
@@ -0,0 +1,116 @@
+#![crate_name = "foo"]
+
+
+// @has foo/index.html '//a/@href' 'struct.Foo.html#method.new'
+// @has foo/struct.Foo.html '//a/@href' 'struct.Foo.html#method.new'
+
+/// Use [`new`] to create a new instance.
+///
+/// [`new`]: Self::new
+pub struct Foo;
+
+impl Foo {
+ pub fn new() -> Self {
+ unimplemented!()
+ }
+}
+
+// @has foo/index.html '//a/@href' 'struct.Bar.html#method.new2'
+// @has foo/struct.Bar.html '//a/@href' 'struct.Bar.html#method.new2'
+
+/// Use [`new2`] to create a new instance.
+///
+/// [`new2`]: Self::new2
+pub struct Bar;
+
+impl Bar {
+ pub fn new2() -> Self {
+ unimplemented!()
+ }
+}
+
+pub struct MyStruct {
+ // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#structfield.struct_field'
+
+ /// [`struct_field`]
+ ///
+ /// [`struct_field`]: Self::struct_field
+ pub struct_field: u8,
+}
+
+pub enum MyEnum {
+ // @has foo/enum.MyEnum.html '//a/@href' 'enum.MyEnum.html#variant.EnumVariant'
+
+ /// [`EnumVariant`]
+ ///
+ /// [`EnumVariant`]: Self::EnumVariant
+ EnumVariant,
+}
+
+pub union MyUnion {
+ // @has foo/union.MyUnion.html '//a/@href' 'union.MyUnion.html#structfield.union_field'
+
+ /// [`union_field`]
+ ///
+ /// [`union_field`]: Self::union_field
+ pub union_field: f32,
+}
+
+pub trait MyTrait {
+ // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#associatedtype.AssoType'
+
+ /// [`AssoType`]
+ ///
+ /// [`AssoType`]: Self::AssoType
+ type AssoType;
+
+ // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#associatedconstant.ASSO_CONST'
+
+ /// [`ASSO_CONST`]
+ ///
+ /// [`ASSO_CONST`]: Self::ASSO_CONST
+ const ASSO_CONST: i32 = 1;
+
+ // @has foo/trait.MyTrait.html '//a/@href' 'trait.MyTrait.html#method.asso_fn'
+
+ /// [`asso_fn`]
+ ///
+ /// [`asso_fn`]: Self::asso_fn
+ fn asso_fn() {}
+}
+
+impl MyStruct {
+ // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.for_impl'
+
+ /// [`for_impl`]
+ ///
+ /// [`for_impl`]: Self::for_impl
+ pub fn for_impl() {
+ unimplemented!()
+ }
+}
+
+impl MyTrait for MyStruct {
+ // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedtype.AssoType'
+
+ /// [`AssoType`]
+ ///
+ /// [`AssoType`]: Self::AssoType
+ type AssoType = u32;
+
+ // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedconstant.ASSO_CONST'
+
+ /// [`ASSO_CONST`]
+ ///
+ /// [`ASSO_CONST`]: Self::ASSO_CONST
+ const ASSO_CONST: i32 = 10;
+
+ // @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.asso_fn'
+
+ /// [`asso_fn`]
+ ///
+ /// [`asso_fn`]: Self::asso_fn
+ fn asso_fn() {
+ unimplemented!()
+ }
+}
diff --git a/src/test/rustdoc/intra-doc/trait-impl.rs b/src/test/rustdoc/intra-doc/trait-impl.rs
new file mode 100644
index 000000000..cf60dc1db
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/trait-impl.rs
@@ -0,0 +1,34 @@
+#![crate_name = "foo"]
+
+
+pub struct MyStruct;
+
+impl MyTrait for MyStruct {
+
+// @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedtype.AssoType'
+
+ /// [`AssoType`]
+ ///
+ /// [`AssoType`]: MyStruct::AssoType
+ type AssoType = u32;
+
+// @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#associatedconstant.ASSO_CONST'
+
+ /// [`ASSO_CONST`]
+ ///
+ /// [`ASSO_CONST`]: MyStruct::ASSO_CONST
+ const ASSO_CONST: i32 = 10;
+
+// @has foo/struct.MyStruct.html '//a/@href' 'struct.MyStruct.html#method.trait_fn'
+
+ /// [`trait_fn`]
+ ///
+ /// [`trait_fn`]: MyStruct::trait_fn
+ fn trait_fn() { }
+}
+
+pub trait MyTrait {
+ type AssoType;
+ const ASSO_CONST: i32 = 1;
+ fn trait_fn();
+}
diff --git a/src/test/rustdoc/intra-doc/trait-item.rs b/src/test/rustdoc/intra-doc/trait-item.rs
new file mode 100644
index 000000000..e95dba33b
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/trait-item.rs
@@ -0,0 +1,11 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+
+/// Link to [S::assoc_fn()]
+/// Link to [Default::default()]
+// @has trait_item/struct.S.html '//*[@href="struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
+// @has - '//*[@href="{{channel}}/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
+pub struct S;
+
+impl S {
+ pub fn assoc_fn() {}
+}
diff --git a/src/test/rustdoc/intra-doc/true-false.rs b/src/test/rustdoc/intra-doc/true-false.rs
new file mode 100644
index 000000000..e02be9cab
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/true-false.rs
@@ -0,0 +1,8 @@
+#![deny(rustdoc::broken_intra_doc_links)]
+#![crate_name = "foo"]
+
+// @has foo/index.html
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'true'
+// @has - '//*[@id="main-content"]//a[@href="{{channel}}/std/primitive.bool.html"]' 'false'
+
+//! A `bool` is either [`true`] or [`false`].
diff --git a/src/test/rustdoc/intra-doc/type-alias.rs b/src/test/rustdoc/intra-doc/type-alias.rs
new file mode 100644
index 000000000..6c52082a2
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/type-alias.rs
@@ -0,0 +1,19 @@
+// Regression test for issue #86120.
+
+#![deny(rustdoc::broken_intra_doc_links)]
+#![crate_name = "foo"]
+
+pub struct Foo;
+
+/// You should really try [`Self::bar`]!
+pub type Bar = Foo;
+
+impl Bar {
+ pub fn bar() {}
+}
+
+/// The minimum is [`Self::MIN`].
+pub type Int = i32;
+
+// @has foo/type.Bar.html '//a[@href="struct.Foo.html#method.bar"]' 'Self::bar'
+// @has foo/type.Int.html '//a[@href="{{channel}}/std/primitive.i32.html#associatedconstant.MIN"]' 'Self::MIN'