about summary refs log tree commit diff
path: root/src/test/rustdoc/intra-doc
diff options
context:
space:
mode:
authorJoshua Nelson <jyn514@gmail.com>2020-11-28 20:25:41 -0500
committerJoshua Nelson <jyn514@gmail.com>2020-11-28 21:13:55 -0500
commitddfb581fb9e04595bc7cdb9d66792fdfdbec67ed (patch)
treeecf43b905627276e664d79d7ab93bba72f899fad /src/test/rustdoc/intra-doc
parente37f25aa3f356546ab851e394d5598fc575eabda (diff)
downloadrust-ddfb581fb9e04595bc7cdb9d66792fdfdbec67ed.tar.gz
rust-ddfb581fb9e04595bc7cdb9d66792fdfdbec67ed.zip
Move `src/test/rustdoc` intra-doc link tests into a subdirectory
They were starting to get unwieldy.
Diffstat (limited to 'src/test/rustdoc/intra-doc')
-rw-r--r--src/test/rustdoc/intra-doc/anchors.rs12
-rw-r--r--src/test/rustdoc/intra-doc/associated-defaults.rs27
-rw-r--r--src/test/rustdoc/intra-doc/associated-items.rs61
-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/my-core.rs19
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs34
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/through-proc-macro-aux.rs20
-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/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.rs12
-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.rs15
-rw-r--r--src/test/rustdoc/intra-doc/disambiguators-removed.rs51
-rw-r--r--src/test/rustdoc/intra-doc/enum-struct-field.rs14
-rw-r--r--src/test/rustdoc/intra-doc/extern-crate.rs9
-rw-r--r--src/test/rustdoc/intra-doc/extern-type.rs17
-rw-r--r--src/test/rustdoc/intra-doc/external-traits.rs12
-rw-r--r--src/test/rustdoc/intra-doc/generic-params.rs62
-rw-r--r--src/test/rustdoc/intra-doc/in-bodies.rs30
-rw-r--r--src/test/rustdoc/intra-doc/libstd-re-export.rs3
-rw-r--r--src/test/rustdoc/intra-doc/mod-ambiguity.rs16
-rw-r--r--src/test/rustdoc/intra-doc/prim-assoc.rs5
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods-external-core.rs18
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods-local.rs28
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods.rs9
-rw-r--r--src/test/rustdoc/intra-doc/prim-precedence.rs17
-rw-r--r--src/test/rustdoc/intra-doc/primitive-non-default-impl.rs32
-rw-r--r--src/test/rustdoc/intra-doc/private-failures-ignored.rs8
-rw-r--r--src/test/rustdoc/intra-doc/private.rs6
-rw-r--r--src/test/rustdoc/intra-doc/proc-macro.rs27
-rw-r--r--src/test/rustdoc/intra-doc/pub-use.rs27
-rw-r--r--src/test/rustdoc/intra-doc/reexport-additional-docs.rs23
-rw-r--r--src/test/rustdoc/intra-doc/self.rs117
-rw-r--r--src/test/rustdoc/intra-doc/through-proc-macro.rs12
-rw-r--r--src/test/rustdoc/intra-doc/trait-impl.rs35
-rw-r--r--src/test/rustdoc/intra-doc/trait-item.rs12
-rw-r--r--src/test/rustdoc/intra-doc/true-false.rs10
56 files changed, 1088 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 00000000000..e4f0c737bdd
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/anchors.rs
@@ -0,0 +1,12 @@
+/// I want...
+///
+/// # Anchor!
+pub struct Something;
+
+// @has anchors/struct.SomeOtherType.html
+// @has - '//a/@href' '../anchors/struct.Something.html#Anchor!'
+
+/// I want...
+///
+/// To link to [Something#Anchor!]
+pub struct SomeOtherType;
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 00000000000..f99d9b5baea
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/associated-defaults.rs
@@ -0,0 +1,27 @@
+// ignore-tidy-linelength
+#![deny(intra_doc_link_resolution_failure)]
+#![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="../associated_defaults/struct.UsesDefaults.html#associatedtype.T"]' 'UsesDefaults::T'
+// @has 'associated_defaults/struct.UsesDefaults.html' '//a[@href="../associated_defaults/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="../associated_defaults/struct.OverridesDefaults.html#associatedtype.T"]' 'OverridesDefaults::T'
+// @has 'associated_defaults/struct.OverridesDefaults.html' '//a[@href="../associated_defaults/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 00000000000..09dfbfcf68a
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/associated-items.rs
@@ -0,0 +1,61 @@
+// ignore-tidy-linelength
+#![deny(intra_doc_link_resolution_failure)]
+
+/// [`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="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter'
+// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from'
+// @has 'associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/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="../associated_items/struct.MyStruct.html"]' 'MyStruct'
+// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html#method.method"]' 'link from struct'
+// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/struct.MyStruct.html#method.clone"]' 'MyStruct::clone'
+// @has 'associated_items/struct.MyStruct.html' '//a[@href="../associated_items/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="../associated_items/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() {}
+}
+
+fn main() {}
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 00000000000..db3bb38ada0
--- /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 00000000000..a4db2ffc445
--- /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 00000000000..fc51995a94e
--- /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 00000000000..6142dcda986
--- /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/my-core.rs b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs
new file mode 100644
index 00000000000..54e986be9ec
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs
@@ -0,0 +1,19 @@
+#![feature(no_core, lang_items)]
+#![no_core]
+#![crate_type="rlib"]
+
+#[lang = "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 00000000000..5ba132f25b4
--- /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/through-proc-macro-aux.rs b/src/test/rustdoc/intra-doc/auxiliary/through-proc-macro-aux.rs
new file mode 100644
index 00000000000..5c4a01ee3a7
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/auxiliary/through-proc-macro-aux.rs
@@ -0,0 +1,20 @@
+// force-host
+// no-prefer-dynamic
+#![crate_type = "proc-macro"]
+#![crate_name="some_macros"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_attribute]
+pub fn first(_attr: TokenStream, item: TokenStream) -> TokenStream {
+    item // This doesn't erase the spans.
+}
+
+#[proc_macro_attribute]
+pub fn second(_attr: TokenStream, item: TokenStream) -> TokenStream {
+    // Make a new `TokenStream` to erase the spans:
+    let mut out: TokenStream = TokenStream::new();
+    out.extend(item);
+    out
+}
diff --git a/src/test/rustdoc/intra-doc/basic.rs b/src/test/rustdoc/intra-doc/basic.rs
new file mode 100644
index 00000000000..7760546e1fa
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/basic.rs
@@ -0,0 +1,84 @@
+// @has basic/index.html
+// @has - '//a/@href' '../basic/struct.ThisType.html'
+// @has - '//a/@href' '../basic/struct.ThisType.html#method.this_method'
+// @has - '//a/@href' '../basic/enum.ThisEnum.html'
+// @has - '//a/@href' '../basic/enum.ThisEnum.html#variant.ThisVariant'
+// @has - '//a/@href' '../basic/trait.ThisTrait.html'
+// @has - '//a/@href' '../basic/trait.ThisTrait.html#tymethod.this_associated_method'
+// @has - '//a/@href' '../basic/trait.ThisTrait.html#associatedtype.ThisAssociatedType'
+// @has - '//a/@href' '../basic/trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST'
+// @has - '//a/@href' '../basic/trait.ThisTrait.html'
+// @has - '//a/@href' '../basic/type.ThisAlias.html'
+// @has - '//a/@href' '../basic/union.ThisUnion.html'
+// @has - '//a/@href' '../basic/fn.this_function.html'
+// @has - '//a/@href' '../basic/constant.THIS_CONST.html'
+// @has - '//a/@href' '../basic/static.THIS_STATIC.html'
+// @has - '//a/@href' '../basic/macro.this_macro.html'
+// @has - '//a/@href' '../basic/trait.SoAmbiguous.html'
+// @has - '//a/@href' '../basic/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' '../basic/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' '../basic/struct.ThisType.html'
+// @has - '//a/@href' '../basic/struct.ThisType.html#method.this_method'
+// @has - '//a/@href' '../basic/enum.ThisEnum.html'
+// @has - '//a/@href' '../basic/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 00000000000..74216a587e1
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/builtin-macros.rs
@@ -0,0 +1,3 @@
+// @has builtin_macros/index.html
+// @has - '//a/@href' 'https://doc.rust-lang.org/nightly/core/macro.cfg.html'
+//! [cfg]
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 00000000000..837390b3c71
--- /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(broken_intra_doc_links)]
+
+extern crate my_rand;
+
+// @has 'additional_doc/trait.Rng.html' '//a[@href="../additional_doc/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 00000000000..849d2568733
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs
@@ -0,0 +1,6 @@
+#![crate_name = "my_rand"]
+#![deny(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 00000000000..b543ae764c0
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs
@@ -0,0 +1,19 @@
+#![crate_name = "hidden_dep"]
+#![deny(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 00000000000..5342baecbc4
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs
@@ -0,0 +1,7 @@
+#![crate_name = "a"]
+#![deny(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 00000000000..a37848e23d9
--- /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 00000000000..a94f9e5dcca
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs
@@ -0,0 +1,10 @@
+#![crate_name = "macro_inner"]
+#![deny(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 00000000000..b7e3913f108
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs
@@ -0,0 +1,7 @@
+#![crate_name = "module_inner"]
+#![deny(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 00000000000..0d5a954075d
--- /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 00000000000..8ae0f6c16b3
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs
@@ -0,0 +1,12 @@
+#![crate_name = "a"]
+#![deny(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 00000000000..d90c529e385
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs
@@ -0,0 +1,13 @@
+#![crate_name = "bar"]
+#![deny(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 00000000000..c16e39d56f3
--- /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 00000000000..6ab9140c3c3
--- /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(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 00000000000..edf544708b6
--- /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 00000000000..9c9d4c64945
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs
@@ -0,0 +1,10 @@
+// aux-build:hidden.rs
+// build-aux-docs
+#![deny(broken_intra_doc_links)]
+
+// tests https://github.com/rust-lang/rust/issues/73363
+
+extern crate hidden_dep;
+
+// @has 'hidden/struct.Ready.html' '//a/@href' '../hidden/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 00000000000..311b16dff13
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/macro.rs
@@ -0,0 +1,12 @@
+// ignore-tidy-linelength
+// aux-build:macro_inner.rs
+// aux-build:proc_macro.rs
+// build-aux-docs
+#![deny(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 00000000000..9039e344f7b
--- /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(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 00000000000..e1465816368
--- /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(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 00000000000..45f561328f2
--- /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(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="../submodule_outer/bar/trait.Bar.html"]' 'Bar'
+// @has 'submodule_outer/trait.Foo.html' '//a[@href="../submodule_outer/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 00000000000..07decb48019
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/cross-crate/traits.rs
@@ -0,0 +1,15 @@
+// aux-build:traits.rs
+// build-aux-docs
+// ignore-tidy-line-length
+#![deny(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 00000000000..aa0ced62aaf
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/disambiguators-removed.rs
@@ -0,0 +1,51 @@
+// ignore-tidy-linelength
+#![deny(intra_doc_link_resolution_failure)]
+// first try backticks
+/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`]
+// @has disambiguators_removed/struct.AtDisambiguator.html
+// @has - '//a[@href="../disambiguators_removed/trait.Name.html"][code]' "Name"
+// @has - '//a[@href="../disambiguators_removed/fn.Name.html"][code]' "Name"
+// @has - '//a[@href="../disambiguators_removed/macro.Name.html"][code]' "Name"
+pub struct AtDisambiguator;
+
+/// fn: [`Name()`], macro: [`Name!`]
+// @has disambiguators_removed/struct.SymbolDisambiguator.html
+// @has - '//a[@href="../disambiguators_removed/fn.Name.html"][code]' "Name()"
+// @has - '//a[@href="../disambiguators_removed/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="../disambiguators_removed/fn.Name.html"]' "Name"
+// @!has - '//a[@href="../disambiguators_removed/fn.Name.html"][code]' "Name"
+
+// FIXME: this will turn !() into ! alone
+/// [Name!()]
+// @has - '//a[@href="../disambiguators_removed/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="../disambiguators_removed/macro.Name.html"]' "Name"
+
+// Try links that have the same text as a generated URL
+/// Weird URL aligned [../disambiguators_removed/macro.Name.html][trait@Name]
+// @has - '//a[@href="../disambiguators_removed/trait.Name.html"]' "../disambiguators_removed/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="../disambiguators_removed/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="../disambiguators_removed/trait.Name.html"]' "trait@Name"
+macro_rules! Name {
+    () => ()
+}
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 00000000000..70bf343a9a5
--- /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' '../foo/enum.Foo.html#variant.X.field.y'
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 00000000000..193bca704bf
--- /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(broken_intra_doc_links)]
+
+extern crate inner;
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 00000000000..e1934698d1f
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/extern-type.rs
@@ -0,0 +1,17 @@
+#![feature(extern_types)]
+
+extern {
+    pub type ExternType;
+}
+
+impl ExternType {
+    pub fn f(&self) {
+
+    }
+}
+
+// @has 'extern_type/foreigntype.ExternType.html'
+// @has 'extern_type/fn.links_to_extern_type.html' \
+// 'href="../extern_type/foreigntype.ExternType.html#method.f"'
+/// See also [ExternType::f]
+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 00000000000..de76f29476c
--- /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(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/generic-params.rs b/src/test/rustdoc/intra-doc/generic-params.rs
new file mode 100644
index 00000000000..1de6410f10c
--- /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="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html"]' 'Vec<T>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html"]' 'Box<Vec<Option<T>>>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/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="https://doc.rust-lang.org/nightly/core/option/enum.Option.html"]' 'just Option'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/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="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, E>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/core/result/enum.Result.html"]' 'Result<T, !>'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/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="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'Vec::<T>::new'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.new"]' 'with parentheses as Vec::<T>::new()'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/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="https://doc.rust-lang.org/nightly/core/any/struct.TypeId.html#method.of"]' 'TypeId::of::<String>()'
+// @has foo/index.html '//a[@href="https://doc.rust-lang.org/nightly/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="https://doc.rust-lang.org/nightly/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/in-bodies.rs b/src/test/rustdoc/intra-doc/in-bodies.rs
new file mode 100644
index 00000000000..ec965a99dc2
--- /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(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/libstd-re-export.rs b/src/test/rustdoc/intra-doc/libstd-re-export.rs
new file mode 100644
index 00000000000..d0af3aec660
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/libstd-re-export.rs
@@ -0,0 +1,3 @@
+#![deny(broken_intra_doc_links)]
+
+pub use std::*;
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 00000000000..feb013b22be
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/mod-ambiguity.rs
@@ -0,0 +1,16 @@
+#![deny(broken_intra_doc_links)]
+
+
+pub fn foo() {
+
+}
+
+pub mod foo {}
+// @has mod_ambiguity/struct.A.html '//a/@href' '../mod_ambiguity/foo/index.html'
+/// Module is [`module@foo`]
+pub struct A;
+
+
+// @has mod_ambiguity/struct.B.html '//a/@href' '../mod_ambiguity/fn.foo.html'
+/// Function is [`fn@foo`]
+pub struct B;
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 00000000000..d687cbd69bb
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-assoc.rs
@@ -0,0 +1,5 @@
+// ignore-tidy-linelength
+#![deny(broken_intra_doc_links)]
+
+//! [i32::MAX]
+// @has prim_assoc/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX"
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 00000000000..434e0338983
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs
@@ -0,0 +1,18 @@
+// aux-build:my-core.rs
+// build-aux-docs
+// ignore-cross-compile
+// ignore-windows
+// ignore-tidy-linelength
+
+#![deny(broken_intra_doc_links)]
+#![feature(no_core, lang_items)]
+#![no_core]
+#![crate_type = "rlib"]
+
+// @has prim_methods_external_core/index.html
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/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 00000000000..9888f29db5b
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-methods-local.rs
@@ -0,0 +1,28 @@
+#![deny(broken_intra_doc_links)]
+#![feature(no_core, lang_items)]
+#![no_core]
+#![crate_type = "rlib"]
+
+// ignore-tidy-linelength
+
+// @has prim_methods_local/index.html
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html#method.len_utf8"]' 'char::len_utf8'
+
+//! A [`char`] and its [`char::len_utf8`].
+
+#[lang = "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 00000000000..f19cff7d34a
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-methods.rs
@@ -0,0 +1,9 @@
+#![deny(broken_intra_doc_links)]
+
+// ignore-tidy-linelength
+
+// @has prim_methods/index.html
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.char.html"]' 'char'
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/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 00000000000..ed2c2cda718
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/prim-precedence.rs
@@ -0,0 +1,17 @@
+// ignore-tidy-linelength
+#![deny(broken_intra_doc_links)]
+
+pub mod char {
+    /// [char]
+    // @has prim_precedence/char/struct.Inner.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
+    pub struct Inner;
+}
+
+/// See [prim@char]
+// @has prim_precedence/struct.MyString.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
+pub struct MyString;
+
+/// See also [crate::char] and [mod@char]
+// @has prim_precedence/struct.MyString2.html '//*[@href="../prim_precedence/char/index.html"]' 'crate::char'
+// @has - '//*[@href="../prim_precedence/char/index.html"]' 'mod@char'
+pub struct MyString2;
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 00000000000..548eb090a32
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs
@@ -0,0 +1,32 @@
+#![deny(broken_intra_doc_links)]
+
+// ignore-tidy-linelength
+
+// @has primitive_non_default_impl/fn.str_methods.html
+/// [`str::trim`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.trim"]' 'str::trim'
+/// [`str::to_lowercase`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_lowercase"]' 'str::to_lowercase'
+/// [`str::into_boxed_bytes`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.into_boxed_bytes"]' 'str::into_boxed_bytes'
+/// [`str::replace`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/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="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.powi"]' 'f32::powi'
+/// [f32::sqrt]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.sqrt"]' 'f32::sqrt'
+/// [f32::mul_add]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/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="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.powi"]' 'f64::powi'
+/// [`f64::sqrt`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f64.html#method.sqrt"]' 'f64::sqrt'
+/// [`f64::mul_add`]
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/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 00000000000..cf8bc0b1586
--- /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(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 00000000000..f86ca44403d
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/private.rs
@@ -0,0 +1,6 @@
+#![crate_name = "private"]
+// compile-flags: --document-private-items
+/// docs [DontDocMe]
+// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html"]' 'DontDocMe'
+pub struct DocMe;
+struct DontDocMe;
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 00000000000..ab4626ccfc3
--- /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(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' '../proc_macro/derive.DeriveA.html'
+// @has - '//a/@href' '../proc_macro/attr.attr_a.html'
+// @has - '//a/@href' '../proc_macro/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' '../proc_macro/derive.DeriveA.html'
+// @has - '//a/@href' '../proc_macro/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 00000000000..dd52249abc6
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/pub-use.rs
@@ -0,0 +1,27 @@
+// aux-build: intra-link-pub-use.rs
+#![deny(broken_intra_doc_links)]
+#![crate_name = "outer"]
+
+extern crate inner;
+
+/// [mod@std::env] [g]
+
+// FIXME: This can't be tested because rustdoc doesn't show documentation on pub re-exports.
+// Until then, comment out the `htmldocck` test.
+// This test still does something; namely check that no incorrect errors are emitted when
+// documenting the re-export.
+
+// @has outer/index.html
+// @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/fn.var.html"]' "std::env"
+// @ has - '//a[@href="../outer/fn.f.html"]' "g"
+pub use f as g;
+
+// FIXME: same as above
+/// [std::env]
+extern crate self as _;
+
+// Make sure the documentation is actually correct by documenting an inlined re-export
+/// [mod@std::env]
+// @has outer/fn.f.html
+// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/index.html"]' "std::env"
+pub use inner::f;
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 00000000000..96f3580f305
--- /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="../foo/fn.with_code.html"]' 'crate::with_code'
+/// [crate::with_code]
+// @has - '//a[@href="../foo/fn.with_code.html"]' 'different text'
+/// [different text][with_code]
+// @has - '//a[@href="../foo/fn.me_too.html"]' 'me_too'
+#[doc = "[me_too]"]
+// @has - '//a[@href="../foo/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.rs b/src/test/rustdoc/intra-doc/self.rs
new file mode 100644
index 00000000000..81545fec741
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/self.rs
@@ -0,0 +1,117 @@
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+// @has foo/index.html '//a/@href' '../foo/struct.Foo.html#method.new'
+// @has foo/struct.Foo.html '//a/@href' '../foo/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' '../foo/struct.Bar.html#method.new2'
+// @has foo/struct.Bar.html '//a/@href' '../foo/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' '../foo/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' '../foo/enum.MyEnum.html#variant.EnumVariant'
+
+    /// [`EnumVariant`]
+    ///
+    /// [`EnumVariant`]: Self::EnumVariant
+    EnumVariant,
+}
+
+pub union MyUnion {
+    // @has foo/union.MyUnion.html '//a/@href' '../foo/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' '../foo/trait.MyTrait.html#associatedtype.AssoType'
+
+    /// [`AssoType`]
+    ///
+    /// [`AssoType`]: Self::AssoType
+    type AssoType;
+
+    // @has foo/trait.MyTrait.html '//a/@href' '../foo/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' '../foo/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' '../foo/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' '../foo/struct.MyStruct.html#associatedtype.AssoType'
+
+    /// [`AssoType`]
+    ///
+    /// [`AssoType`]: Self::AssoType
+    type AssoType = u32;
+
+    // @has foo/struct.MyStruct.html '//a/@href' '../foo/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' '../foo/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/through-proc-macro.rs b/src/test/rustdoc/intra-doc/through-proc-macro.rs
new file mode 100644
index 00000000000..613410871f0
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/through-proc-macro.rs
@@ -0,0 +1,12 @@
+// aux-build:through-proc-macro-aux.rs
+// build-aux-docs
+#![warn(broken_intra_doc_links)]
+extern crate some_macros;
+
+#[some_macros::second]
+pub enum Boom {
+    /// [Oooops]
+    Bam,
+}
+
+fn main() {}
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 00000000000..fab8406d525
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/trait-impl.rs
@@ -0,0 +1,35 @@
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+pub struct MyStruct;
+
+impl MyTrait for MyStruct {
+
+// @has foo/struct.MyStruct.html '//a/@href' '../foo/struct.MyStruct.html#associatedtype.AssoType'
+
+    /// [`AssoType`]
+    ///
+    /// [`AssoType`]: MyStruct::AssoType
+    type AssoType = u32;
+
+// @has foo/struct.MyStruct.html '//a/@href' '../foo/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' '../foo/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 00000000000..de8585f4c9a
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/trait-item.rs
@@ -0,0 +1,12 @@
+// ignore-tidy-linelength
+#![deny(broken_intra_doc_links)]
+
+/// Link to [S::assoc_fn()]
+/// Link to [Default::default()]
+// @has trait_item/struct.S.html '//*[@href="../trait_item/struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/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 00000000000..7b21e934147
--- /dev/null
+++ b/src/test/rustdoc/intra-doc/true-false.rs
@@ -0,0 +1,10 @@
+#![deny(broken_intra_doc_links)]
+#![crate_name = "foo"]
+
+// ignore-tidy-linelength
+
+// @has foo/index.html
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'true'
+// @has - '//*[@id="main"]//a[@href="https://doc.rust-lang.org/nightly/std/primitive.bool.html"]' 'false'
+
+//! A `bool` is either [`true`] or [`false`].