about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-12-01 12:15:10 +0000
committerbors <bors@rust-lang.org>2020-12-01 12:15:10 +0000
commitb2dd82929b5b956972446d9720ceabdee171d405 (patch)
tree0aab2888533c6ce4c1c3c3a0f5f66fdbc3625cef
parent0fa9d31c41cfa5f60dbce1204104eb8d8261be5f (diff)
parentc06a00e21d93e000e2fa17eba66159240e08dfae (diff)
downloadrust-b2dd82929b5b956972446d9720ceabdee171d405.tar.gz
rust-b2dd82929b5b956972446d9720ceabdee171d405.zip
Auto merge of #79596 - m-ou-se:rollup-hujx3c7, r=m-ou-se
Rollup of 11 pull requests

Successful merges:

 - #79038 (Change ui test that are run-pass and that do not test the compiler to library tests)
 - #79184 (Stop adding '*' at the end of slice and str typenames for MSVC case)
 - #79227 (Remove const_fn_feature_flags test)
 - #79444 (Move const ip in ui test to unit test)
 - #79522 (Validate lint docs separately.)
 - #79525 (Add -Z normalize-docs and enable it for compiler docs)
 - #79527 (Move intra-doc link tests into a subdirectory)
 - #79548 (Show since when a function is const in stdlib)
 - #79568 (update Miri)
 - #79573 (Update with status for various NetBSD ports.)
 - #79583 (Update books)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs9
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs24
-rw-r--r--compiler/rustc_session/src/options.rs2
-rw-r--r--library/alloc/tests/str.rs96
-rw-r--r--library/core/tests/ascii.rs53
-rw-r--r--library/core/tests/atomic.rs79
-rw-r--r--library/core/tests/bool.rs84
-rw-r--r--library/core/tests/cmp.rs71
-rw-r--r--library/core/tests/iter.rs12
-rw-r--r--library/core/tests/lib.rs4
-rw-r--r--library/core/tests/macros.rs14
-rw-r--r--library/core/tests/num/wrapping.rs233
-rw-r--r--library/core/tests/ops.rs33
-rw-r--r--library/core/tests/option.rs10
-rw-r--r--library/core/tests/ptr.rs13
-rw-r--r--library/core/tests/result.rs38
-rw-r--r--library/core/tests/unicode.rs5
-rw-r--r--library/std/src/net/ip/tests.rs6
-rw-r--r--library/std/tests/env.rs61
-rw-r--r--library/std/tests/thread.rs (renamed from src/test/ui/sleep.rs)15
-rw-r--r--src/bootstrap/builder.rs2
-rw-r--r--src/bootstrap/doc.rs6
-rw-r--r--src/bootstrap/test.rs66
m---------src/doc/book0
m---------src/doc/embedded-book0
m---------src/doc/nomicon0
m---------src/doc/reference0
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustc/src/platform-support.md8
-rw-r--r--src/librustdoc/clean/auto_trait.rs1
-rw-r--r--src/librustdoc/clean/blanket_impl.rs1
-rw-r--r--src/librustdoc/clean/inline.rs1
-rw-r--r--src/librustdoc/clean/mod.rs10
-rw-r--r--src/librustdoc/clean/types.rs11
-rw-r--r--src/librustdoc/html/render/mod.rs90
-rw-r--r--src/test/rustdoc-ui/.gitattributes1
-rw-r--r--src/test/rustdoc-ui/intra-doc/.gitattributes1
-rw-r--r--src/test/rustdoc-ui/intra-doc/alias-ice.rs (renamed from src/test/rustdoc-ui/intra-doc-alias-ice.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/alias-ice.stderr (renamed from src/test/rustdoc-ui/intra-doc-alias-ice.stderr)4
-rw-r--r--src/test/rustdoc-ui/intra-doc/ambiguity.rs (renamed from src/test/rustdoc-ui/intra-links-ambiguity.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/ambiguity.stderr (renamed from src/test/rustdoc-ui/intra-links-ambiguity.stderr)14
-rw-r--r--src/test/rustdoc-ui/intra-doc/anchors.rs (renamed from src/test/rustdoc-ui/intra-links-anchors.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/anchors.stderr (renamed from src/test/rustdoc-ui/intra-links-anchors.stderr)10
-rw-r--r--src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs (renamed from src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/broken-reexport.rs (renamed from src/test/rustdoc-ui/intra-doc-broken-reexport.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs (renamed from src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr (renamed from src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr)24
-rw-r--r--src/test/rustdoc-ui/intra-doc/double-anchor.rs (renamed from src/test/rustdoc-ui/intra-link-double-anchor.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/double-anchor.stderr (renamed from src/test/rustdoc-ui/intra-link-double-anchor.stderr)2
-rw-r--r--src/test/rustdoc-ui/intra-doc/errors.rs (renamed from src/test/rustdoc-ui/intra-link-errors.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/errors.stderr (renamed from src/test/rustdoc-ui/intra-link-errors.stderr)42
-rw-r--r--src/test/rustdoc-ui/intra-doc/malformed-generics.rs (renamed from src/test/rustdoc-ui/intra-link-malformed-generics.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/malformed-generics.stderr (renamed from src/test/rustdoc-ui/intra-link-malformed-generics.stderr)32
-rw-r--r--src/test/rustdoc-ui/intra-doc/prim-conflict.rs (renamed from src/test/rustdoc-ui/intra-link-prim-conflict.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/prim-conflict.stderr (renamed from src/test/rustdoc-ui/intra-link-prim-conflict.stderr)10
-rw-r--r--src/test/rustdoc-ui/intra-doc/private.private.stderr (renamed from src/test/rustdoc-ui/intra-links-private.private.stderr)2
-rw-r--r--src/test/rustdoc-ui/intra-doc/private.public.stderr (renamed from src/test/rustdoc-ui/intra-links-private.public.stderr)2
-rw-r--r--src/test/rustdoc-ui/intra-doc/private.rs (renamed from src/test/rustdoc-ui/intra-links-private.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/span-ice-55723.rs (renamed from src/test/rustdoc-ui/intra-link-span-ice-55723.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr (renamed from src/test/rustdoc-ui/intra-link-span-ice-55723.stderr)4
-rw-r--r--src/test/rustdoc-ui/intra-doc/warning-crlf.rs (renamed from src/test/rustdoc-ui/intra-links-warning-crlf.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/warning-crlf.stderr (renamed from src/test/rustdoc-ui/intra-links-warning-crlf.stderr)8
-rw-r--r--src/test/rustdoc-ui/intra-doc/warning.rs (renamed from src/test/rustdoc-ui/intra-links-warning.rs)0
-rw-r--r--src/test/rustdoc-ui/intra-doc/warning.stderr (renamed from src/test/rustdoc-ui/intra-links-warning.stderr)38
-rw-r--r--src/test/rustdoc/const-display.rs10
-rw-r--r--src/test/rustdoc/intra-doc-link-mod-ambiguity.rs18
-rw-r--r--src/test/rustdoc/intra-doc/anchors.rs (renamed from src/test/rustdoc/intra-links-anchors.rs)4
-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.rs (renamed from src/test/rustdoc/auxiliary/intra-link-extern-crate.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs (renamed from src/test/rustdoc/auxiliary/intra-link-pub-use.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs (renamed from src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs (renamed from src/test/rustdoc/auxiliary/intra-links-external-traits.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/my-core.rs (renamed from src/test/rustdoc/auxiliary/my-core.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs (renamed from src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs)1
-rw-r--r--src/test/rustdoc/intra-doc/auxiliary/through-proc-macro-aux.rs (renamed from src/test/rustdoc/auxiliary/through-proc-macro-aux.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/basic.rs (renamed from src/test/rustdoc/intra-links.rs)46
-rw-r--r--src/test/rustdoc/intra-doc/builtin-macros.rs (renamed from src/test/rustdoc/intra-link-builtin-macros.rs)2
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs (renamed from src/test/rustdoc/intra-doc-crate/additional_doc.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs (renamed from src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs (renamed from src/test/rustdoc/intra-doc-crate/auxiliary/hidden.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs (renamed from src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs (renamed from src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs (renamed from src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs (renamed from src/test/rustdoc/intra-doc-crate/auxiliary/module.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs (renamed from src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs (renamed from src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs (renamed from src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs (renamed from src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/basic.rs (renamed from src/test/rustdoc/intra-doc-crate/basic.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/crate.rs (renamed from src/test/rustdoc/intra-link-cross-crate-crate.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/hidden.rs (renamed from src/test/rustdoc/intra-doc-crate/hidden.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/macro.rs (renamed from src/test/rustdoc/intra-doc-crate/macro.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/module.rs (renamed from src/test/rustdoc/intra-doc-crate/module.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs (renamed from src/test/rustdoc/intra-doc-crate/submodule-inner.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs (renamed from src/test/rustdoc/intra-doc-crate/submodule-outer.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/cross-crate/traits.rs (renamed from src/test/rustdoc/intra-doc-crate/traits.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/disambiguators-removed.rs51
-rw-r--r--src/test/rustdoc/intra-doc/enum-struct-field.rs (renamed from src/test/rustdoc/intra-doc-link-enum-struct-field.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/extern-crate.rs (renamed from src/test/rustdoc/intra-link-extern-crate.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/extern-type.rs17
-rw-r--r--src/test/rustdoc/intra-doc/external-traits.rs (renamed from src/test/rustdoc/intra-links-external-traits.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/generic-params.rs (renamed from src/test/rustdoc/intra-doc-link-generic-params.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/in-bodies.rs (renamed from src/test/rustdoc/intra-link-in-bodies.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/libstd-re-export.rs (renamed from src/test/rustdoc/intra-link-libstd-re-export.rs)0
-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.rs (renamed from src/test/rustdoc/intra-link-prim-methods-external-core.rs)2
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods-local.rs (renamed from src/test/rustdoc/intra-link-prim-methods-local.rs)2
-rw-r--r--src/test/rustdoc/intra-doc/prim-methods.rs (renamed from src/test/rustdoc/intra-link-prim-methods.rs)2
-rw-r--r--src/test/rustdoc/intra-doc/prim-precedence.rs17
-rw-r--r--src/test/rustdoc/intra-doc/primitive-non-default-impl.rs (renamed from src/test/rustdoc/intra-link-primitive-non-default-impl.rs)6
-rw-r--r--src/test/rustdoc/intra-doc/private-failures-ignored.rs (renamed from src/test/rustdoc/intra-link-private.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/private.rs (renamed from src/test/rustdoc/intra-doc-link-private.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/proc-macro.rs27
-rw-r--r--src/test/rustdoc/intra-doc/pub-use.rs (renamed from src/test/rustdoc/intra-link-pub-use.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/reexport-additional-docs.rs (renamed from src/test/rustdoc/intra-link-reexport-additional-docs.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/self.rs (renamed from src/test/rustdoc/intra-link-self.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/through-proc-macro.rs (renamed from src/test/rustdoc/through-proc-macro.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/trait-impl.rs (renamed from src/test/rustdoc/intra-link-trait-impl.rs)0
-rw-r--r--src/test/rustdoc/intra-doc/trait-item.rs (renamed from src/test/rustdoc/intra-link-trait-item.rs)2
-rw-r--r--src/test/rustdoc/intra-doc/true-false.rs (renamed from src/test/rustdoc/intra-doc-link-true-false.rs)0
-rw-r--r--src/test/rustdoc/intra-link-associated-defaults.rs27
-rw-r--r--src/test/rustdoc/intra-link-associated-items.rs61
-rw-r--r--src/test/rustdoc/intra-link-disambiguators-removed.rs51
-rw-r--r--src/test/rustdoc/intra-link-extern-type.rs18
-rw-r--r--src/test/rustdoc/intra-link-prim-assoc.rs5
-rw-r--r--src/test/rustdoc/intra-link-prim-precedence.rs17
-rw-r--r--src/test/rustdoc/intra-link-proc-macro.rs27
-rw-r--r--src/test/rustdoc/normalize-assoc-item.rs2
-rw-r--r--src/test/ui/assert-eq-trailing-comma.rs5
-rw-r--r--src/test/ui/assert-escape.rs5
-rw-r--r--src/test/ui/assert-ne-trailing-comma.rs5
-rw-r--r--src/test/ui/atomic-access-bool.rs24
-rw-r--r--src/test/ui/atomic-alignment.rs38
-rw-r--r--src/test/ui/atomic-compare_exchange.rs31
-rw-r--r--src/test/ui/bool-not.rs6
-rw-r--r--src/test/ui/bool.rs72
-rw-r--r--src/test/ui/char_unicode.rs10
-rw-r--r--src/test/ui/cmp-default.rs73
-rw-r--r--src/test/ui/consts/ascii_ctype.rs53
-rw-r--r--src/test/ui/consts/const-fn-feature-flags.rs13
-rw-r--r--src/test/ui/consts/const-str-ptr.rs17
-rw-r--r--src/test/ui/consts/std/net/ip.rs13
-rw-r--r--src/test/ui/deref-mut-on-ref.rs15
-rw-r--r--src/test/ui/deref-on-ref.rs19
-rw-r--r--src/test/ui/env-home-dir.rs50
-rw-r--r--src/test/ui/extend-for-unit.rs12
-rw-r--r--src/test/ui/offset_from.rs13
-rw-r--r--src/test/ui/option-ext.rs10
-rw-r--r--src/test/ui/result-opt-conversions.rs47
-rw-r--r--src/test/ui/utf8.rs50
-rw-r--r--src/test/ui/utf8_chars.rs31
-rw-r--r--src/test/ui/wrapping-int-api.rs225
-rw-r--r--src/tools/lint-docs/src/groups.rs203
-rw-r--r--src/tools/lint-docs/src/lib.rs756
-rw-r--r--src/tools/lint-docs/src/main.rs33
m---------src/tools/miri24
159 files changed, 1888 insertions, 1742 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 18dfe890a0c..ce1f705bdff 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2131,6 +2131,7 @@ dependencies = [
  "rustc-workspace-hack",
  "rustc_version",
  "shell-escape",
+ "smallvec 1.4.2",
 ]
 
 [[package]]
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index 896af8a9191..d1bbf74307c 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -94,7 +94,14 @@ pub fn push_debuginfo_type_name<'tcx>(
             push_debuginfo_type_name(tcx, inner_type, true, output, visited);
 
             if cpp_like_names {
-                output.push('*');
+                // Slices and `&str` are treated like C++ pointers when computing debug
+                // info for MSVC debugger. However, adding '*' at the end of these types' names
+                // causes the .natvis engine for WinDbg to fail to display their data, so we opt these
+                // types out to aid debugging in MSVC.
+                match *inner_type.kind() {
+                    ty::Slice(_) | ty::Str => {}
+                    _ => output.push('*'),
+                }
             }
         }
         ty::Array(inner_type, len) => {
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index af9926400ca..aec0fc253ca 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -366,11 +366,25 @@ impl LintBuffer {
 /// ```
 ///
 /// The `{{produces}}` tag will be automatically replaced with the output from
-/// the example by the build system. You can build and view the rustc book
-/// with `x.py doc --stage=1 src/doc/rustc --open`. If the lint example is too
-/// complex to run as a simple example (for example, it needs an extern
-/// crate), mark it with `ignore` and manually paste the expected output below
-/// the example.
+/// the example by the build system. If the lint example is too complex to run
+/// as a simple example (for example, it needs an extern crate), mark the code
+/// block with `ignore` and manually replace the `{{produces}}` line with the
+/// expected output in a `text` code block.
+///
+/// If this is a rustdoc-only lint, then only include a brief introduction
+/// with a link with the text `[rustdoc book]` so that the validator knows
+/// that this is for rustdoc only (see BROKEN_INTRA_DOC_LINKS as an example).
+///
+/// Commands to view and test the documentation:
+///
+/// * `./x.py doc --stage=1 src/doc/rustc --open`: Builds the rustc book and opens it.
+/// * `./x.py test src/tools/lint-docs`: Validates that the lint docs have the
+///   correct style, and that the code example actually emits the expected
+///   lint.
+///
+/// If you have already built the compiler, and you want to make changes to
+/// just the doc comments, then use the `--keep-stage=0` flag with the above
+/// commands to avoid rebuilding the compiler.
 #[macro_export]
 macro_rules! declare_lint {
     ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index b438be0696a..66c709b4080 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -996,6 +996,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
         "run LLVM in non-parallel mode (while keeping codegen-units and ThinLTO)"),
     no_profiler_runtime: bool = (false, parse_no_flag, [TRACKED],
         "prevent automatic injection of the profiler_builtins crate"),
+    normalize_docs: bool = (false, parse_bool, [TRACKED],
+        "normalize associated items in rustdoc when generating documentation"),
     osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
         "pass `-install_name @rpath/...` to the macOS linker (default: no)"),
     panic_abort_tests: bool = (false, parse_bool, [TRACKED],
diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs
index 834dd4656ff..b1301914656 100644
--- a/library/alloc/tests/str.rs
+++ b/library/alloc/tests/str.rs
@@ -1,6 +1,6 @@
 use std::borrow::Cow;
 use std::cmp::Ordering::{Equal, Greater, Less};
-use std::str::from_utf8;
+use std::str::{from_utf8, from_utf8_unchecked};
 
 #[test]
 fn test_le() {
@@ -1971,3 +1971,97 @@ fn test_str_escapes() {
     ";
     assert_eq!(x, r"\\"); // extraneous whitespace stripped
 }
+
+#[test]
+fn const_str_ptr() {
+    const A: [u8; 2] = ['h' as u8, 'i' as u8];
+    const B: &'static [u8; 2] = &A;
+    const C: *const u8 = B as *const u8;
+
+    unsafe {
+        let foo = &A as *const u8;
+        assert_eq!(foo, C);
+        assert_eq!(from_utf8_unchecked(&A), "hi");
+        assert_eq!(*C, A[0]);
+        assert_eq!(*(&B[0] as *const u8), A[0]);
+    }
+}
+
+#[test]
+fn utf8() {
+    let yen: char = '¥'; // 0xa5
+    let c_cedilla: char = 'ç'; // 0xe7
+    let thorn: char = 'þ'; // 0xfe
+    let y_diaeresis: char = 'ÿ'; // 0xff
+    let pi: char = 'Π'; // 0x3a0
+
+    assert_eq!(yen as isize, 0xa5);
+    assert_eq!(c_cedilla as isize, 0xe7);
+    assert_eq!(thorn as isize, 0xfe);
+    assert_eq!(y_diaeresis as isize, 0xff);
+    assert_eq!(pi as isize, 0x3a0);
+
+    assert_eq!(pi as isize, '\u{3a0}' as isize);
+    assert_eq!('\x0a' as isize, '\n' as isize);
+
+    let bhutan: String = "འབྲུག་ཡུལ།".to_string();
+    let japan: String = "日本".to_string();
+    let uzbekistan: String = "Ўзбекистон".to_string();
+    let austria: String = "Österreich".to_string();
+
+    let bhutan_e: String =
+        "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string();
+    let japan_e: String = "\u{65e5}\u{672c}".to_string();
+    let uzbekistan_e: String =
+        "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string();
+    let austria_e: String = "\u{d6}sterreich".to_string();
+
+    let oo: char = 'Ö';
+    assert_eq!(oo as isize, 0xd6);
+
+    fn check_str_eq(a: String, b: String) {
+        let mut i: isize = 0;
+        for ab in a.bytes() {
+            println!("{}", i);
+            println!("{}", ab);
+            let bb: u8 = b.as_bytes()[i as usize];
+            println!("{}", bb);
+            assert_eq!(ab, bb);
+            i += 1;
+        }
+    }
+
+    check_str_eq(bhutan, bhutan_e);
+    check_str_eq(japan, japan_e);
+    check_str_eq(uzbekistan, uzbekistan_e);
+    check_str_eq(austria, austria_e);
+}
+
+#[test]
+fn utf8_chars() {
+    // Chars of 1, 2, 3, and 4 bytes
+    let chs: Vec<char> = vec!['e', 'é', '€', '\u{10000}'];
+    let s: String = chs.iter().cloned().collect();
+    let schs: Vec<char> = s.chars().collect();
+
+    assert_eq!(s.len(), 10);
+    assert_eq!(s.chars().count(), 4);
+    assert_eq!(schs.len(), 4);
+    assert_eq!(schs.iter().cloned().collect::<String>(), s);
+
+    assert!((from_utf8(s.as_bytes()).is_ok()));
+    // invalid prefix
+    assert!((!from_utf8(&[0x80]).is_ok()));
+    // invalid 2 byte prefix
+    assert!((!from_utf8(&[0xc0]).is_ok()));
+    assert!((!from_utf8(&[0xc0, 0x10]).is_ok()));
+    // invalid 3 byte prefix
+    assert!((!from_utf8(&[0xe0]).is_ok()));
+    assert!((!from_utf8(&[0xe0, 0x10]).is_ok()));
+    assert!((!from_utf8(&[0xe0, 0xff, 0x10]).is_ok()));
+    // invalid 4 byte prefix
+    assert!((!from_utf8(&[0xf0]).is_ok()));
+    assert!((!from_utf8(&[0xf0, 0x10]).is_ok()));
+    assert!((!from_utf8(&[0xf0, 0xff, 0x10]).is_ok()));
+    assert!((!from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()));
+}
diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs
index 3244bbc2d67..66c25e449df 100644
--- a/library/core/tests/ascii.rs
+++ b/library/core/tests/ascii.rs
@@ -408,3 +408,56 @@ fn ascii_const() {
     const BYTE_IS_ASCII: bool = 97u8.is_ascii();
     assert!(BYTE_IS_ASCII);
 }
+
+#[test]
+fn ascii_ctype_const() {
+    macro_rules! suite {
+        ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => {
+            $(
+                mod $fn {
+                    const CHAR_A_LOWER: bool = 'a'.$fn();
+                    const CHAR_A_UPPER: bool = 'A'.$fn();
+                    const CHAR_NINE: bool = '9'.$fn();
+                    const CHAR_DOT: bool = '.'.$fn();
+                    const CHAR_SPACE: bool = ' '.$fn();
+
+                    const U8_A_LOWER: bool = b'a'.$fn();
+                    const U8_A_UPPER: bool = b'A'.$fn();
+                    const U8_NINE: bool = b'9'.$fn();
+                    const U8_DOT: bool = b'.'.$fn();
+                    const U8_SPACE: bool = b' '.$fn();
+
+                    pub fn run() {
+                        assert_eq!(CHAR_A_LOWER, $a);
+                        assert_eq!(CHAR_A_UPPER, $A);
+                        assert_eq!(CHAR_NINE, $nine);
+                        assert_eq!(CHAR_DOT, $dot);
+                        assert_eq!(CHAR_SPACE, $space);
+
+                        assert_eq!(U8_A_LOWER, $a);
+                        assert_eq!(U8_A_UPPER, $A);
+                        assert_eq!(U8_NINE, $nine);
+                        assert_eq!(U8_DOT, $dot);
+                        assert_eq!(U8_SPACE, $space);
+                    }
+                }
+            )*
+
+            $( $fn::run(); )*
+        }
+    }
+
+    suite! {
+        //                        'a'    'A'    '9'    '.'    ' '
+        is_ascii_alphabetic   => [true,  true,  false, false, false];
+        is_ascii_uppercase    => [false, true,  false, false, false];
+        is_ascii_lowercase    => [true,  false, false, false, false];
+        is_ascii_alphanumeric => [true,  true,  true,  false, false];
+        is_ascii_digit        => [false, false, true,  false, false];
+        is_ascii_hexdigit     => [true,  true,  true,  false, false];
+        is_ascii_punctuation  => [false, false, false, true,  false];
+        is_ascii_graphic      => [true,  true,  true,  true,  false];
+        is_ascii_whitespace   => [false, false, false, false, true];
+        is_ascii_control      => [false, false, false, false, false];
+    }
+}
diff --git a/library/core/tests/atomic.rs b/library/core/tests/atomic.rs
index acbd913982c..75528ebb54e 100644
--- a/library/core/tests/atomic.rs
+++ b/library/core/tests/atomic.rs
@@ -101,3 +101,82 @@ fn static_init() {
     assert!(S_INT.fetch_add(1, SeqCst) == 0);
     assert!(S_UINT.fetch_add(1, SeqCst) == 0);
 }
+
+#[test]
+fn atomic_access_bool() {
+    static mut ATOMIC: AtomicBool = AtomicBool::new(false);
+
+    unsafe {
+        assert_eq!(*ATOMIC.get_mut(), false);
+        ATOMIC.store(true, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), true);
+        ATOMIC.fetch_or(false, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), true);
+        ATOMIC.fetch_and(false, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), false);
+        ATOMIC.fetch_nand(true, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), true);
+        ATOMIC.fetch_xor(true, SeqCst);
+        assert_eq!(*ATOMIC.get_mut(), false);
+    }
+}
+
+#[test]
+fn atomic_alignment() {
+    use std::mem::{align_of, size_of};
+
+    #[cfg(target_has_atomic = "8")]
+    assert_eq!(align_of::<AtomicBool>(), size_of::<AtomicBool>());
+    #[cfg(target_has_atomic = "ptr")]
+    assert_eq!(align_of::<AtomicPtr<u8>>(), size_of::<AtomicPtr<u8>>());
+    #[cfg(target_has_atomic = "8")]
+    assert_eq!(align_of::<AtomicU8>(), size_of::<AtomicU8>());
+    #[cfg(target_has_atomic = "8")]
+    assert_eq!(align_of::<AtomicI8>(), size_of::<AtomicI8>());
+    #[cfg(target_has_atomic = "16")]
+    assert_eq!(align_of::<AtomicU16>(), size_of::<AtomicU16>());
+    #[cfg(target_has_atomic = "16")]
+    assert_eq!(align_of::<AtomicI16>(), size_of::<AtomicI16>());
+    #[cfg(target_has_atomic = "32")]
+    assert_eq!(align_of::<AtomicU32>(), size_of::<AtomicU32>());
+    #[cfg(target_has_atomic = "32")]
+    assert_eq!(align_of::<AtomicI32>(), size_of::<AtomicI32>());
+    #[cfg(target_has_atomic = "64")]
+    assert_eq!(align_of::<AtomicU64>(), size_of::<AtomicU64>());
+    #[cfg(target_has_atomic = "64")]
+    assert_eq!(align_of::<AtomicI64>(), size_of::<AtomicI64>());
+    #[cfg(target_has_atomic = "128")]
+    assert_eq!(align_of::<AtomicU128>(), size_of::<AtomicU128>());
+    #[cfg(target_has_atomic = "128")]
+    assert_eq!(align_of::<AtomicI128>(), size_of::<AtomicI128>());
+    #[cfg(target_has_atomic = "ptr")]
+    assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
+    #[cfg(target_has_atomic = "ptr")]
+    assert_eq!(align_of::<AtomicIsize>(), size_of::<AtomicIsize>());
+}
+
+#[test]
+fn atomic_compare_exchange() {
+    use Ordering::*;
+
+    static ATOMIC: AtomicIsize = AtomicIsize::new(0);
+
+    ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok();
+    ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok();
+    ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok();
+    ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok();
+    ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok();
+    ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok();
+    ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok();
+    ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok();
+    ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok();
+    ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok();
+    ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok();
+    ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok();
+    ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok();
+    ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok();
+    ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok();
+    ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok();
+    ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok();
+    ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok();
+}
diff --git a/library/core/tests/bool.rs b/library/core/tests/bool.rs
index e89eb2c7f94..e40f0482aee 100644
--- a/library/core/tests/bool.rs
+++ b/library/core/tests/bool.rs
@@ -1,3 +1,87 @@
+use core::cmp::Ordering::{Equal, Greater, Less};
+use core::ops::{BitAnd, BitOr, BitXor};
+
+#[test]
+fn test_bool() {
+    assert_eq!(false.eq(&true), false);
+    assert_eq!(false == false, true);
+    assert_eq!(false != true, true);
+    assert_eq!(false.ne(&false), false);
+
+    assert_eq!(false.bitand(false), false);
+    assert_eq!(true.bitand(false), false);
+    assert_eq!(false.bitand(true), false);
+    assert_eq!(true.bitand(true), true);
+
+    assert_eq!(false & false, false);
+    assert_eq!(true & false, false);
+    assert_eq!(false & true, false);
+    assert_eq!(true & true, true);
+
+    assert_eq!(false.bitor(false), false);
+    assert_eq!(true.bitor(false), true);
+    assert_eq!(false.bitor(true), true);
+    assert_eq!(true.bitor(true), true);
+
+    assert_eq!(false | false, false);
+    assert_eq!(true | false, true);
+    assert_eq!(false | true, true);
+    assert_eq!(true | true, true);
+
+    assert_eq!(false.bitxor(false), false);
+    assert_eq!(true.bitxor(false), true);
+    assert_eq!(false.bitxor(true), true);
+    assert_eq!(true.bitxor(true), false);
+
+    assert_eq!(false ^ false, false);
+    assert_eq!(true ^ false, true);
+    assert_eq!(false ^ true, true);
+    assert_eq!(true ^ true, false);
+
+    assert_eq!(!true, false);
+    assert_eq!(!false, true);
+
+    let s = false.to_string();
+    assert_eq!(s, "false");
+    let s = true.to_string();
+    assert_eq!(s, "true");
+
+    assert!(true > false);
+    assert!(!(false > true));
+
+    assert!(false < true);
+    assert!(!(true < false));
+
+    assert!(false <= false);
+    assert!(false >= false);
+    assert!(true <= true);
+    assert!(true >= true);
+
+    assert!(false <= true);
+    assert!(!(false >= true));
+    assert!(true >= false);
+    assert!(!(true <= false));
+
+    assert_eq!(true.cmp(&true), Equal);
+    assert_eq!(false.cmp(&false), Equal);
+    assert_eq!(true.cmp(&false), Greater);
+    assert_eq!(false.cmp(&true), Less);
+}
+
+#[test]
+pub fn test_bool_not() {
+    if !false {
+        assert!((true));
+    } else {
+        assert!((false));
+    }
+    if !true {
+        assert!((false));
+    } else {
+        assert!((true));
+    }
+}
+
 #[test]
 fn test_bool_to_option() {
     assert_eq!(false.then_some(0), None);
diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs
index 835289daf71..11cf7add07a 100644
--- a/library/core/tests/cmp.rs
+++ b/library/core/tests/cmp.rs
@@ -132,3 +132,74 @@ fn ordering_const() {
     const THEN: Ordering = Equal.then(ORDERING);
     assert_eq!(THEN, Greater);
 }
+
+#[test]
+fn cmp_default() {
+    // Test default methods in PartialOrd and PartialEq
+
+    #[derive(Debug)]
+    struct Fool(bool);
+
+    impl PartialEq for Fool {
+        fn eq(&self, other: &Fool) -> bool {
+            let Fool(this) = *self;
+            let Fool(other) = *other;
+            this != other
+        }
+    }
+
+    struct Int(isize);
+
+    impl PartialEq for Int {
+        fn eq(&self, other: &Int) -> bool {
+            let Int(this) = *self;
+            let Int(other) = *other;
+            this == other
+        }
+    }
+
+    impl PartialOrd for Int {
+        fn partial_cmp(&self, other: &Int) -> Option<Ordering> {
+            let Int(this) = *self;
+            let Int(other) = *other;
+            this.partial_cmp(&other)
+        }
+    }
+
+    struct RevInt(isize);
+
+    impl PartialEq for RevInt {
+        fn eq(&self, other: &RevInt) -> bool {
+            let RevInt(this) = *self;
+            let RevInt(other) = *other;
+            this == other
+        }
+    }
+
+    impl PartialOrd for RevInt {
+        fn partial_cmp(&self, other: &RevInt) -> Option<Ordering> {
+            let RevInt(this) = *self;
+            let RevInt(other) = *other;
+            other.partial_cmp(&this)
+        }
+    }
+
+    assert!(Int(2) > Int(1));
+    assert!(Int(2) >= Int(1));
+    assert!(Int(1) >= Int(1));
+    assert!(Int(1) < Int(2));
+    assert!(Int(1) <= Int(2));
+    assert!(Int(1) <= Int(1));
+
+    assert!(RevInt(2) < RevInt(1));
+    assert!(RevInt(2) <= RevInt(1));
+    assert!(RevInt(1) <= RevInt(1));
+    assert!(RevInt(1) > RevInt(2));
+    assert!(RevInt(1) >= RevInt(2));
+    assert!(RevInt(1) >= RevInt(1));
+
+    assert_eq!(Fool(true), Fool(false));
+    assert!(Fool(true) != Fool(true));
+    assert!(Fool(false) != Fool(false));
+    assert_eq!(Fool(false), Fool(true));
+}
diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs
index 6b8a989fa42..ec4b49da384 100644
--- a/library/core/tests/iter.rs
+++ b/library/core/tests/iter.rs
@@ -3493,3 +3493,15 @@ fn test_flatten_non_fused_inner() {
     assert_eq!(iter.next(), Some(1));
     assert_eq!(iter.next(), None);
 }
+
+#[test]
+pub fn extend_for_unit() {
+    let mut x = 0;
+    {
+        let iter = (0..5).map(|_| {
+            x += 1;
+        });
+        ().extend(iter);
+    }
+    assert_eq!(x, 5);
+}
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 1efb3b74118..106c9fe5da3 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -8,6 +8,7 @@
 #![feature(bound_cloned)]
 #![feature(box_syntax)]
 #![feature(cell_update)]
+#![feature(cfg_target_has_atomic)]
 #![feature(const_assume)]
 #![feature(const_cell_into_inner)]
 #![feature(core_intrinsics)]
@@ -63,6 +64,7 @@
 #![feature(int_bits_const)]
 #![feature(nonzero_leading_trailing_zeros)]
 #![feature(const_option)]
+#![feature(integer_atomics)]
 #![deny(unsafe_op_in_unsafe_fn)]
 
 extern crate test;
@@ -82,6 +84,7 @@ mod hash;
 mod intrinsics;
 mod iter;
 mod lazy;
+mod macros;
 mod manually_drop;
 mod mem;
 mod nonzero;
@@ -98,3 +101,4 @@ mod str_lossy;
 mod task;
 mod time;
 mod tuple;
+mod unicode;
diff --git a/library/core/tests/macros.rs b/library/core/tests/macros.rs
new file mode 100644
index 00000000000..482f3c1c998
--- /dev/null
+++ b/library/core/tests/macros.rs
@@ -0,0 +1,14 @@
+#[test]
+fn assert_eq_trailing_comma() {
+    assert_eq!(1, 1,);
+}
+
+#[test]
+fn assert_escape() {
+    assert!(r#"☃\backslash"#.contains("\\"));
+}
+
+#[test]
+fn assert_ne_trailing_comma() {
+    assert_ne!(1, 2,);
+}
diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs
index 5d4ecb2669a..01defab2b38 100644
--- a/library/core/tests/num/wrapping.rs
+++ b/library/core/tests/num/wrapping.rs
@@ -74,3 +74,236 @@ wrapping_test!(u64, u64::MIN, u64::MAX);
 #[cfg(not(target_os = "emscripten"))]
 wrapping_test!(u128, u128::MIN, u128::MAX);
 wrapping_test!(usize, usize::MIN, usize::MAX);
+
+// Don't warn about overflowing ops on 32-bit platforms
+#[cfg_attr(target_pointer_width = "32", allow(const_err))]
+fn wrapping_int_api() {
+    assert_eq!(i8::MAX.wrapping_add(1), i8::MIN);
+    assert_eq!(i16::MAX.wrapping_add(1), i16::MIN);
+    assert_eq!(i32::MAX.wrapping_add(1), i32::MIN);
+    assert_eq!(i64::MAX.wrapping_add(1), i64::MIN);
+    assert_eq!(isize::MAX.wrapping_add(1), isize::MIN);
+
+    assert_eq!(i8::MIN.wrapping_sub(1), i8::MAX);
+    assert_eq!(i16::MIN.wrapping_sub(1), i16::MAX);
+    assert_eq!(i32::MIN.wrapping_sub(1), i32::MAX);
+    assert_eq!(i64::MIN.wrapping_sub(1), i64::MAX);
+    assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX);
+
+    assert_eq!(u8::MAX.wrapping_add(1), u8::MIN);
+    assert_eq!(u16::MAX.wrapping_add(1), u16::MIN);
+    assert_eq!(u32::MAX.wrapping_add(1), u32::MIN);
+    assert_eq!(u64::MAX.wrapping_add(1), u64::MIN);
+    assert_eq!(usize::MAX.wrapping_add(1), usize::MIN);
+
+    assert_eq!(u8::MIN.wrapping_sub(1), u8::MAX);
+    assert_eq!(u16::MIN.wrapping_sub(1), u16::MAX);
+    assert_eq!(u32::MIN.wrapping_sub(1), u32::MAX);
+    assert_eq!(u64::MIN.wrapping_sub(1), u64::MAX);
+    assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX);
+
+    assert_eq!((0xfe_u8 as i8).wrapping_mul(16), (0xe0_u8 as i8));
+    assert_eq!((0xfedc_u16 as i16).wrapping_mul(16), (0xedc0_u16 as i16));
+    assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16), (0xedcb_a980_u32 as i32));
+    assert_eq!(
+        (0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16),
+        (0xedcb_a987_6543_2170_u64 as i64)
+    );
+
+    match () {
+        #[cfg(target_pointer_width = "32")]
+        () => {
+            assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16), (0xedcb_a980_u32 as isize));
+        }
+        #[cfg(target_pointer_width = "64")]
+        () => {
+            assert_eq!(
+                (0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16),
+                (0xedcb_a987_6543_2170_u64 as isize)
+            );
+        }
+    }
+
+    assert_eq!((0xfe as u8).wrapping_mul(16), (0xe0 as u8));
+    assert_eq!((0xfedc as u16).wrapping_mul(16), (0xedc0 as u16));
+    assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16), (0xedcb_a980 as u32));
+    assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16), (0xedcb_a987_6543_2170 as u64));
+
+    match () {
+        #[cfg(target_pointer_width = "32")]
+        () => {
+            assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16), (0xedcb_a980 as usize));
+        }
+        #[cfg(target_pointer_width = "64")]
+        () => {
+            assert_eq!(
+                (0xfedc_ba98_7654_3217 as usize).wrapping_mul(16),
+                (0xedcb_a987_6543_2170 as usize)
+            );
+        }
+    }
+
+    macro_rules! check_mul_no_wrap {
+        ($e:expr, $f:expr) => {
+            assert_eq!(($e).wrapping_mul($f), ($e) * $f);
+        };
+    }
+    macro_rules! check_mul_wraps {
+        ($e:expr, $f:expr) => {
+            assert_eq!(($e).wrapping_mul($f), $e);
+        };
+    }
+
+    check_mul_no_wrap!(0xfe_u8 as i8, -1);
+    check_mul_no_wrap!(0xfedc_u16 as i16, -1);
+    check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1);
+    check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1);
+    check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1);
+
+    check_mul_no_wrap!(0xfe_u8 as i8, -2);
+    check_mul_no_wrap!(0xfedc_u16 as i16, -2);
+    check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2);
+    check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2);
+    check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2);
+
+    check_mul_no_wrap!(0xfe_u8 as i8, 2);
+    check_mul_no_wrap!(0xfedc_u16 as i16, 2);
+    check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2);
+    check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2);
+    check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2);
+
+    check_mul_wraps!(0x80_u8 as i8, -1);
+    check_mul_wraps!(0x8000_u16 as i16, -1);
+    check_mul_wraps!(0x8000_0000_u32 as i32, -1);
+    check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1);
+    match () {
+        #[cfg(target_pointer_width = "32")]
+        () => {
+            check_mul_wraps!(0x8000_0000_u32 as isize, -1);
+        }
+        #[cfg(target_pointer_width = "64")]
+        () => {
+            check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1);
+        }
+    }
+
+    macro_rules! check_div_no_wrap {
+        ($e:expr, $f:expr) => {
+            assert_eq!(($e).wrapping_div($f), ($e) / $f);
+        };
+    }
+    macro_rules! check_div_wraps {
+        ($e:expr, $f:expr) => {
+            assert_eq!(($e).wrapping_div($f), $e);
+        };
+    }
+
+    check_div_no_wrap!(0xfe_u8 as i8, -1);
+    check_div_no_wrap!(0xfedc_u16 as i16, -1);
+    check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1);
+    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1);
+    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1);
+
+    check_div_no_wrap!(0xfe_u8 as i8, -2);
+    check_div_no_wrap!(0xfedc_u16 as i16, -2);
+    check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2);
+    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2);
+    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2);
+
+    check_div_no_wrap!(0xfe_u8 as i8, 2);
+    check_div_no_wrap!(0xfedc_u16 as i16, 2);
+    check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2);
+    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2);
+    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2);
+
+    check_div_wraps!(-128 as i8, -1);
+    check_div_wraps!(0x8000_u16 as i16, -1);
+    check_div_wraps!(0x8000_0000_u32 as i32, -1);
+    check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1);
+    match () {
+        #[cfg(target_pointer_width = "32")]
+        () => {
+            check_div_wraps!(0x8000_0000_u32 as isize, -1);
+        }
+        #[cfg(target_pointer_width = "64")]
+        () => {
+            check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1);
+        }
+    }
+
+    macro_rules! check_rem_no_wrap {
+        ($e:expr, $f:expr) => {
+            assert_eq!(($e).wrapping_rem($f), ($e) % $f);
+        };
+    }
+    macro_rules! check_rem_wraps {
+        ($e:expr, $f:expr) => {
+            assert_eq!(($e).wrapping_rem($f), 0);
+        };
+    }
+
+    check_rem_no_wrap!(0xfe_u8 as i8, -1);
+    check_rem_no_wrap!(0xfedc_u16 as i16, -1);
+    check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1);
+    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1);
+    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1);
+
+    check_rem_no_wrap!(0xfe_u8 as i8, -2);
+    check_rem_no_wrap!(0xfedc_u16 as i16, -2);
+    check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2);
+    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2);
+    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2);
+
+    check_rem_no_wrap!(0xfe_u8 as i8, 2);
+    check_rem_no_wrap!(0xfedc_u16 as i16, 2);
+    check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2);
+    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2);
+    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2);
+
+    check_rem_wraps!(0x80_u8 as i8, -1);
+    check_rem_wraps!(0x8000_u16 as i16, -1);
+    check_rem_wraps!(0x8000_0000_u32 as i32, -1);
+    check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1);
+    match () {
+        #[cfg(target_pointer_width = "32")]
+        () => {
+            check_rem_wraps!(0x8000_0000_u32 as isize, -1);
+        }
+        #[cfg(target_pointer_width = "64")]
+        () => {
+            check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1);
+        }
+    }
+
+    macro_rules! check_neg_no_wrap {
+        ($e:expr) => {
+            assert_eq!(($e).wrapping_neg(), -($e));
+        };
+    }
+    macro_rules! check_neg_wraps {
+        ($e:expr) => {
+            assert_eq!(($e).wrapping_neg(), ($e));
+        };
+    }
+
+    check_neg_no_wrap!(0xfe_u8 as i8);
+    check_neg_no_wrap!(0xfedc_u16 as i16);
+    check_neg_no_wrap!(0xfedc_ba98_u32 as i32);
+    check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64);
+    check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize);
+
+    check_neg_wraps!(0x80_u8 as i8);
+    check_neg_wraps!(0x8000_u16 as i16);
+    check_neg_wraps!(0x8000_0000_u32 as i32);
+    check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64);
+    match () {
+        #[cfg(target_pointer_width = "32")]
+        () => {
+            check_neg_wraps!(0x8000_0000_u32 as isize);
+        }
+        #[cfg(target_pointer_width = "64")]
+        () => {
+            check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize);
+        }
+    }
+}
diff --git a/library/core/tests/ops.rs b/library/core/tests/ops.rs
index e9d595e65e2..53e5539fad9 100644
--- a/library/core/tests/ops.rs
+++ b/library/core/tests/ops.rs
@@ -1,4 +1,5 @@
 use core::ops::{Bound, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
+use core::ops::{Deref, DerefMut};
 
 // Test the Range structs and syntax.
 
@@ -197,3 +198,35 @@ fn range_structural_match() {
         _ => unreachable!(),
     }
 }
+
+// Test Deref implementations
+
+#[test]
+fn deref_mut_on_ref() {
+    // Test that `&mut T` implements `DerefMut<T>`
+
+    fn inc<T: Deref<Target = isize> + DerefMut>(mut t: T) {
+        *t += 1;
+    }
+
+    let mut x: isize = 5;
+    inc(&mut x);
+    assert_eq!(x, 6);
+}
+
+#[test]
+fn deref_on_ref() {
+    // Test that `&T` and `&mut T` implement `Deref<T>`
+
+    fn deref<U: Copy, T: Deref<Target = U>>(t: T) -> U {
+        *t
+    }
+
+    let x: isize = 3;
+    let y = deref(&x);
+    assert_eq!(y, 3);
+
+    let mut x: isize = 4;
+    let y = deref(&mut x);
+    assert_eq!(y, 4);
+}
diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs
index ae814efec20..5388b475624 100644
--- a/library/core/tests/option.rs
+++ b/library/core/tests/option.rs
@@ -402,3 +402,13 @@ fn test_unwrap_drop() {
 
     assert_eq!(x.get(), 0);
 }
+
+#[test]
+pub fn option_ext() {
+    let thing = "{{ f }}";
+    let f = thing.find("{{");
+
+    if f.is_none() {
+        println!("None!");
+    }
+}
diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs
index 1970b17e267..57c2fb06c16 100644
--- a/library/core/tests/ptr.rs
+++ b/library/core/tests/ptr.rs
@@ -400,3 +400,16 @@ fn align_offset_weird_strides() {
     }
     assert!(!x);
 }
+
+#[test]
+fn offset_from() {
+    let mut a = [0; 5];
+    let ptr1: *mut i32 = &mut a[1];
+    let ptr2: *mut i32 = &mut a[3];
+    unsafe {
+        assert_eq!(ptr2.offset_from(ptr1), 2);
+        assert_eq!(ptr1.offset_from(ptr2), -2);
+        assert_eq!(ptr1.offset(2), ptr2);
+        assert_eq!(ptr2.offset(-2), ptr1);
+    }
+}
diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs
index 39ea4831b9b..81660870e95 100644
--- a/library/core/tests/result.rs
+++ b/library/core/tests/result.rs
@@ -320,3 +320,41 @@ fn result_const() {
     const IS_ERR: bool = RESULT.is_err();
     assert!(!IS_ERR)
 }
+
+#[test]
+fn result_opt_conversions() {
+    #[derive(Copy, Clone, Debug, PartialEq)]
+    struct BadNumErr;
+
+    fn try_num(x: i32) -> Result<i32, BadNumErr> {
+        if x <= 5 { Ok(x + 1) } else { Err(BadNumErr) }
+    }
+
+    type ResOpt = Result<Option<i32>, BadNumErr>;
+    type OptRes = Option<Result<i32, BadNumErr>>;
+
+    let mut x: ResOpt = Ok(Some(5));
+    let mut y: OptRes = Some(Ok(5));
+    assert_eq!(x, y.transpose());
+    assert_eq!(x.transpose(), y);
+
+    x = Ok(None);
+    y = None;
+    assert_eq!(x, y.transpose());
+    assert_eq!(x.transpose(), y);
+
+    x = Err(BadNumErr);
+    y = Some(Err(BadNumErr));
+    assert_eq!(x, y.transpose());
+    assert_eq!(x.transpose(), y);
+
+    let res: Result<Vec<i32>, BadNumErr> = (0..10)
+        .map(|x| {
+            let y = try_num(x)?;
+            Ok(if y % 2 == 0 { Some(y - 1) } else { None })
+        })
+        .filter_map(Result::transpose)
+        .collect();
+
+    assert_eq!(res, Err(BadNumErr))
+}
diff --git a/library/core/tests/unicode.rs b/library/core/tests/unicode.rs
new file mode 100644
index 00000000000..c28ea859115
--- /dev/null
+++ b/library/core/tests/unicode.rs
@@ -0,0 +1,5 @@
+#[test]
+pub fn version() {
+    let (major, _minor, _update) = core::unicode::UNICODE_VERSION;
+    assert!(major >= 10);
+}
diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs
index d9fbdd1b5e7..44fb3adf070 100644
--- a/library/std/src/net/ip/tests.rs
+++ b/library/std/src/net/ip/tests.rs
@@ -936,4 +936,10 @@ fn ip_const() {
 
     const IS_MULTICAST: bool = IP_ADDRESS.is_multicast();
     assert!(!IS_MULTICAST);
+
+    const IS_IP_V4: bool = IP_ADDRESS.is_ipv4();
+    assert!(IS_IP_V4);
+
+    const IS_IP_V6: bool = IP_ADDRESS.is_ipv6();
+    assert!(!IS_IP_V6);
 }
diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs
index c94fc41178d..0e55ec648c9 100644
--- a/library/std/tests/env.rs
+++ b/library/std/tests/env.rs
@@ -1,5 +1,6 @@
 use std::env::*;
 use std::ffi::{OsStr, OsString};
+use std::path::PathBuf;
 
 use rand::distributions::Alphanumeric;
 use rand::{thread_rng, Rng};
@@ -76,3 +77,63 @@ fn test_env_set_var() {
 
     assert!(vars_os().any(|(k, v)| { &*k == &*n && &*v == "VALUE" }));
 }
+
+#[test]
+#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
+#[allow(deprecated)]
+fn env_home_dir() {
+    fn var_to_os_string(var: Result<String, VarError>) -> Option<OsString> {
+        match var {
+            Ok(var) => Some(OsString::from(var)),
+            Err(VarError::NotUnicode(var)) => Some(var),
+            _ => None,
+        }
+    }
+
+    cfg_if::cfg_if! {
+        if #[cfg(unix)] {
+            let oldhome = var_to_os_string(var("HOME"));
+
+            set_var("HOME", "/home/MountainView");
+            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
+
+            remove_var("HOME");
+            if cfg!(target_os = "android") {
+                assert!(home_dir().is_none());
+            } else {
+                // When HOME is not set, some platforms return `None`,
+                // but others return `Some` with a default.
+                // Just check that it is not "/home/MountainView".
+                assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView")));
+            }
+
+            if let Some(oldhome) = oldhome { set_var("HOME", oldhome); }
+        } else if #[cfg(windows)] {
+            let oldhome = var_to_os_string(var("HOME"));
+            let olduserprofile = var_to_os_string(var("USERPROFILE"));
+
+            remove_var("HOME");
+            remove_var("USERPROFILE");
+
+            assert!(home_dir().is_some());
+
+            set_var("HOME", "/home/MountainView");
+            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
+
+            remove_var("HOME");
+
+            set_var("USERPROFILE", "/home/MountainView");
+            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
+
+            set_var("HOME", "/home/MountainView");
+            set_var("USERPROFILE", "/home/PaloAlto");
+            assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
+
+            remove_var("HOME");
+            remove_var("USERPROFILE");
+
+            if let Some(oldhome) = oldhome { set_var("HOME", oldhome); }
+            if let Some(olduserprofile) = olduserprofile { set_var("USERPROFILE", olduserprofile); }
+        }
+    }
+}
diff --git a/src/test/ui/sleep.rs b/library/std/tests/thread.rs
index f3f8d7259c4..754b264c6ad 100644
--- a/src/test/ui/sleep.rs
+++ b/library/std/tests/thread.rs
@@ -1,17 +1,16 @@
-// run-pass
-// ignore-emscripten no threads support
-
-use std::thread::{self, sleep};
-use std::time::Duration;
 use std::sync::{Arc, Mutex};
+use std::thread;
+use std::time::Duration;
 
-fn main() {
+#[test]
+#[cfg_attr(target_os = "emscripten", ignore)]
+fn sleep() {
     let finished = Arc::new(Mutex::new(false));
     let t_finished = finished.clone();
     thread::spawn(move || {
-        sleep(Duration::new(u64::MAX, 0));
+        thread::sleep(Duration::new(u64::MAX, 0));
         *t_finished.lock().unwrap() = true;
     });
-    sleep(Duration::from_millis(100));
+    thread::sleep(Duration::from_millis(100));
     assert_eq!(*finished.lock().unwrap(), false);
 }
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index 508d785834f..b5bbb6372ee 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -413,6 +413,7 @@ impl<'a> Builder<'a> {
                 test::TheBook,
                 test::UnstableBook,
                 test::RustcBook,
+                test::LintDocs,
                 test::RustcGuide,
                 test::EmbeddedBook,
                 test::EditionGuide,
@@ -730,6 +731,7 @@ impl<'a> Builder<'a> {
             .env("CFG_RELEASE_CHANNEL", &self.config.channel)
             .env("RUSTDOC_REAL", self.rustdoc(compiler))
             .env("RUSTC_BOOTSTRAP", "1")
+            .arg("-Znormalize_docs")
             .arg("-Winvalid_codeblock_attributes");
         if self.config.deny_warnings {
             cmd.arg("-Dwarnings");
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index af7f7eff894..a296a1fe3f4 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -527,6 +527,7 @@ impl Step for Rustc {
         cargo.rustdocflag("--document-private-items");
         cargo.rustdocflag("--enable-index-page");
         cargo.rustdocflag("-Zunstable-options");
+        cargo.rustdocflag("-Znormalize-docs");
         compile::rustc_cargo(builder, &mut cargo, target);
 
         // Only include compiler crates, no dependencies of those, such as `libc`.
@@ -726,6 +727,7 @@ fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()>
 pub struct RustcBook {
     pub compiler: Compiler,
     pub target: TargetSelection,
+    pub validate: bool,
 }
 
 impl Step for RustcBook {
@@ -742,6 +744,7 @@ impl Step for RustcBook {
         run.builder.ensure(RustcBook {
             compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
             target: run.target,
+            validate: false,
         });
     }
 
@@ -772,6 +775,9 @@ impl Step for RustcBook {
         if builder.config.verbose() {
             cmd.arg("--verbose");
         }
+        if self.validate {
+            cmd.arg("--validate");
+        }
         // If the lib directories are in an unusual location (changed in
         // config.toml), then this needs to explicitly update the dylib search
         // path.
diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs
index e087e2b8ff1..1df50322a07 100644
--- a/src/bootstrap/test.rs
+++ b/src/bootstrap/test.rs
@@ -688,38 +688,6 @@ impl Step for RustdocJSNotStd {
     }
 }
 
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
-pub struct RustdocUi {
-    pub target: TargetSelection,
-    pub compiler: Compiler,
-}
-
-impl Step for RustdocUi {
-    type Output = ();
-    const DEFAULT: bool = true;
-    const ONLY_HOSTS: bool = true;
-
-    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/test/rustdoc-ui")
-    }
-
-    fn make_run(run: RunConfig<'_>) {
-        let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
-        run.builder.ensure(RustdocUi { target: run.target, compiler });
-    }
-
-    fn run(self, builder: &Builder<'_>) {
-        builder.ensure(Compiletest {
-            compiler: self.compiler,
-            target: self.target,
-            mode: "ui",
-            suite: "rustdoc-ui",
-            path: "src/test/rustdoc-ui",
-            compare_mode: None,
-        })
-    }
-}
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Tidy;
 
@@ -934,6 +902,7 @@ default_test!(Debuginfo { path: "src/test/debuginfo", mode: "debuginfo", suite:
 host_test!(UiFullDeps { path: "src/test/ui-fulldeps", mode: "ui", suite: "ui-fulldeps" });
 
 host_test!(Rustdoc { path: "src/test/rustdoc", mode: "rustdoc", suite: "rustdoc" });
+host_test!(RustdocUi { path: "src/test/rustdoc-ui", mode: "ui", suite: "rustdoc-ui" });
 
 host_test!(Pretty { path: "src/test/pretty", mode: "pretty", suite: "pretty" });
 
@@ -2115,3 +2084,36 @@ impl Step for TierCheck {
         try_run(builder, &mut cargo.into());
     }
 }
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct LintDocs {
+    pub compiler: Compiler,
+    pub target: TargetSelection,
+}
+
+impl Step for LintDocs {
+    type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/lint-docs")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(LintDocs {
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            target: run.target,
+        });
+    }
+
+    /// Tests that the lint examples in the rustc book generate the correct
+    /// lints and have the expected format.
+    fn run(self, builder: &Builder<'_>) {
+        builder.ensure(crate::doc::RustcBook {
+            compiler: self.compiler,
+            target: self.target,
+            validate: true,
+        });
+    }
+}
diff --git a/src/doc/book b/src/doc/book
-Subproject 13e1c05420bca86ecc79e4ba5b6d02de9bd53c6
+Subproject a190438d77d28041f24da4f6592e287fab073a6
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
-Subproject ca8169e69b479f615855d0eece7e318138fcfc0
+Subproject ba34b8a968f9531d38c4dc4411d5568b7c076bf
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 23c49f1d5ce4720bc5b7e3a920f47eccc8da6b6
+Subproject d8383b65f7948c2ca19191b3b4bd709b403aaf4
diff --git a/src/doc/reference b/src/doc/reference
-Subproject a7de763c213292f5b44bf10acb87ffa38724814
+Subproject a8afdca5d0715b2257b6f8b9a032fd4dd7dae85
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 1886fda6981b723e4de637074455558f8bc1e83
+Subproject 236c734a2cb323541b3394f98682cb981b9ec08
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 52cfb08cdc9..ce8caae375e 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -156,7 +156,7 @@ target | std | host | notes
 `aarch64-apple-tvos` | * |  | ARM64 tvOS
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ? |  |
-`aarch64-unknown-netbsd` | ? |  |
+`aarch64-unknown-netbsd` | ✓ | ✓ |
 `aarch64-unknown-openbsd` | ✓ | ✓ | ARM64 OpenBSD
 `aarch64-unknown-redox` | ? |  | ARM64 Redox OS
 `aarch64-uwp-windows-msvc` | ? |  |
@@ -167,7 +167,7 @@ target | std | host | notes
 `armv6-unknown-netbsd-eabihf` | ? |  |
 `armv7-apple-ios` | ✓ |  | ARMv7 iOS, Cortex-a8
 `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
-`armv7-unknown-netbsd-eabihf` | ? |  |
+`armv7-unknown-netbsd-eabihf` | ✓ | ✓ |
 `armv7-wrs-vxworks-eabihf` | ? |  |
 `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat
 `armv7s-apple-ios` | ✓ |  |
@@ -178,7 +178,7 @@ target | std | host | notes
 `i686-pc-windows-msvc` | ✓ |  | 32-bit Windows XP support
 `i686-unknown-uefi` | ? |  | 32-bit UEFI
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku
-`i686-unknown-netbsd` | ✓ |  | NetBSD/i386 with SSE2
+`i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2
 `i686-unknown-openbsd` | ✓ | ✓ | 32-bit OpenBSD
 `i686-uwp-windows-gnu` | ? |  |
 `i686-uwp-windows-msvc` | ? |  |
@@ -194,7 +194,7 @@ target | std | host | notes
 `msp430-none-elf` | * |  | 16-bit MSP430 microcontrollers
 `powerpc-unknown-linux-gnuspe` | ✓ |  | PowerPC SPE Linux
 `powerpc-unknown-linux-musl` | ? |  |
-`powerpc-unknown-netbsd` | ? |  |
+`powerpc-unknown-netbsd` | ✓ | ✓ |
 `powerpc-wrs-vxworks` | ? |  |
 `powerpc-wrs-vxworks-spe` | ? |  |
 `powerpc64-unknown-freebsd` | ✓ | ✓ | PPC64 FreeBSD (ELFv1 and ELFv2)
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index ff996b2a925..8feef9c259c 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -124,6 +124,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> {
                     visibility: Inherited,
                     def_id: self.cx.next_def_id(param_env_def_id.krate),
                     stability: None,
+                    const_stability: None,
                     deprecation: None,
                     kind: ImplItem(Impl {
                         unsafety: hir::Unsafety::Normal,
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 5721927d0ec..33b5e84c5e0 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -113,6 +113,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                     visibility: Inherited,
                     def_id: self.cx.next_def_id(impl_def_id.krate),
                     stability: None,
+                    const_stability: None,
                     deprecation: None,
                     kind: ImplItem(Impl {
                         unsafety: hir::Unsafety::Normal,
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 61121c776f4..f3067360f06 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -483,6 +483,7 @@ fn build_module(cx: &DocContext<'_>, did: DefId, visited: &mut FxHashSet<DefId>)
                         def_id: DefId::local(CRATE_DEF_INDEX),
                         visibility: clean::Public,
                         stability: None,
+                        const_stability: None,
                         deprecation: None,
                         kind: clean::ImportItem(clean::Import::new_simple(
                             item.ident.to_string(),
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 9e8ce452924..d294d8f02a8 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1515,9 +1515,12 @@ impl Clean<Type> for hir::Ty<'_> {
 }
 
 /// Returns `None` if the type could not be normalized
-#[allow(unreachable_code, unused_variables)]
 fn normalize(cx: &DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
-    return None; // HACK: low-churn fix for #79459 while we wait for a trait normalization fix
+    // HACK: low-churn fix for #79459 while we wait for a trait normalization fix
+    if !cx.tcx.sess.opts.debugging_opts.normalize_docs {
+        return None;
+    }
+
     use crate::rustc_trait_selection::infer::TyCtxtInferExt;
     use crate::rustc_trait_selection::traits::query::normalize::AtExt;
     use rustc_middle::traits::ObligationCause;
@@ -2189,6 +2192,7 @@ fn clean_extern_crate(
         def_id: crate_def_id,
         visibility: krate.vis.clean(cx),
         stability: None,
+        const_stability: None,
         deprecation: None,
         kind: ExternCrateItem(name.clean(cx), path),
     }]
@@ -2259,6 +2263,7 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
                         def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(),
                         visibility: self.vis.clean(cx),
                         stability: None,
+                        const_stability: None,
                         deprecation: None,
                         kind: ImportItem(Import::new_simple(
                             self.name.clean(cx),
@@ -2279,6 +2284,7 @@ impl Clean<Vec<Item>> for doctree::Import<'_> {
             def_id: DefId::local(CRATE_DEF_INDEX),
             visibility: self.vis.clean(cx),
             stability: None,
+            const_stability: None,
             deprecation: None,
             kind: ImportItem(inner),
         }]
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index 2283b71a94f..38d25d8d98e 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -12,7 +12,7 @@ use rustc_ast::attr;
 use rustc_ast::util::comments::beautify_doc_string;
 use rustc_ast::{self as ast, AttrStyle};
 use rustc_ast::{FloatTy, IntTy, UintTy};
-use rustc_attr::{Stability, StabilityLevel};
+use rustc_attr::{ConstStability, Stability, StabilityLevel};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_feature::UnstableFeatures;
 use rustc_hir as hir;
@@ -87,6 +87,7 @@ crate struct Item {
     crate def_id: DefId,
     crate stability: Option<Stability>,
     crate deprecation: Option<Deprecation>,
+    crate const_stability: Option<ConstStability>,
 }
 
 impl fmt::Debug for Item {
@@ -155,6 +156,7 @@ impl Item {
             visibility: cx.tcx.visibility(def_id).clean(cx),
             stability: cx.tcx.lookup_stability(def_id).cloned(),
             deprecation: cx.tcx.lookup_deprecation(def_id).clean(cx),
+            const_stability: cx.tcx.lookup_const_stability(def_id).cloned(),
         }
     }
 
@@ -262,6 +264,13 @@ impl Item {
         }
     }
 
+    crate fn const_stable_since(&self) -> Option<SymbolStr> {
+        match self.const_stability?.level {
+            StabilityLevel::Stable { since, .. } => Some(since.as_str()),
+            StabilityLevel::Unstable { .. } => None,
+        }
+    }
+
     crate fn is_non_exhaustive(&self) -> bool {
         self.attrs.other_attrs.iter().any(|a| a.has_name(sym::non_exhaustive))
     }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index bbd4be88e6a..de620a35c80 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1692,13 +1692,13 @@ fn print_item(cx: &Context, item: &clean::Item, buf: &mut Buffer, cache: &Cache)
     debug_assert!(!item.is_stripped());
     // Write the breadcrumb trail header for the top
     write!(buf, "<h1 class=\"fqn\"><span class=\"out-of-band\">");
-    if let Some(version) = item.stable_since() {
-        write!(
-            buf,
-            "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
-            version
-        );
-    }
+    render_stability_since_raw(
+        buf,
+        item.stable_since().as_deref(),
+        item.const_stable_since().as_deref(),
+        None,
+        None,
+    );
     write!(
         buf,
         "<span id=\"render-detail\">\
@@ -2476,6 +2476,7 @@ fn render_implementor(
         AssocItemLink::Anchor(None),
         RenderMode::Normal,
         implementor.impl_item.stable_since().as_deref(),
+        implementor.impl_item.const_stable_since().as_deref(),
         false,
         Some(use_absolute),
         false,
@@ -2506,6 +2507,7 @@ fn render_impls(
                 assoc_link,
                 RenderMode::Normal,
                 containing_item.stable_since().as_deref(),
+                containing_item.const_stable_since().as_deref(),
                 true,
                 None,
                 false,
@@ -2756,6 +2758,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait,
                     assoc_link,
                     RenderMode::Normal,
                     implementor.impl_item.stable_since().as_deref(),
+                    implementor.impl_item.const_stable_since().as_deref(),
                     false,
                     None,
                     true,
@@ -2898,10 +2901,40 @@ fn assoc_type(
     }
 }
 
-fn render_stability_since_raw(w: &mut Buffer, ver: Option<&str>, containing_ver: Option<&str>) {
+fn render_stability_since_raw(
+    w: &mut Buffer,
+    ver: Option<&str>,
+    const_ver: Option<&str>,
+    containing_ver: Option<&str>,
+    containing_const_ver: Option<&str>,
+) {
+    let ver = ver.and_then(|inner| if !inner.is_empty() { Some(inner) } else { None });
+
+    let const_ver = const_ver.and_then(|inner| if !inner.is_empty() { Some(inner) } else { None });
+
     if let Some(v) = ver {
-        if containing_ver != ver && !v.is_empty() {
-            write!(w, "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>", v)
+        if let Some(cv) = const_ver {
+            if const_ver != containing_const_ver {
+                write!(
+                    w,
+                    "<span class=\"since\" title=\"Stable since Rust version {0}, const since {1}\">{0} (const: {1})</span>",
+                    v, cv
+                );
+            } else if ver != containing_ver {
+                write!(
+                    w,
+                    "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
+                    v
+                );
+            }
+        } else {
+            if ver != containing_ver {
+                write!(
+                    w,
+                    "<span class=\"since\" title=\"Stable since Rust version {0}\">{0}</span>",
+                    v
+                );
+            }
         }
     }
 }
@@ -2910,7 +2943,9 @@ fn render_stability_since(w: &mut Buffer, item: &clean::Item, containing_item: &
     render_stability_since_raw(
         w,
         item.stable_since().as_deref(),
+        item.const_stable_since().as_deref(),
         containing_item.stable_since().as_deref(),
+        containing_item.const_stable_since().as_deref(),
     )
 }
 
@@ -3462,6 +3497,7 @@ fn render_assoc_items(
                 AssocItemLink::Anchor(None),
                 render_mode,
                 containing_item.stable_since().as_deref(),
+                containing_item.const_stable_since().as_deref(),
                 true,
                 None,
                 false,
@@ -3654,6 +3690,7 @@ fn render_impl(
     link: AssocItemLink<'_>,
     render_mode: RenderMode,
     outer_version: Option<&str>,
+    outer_const_version: Option<&str>,
     show_def_docs: bool,
     use_absolute: Option<bool>,
     is_on_foreign_type: bool,
@@ -3705,11 +3742,13 @@ fn render_impl(
             );
         }
         write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
-        let since = i.impl_item.stability.as_ref().and_then(|s| match s.level {
-            StabilityLevel::Stable { since } => Some(since.as_str()),
-            StabilityLevel::Unstable { .. } => None,
-        });
-        render_stability_since_raw(w, since.as_deref(), outer_version);
+        render_stability_since_raw(
+            w,
+            i.impl_item.stable_since().as_deref(),
+            i.impl_item.const_stable_since().as_deref(),
+            outer_version,
+            outer_const_version,
+        );
         write_srclink(cx, &i.impl_item, w, cache);
         write!(w, "</h3>");
 
@@ -3746,6 +3785,7 @@ fn render_impl(
         render_mode: RenderMode,
         is_default_item: bool,
         outer_version: Option<&str>,
+        outer_const_version: Option<&str>,
         trait_: Option<&clean::Trait>,
         show_def_docs: bool,
         cache: &Cache,
@@ -3775,7 +3815,13 @@ fn render_impl(
                     write!(w, "<code>");
                     render_assoc_item(w, item, link.anchor(&id), ItemType::Impl);
                     write!(w, "</code>");
-                    render_stability_since_raw(w, item.stable_since().as_deref(), outer_version);
+                    render_stability_since_raw(
+                        w,
+                        item.stable_since().as_deref(),
+                        item.const_stable_since().as_deref(),
+                        outer_version,
+                        outer_const_version,
+                    );
                     write_srclink(cx, item, w, cache);
                     write!(w, "</h4>");
                 }
@@ -3791,7 +3837,13 @@ fn render_impl(
                 write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, extra_class);
                 assoc_const(w, item, ty, default.as_ref(), link.anchor(&id), "");
                 write!(w, "</code>");
-                render_stability_since_raw(w, item.stable_since().as_deref(), outer_version);
+                render_stability_since_raw(
+                    w,
+                    item.stable_since().as_deref(),
+                    item.const_stable_since().as_deref(),
+                    outer_version,
+                    outer_const_version,
+                );
                 write_srclink(cx, item, w, cache);
                 write!(w, "</h4>");
             }
@@ -3854,6 +3906,7 @@ fn render_impl(
             render_mode,
             false,
             outer_version,
+            outer_const_version,
             trait_,
             show_def_docs,
             cache,
@@ -3868,6 +3921,7 @@ fn render_impl(
         parent: &clean::Item,
         render_mode: RenderMode,
         outer_version: Option<&str>,
+        outer_const_version: Option<&str>,
         show_def_docs: bool,
         cache: &Cache,
     ) {
@@ -3888,6 +3942,7 @@ fn render_impl(
                 render_mode,
                 true,
                 outer_version,
+                outer_const_version,
                 None,
                 show_def_docs,
                 cache,
@@ -3909,6 +3964,7 @@ fn render_impl(
                 &i.impl_item,
                 render_mode,
                 outer_version,
+                outer_const_version,
                 show_def_docs,
                 cache,
             );
diff --git a/src/test/rustdoc-ui/.gitattributes b/src/test/rustdoc-ui/.gitattributes
deleted file mode 100644
index 2bcabdffb3d..00000000000
--- a/src/test/rustdoc-ui/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-intra-links-warning-crlf.rs eol=crlf
diff --git a/src/test/rustdoc-ui/intra-doc/.gitattributes b/src/test/rustdoc-ui/intra-doc/.gitattributes
new file mode 100644
index 00000000000..6c125fac52f
--- /dev/null
+++ b/src/test/rustdoc-ui/intra-doc/.gitattributes
@@ -0,0 +1 @@
+warning-crlf.rs eol=crlf
diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.rs b/src/test/rustdoc-ui/intra-doc/alias-ice.rs
index c053e378e71..c053e378e71 100644
--- a/src/test/rustdoc-ui/intra-doc-alias-ice.rs
+++ b/src/test/rustdoc-ui/intra-doc/alias-ice.rs
diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc/alias-ice.stderr
index 771fc2204f5..3db5fad4cfb 100644
--- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr
+++ b/src/test/rustdoc-ui/intra-doc/alias-ice.stderr
@@ -1,11 +1,11 @@
 error: unresolved link to `TypeAlias::hoge`
-  --> $DIR/intra-doc-alias-ice.rs:5:30
+  --> $DIR/alias-ice.rs:5:30
    |
 LL | /// [broken cross-reference](TypeAlias::hoge)
    |                              ^^^^^^^^^^^^^^^ the type alias `TypeAlias` has no associated item named `hoge`
    |
 note: the lint level is defined here
-  --> $DIR/intra-doc-alias-ice.rs:1:9
+  --> $DIR/alias-ice.rs:1:9
    |
 LL | #![deny(broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.rs b/src/test/rustdoc-ui/intra-doc/ambiguity.rs
index f63435337cf..f63435337cf 100644
--- a/src/test/rustdoc-ui/intra-links-ambiguity.rs
+++ b/src/test/rustdoc-ui/intra-doc/ambiguity.rs
diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-doc/ambiguity.stderr
index 936055da01c..7e967dc88bc 100644
--- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr
+++ b/src/test/rustdoc-ui/intra-doc/ambiguity.stderr
@@ -1,11 +1,11 @@
 error: `true` is both a module and a builtin type
-  --> $DIR/intra-links-ambiguity.rs:38:6
+  --> $DIR/ambiguity.rs:38:6
    |
 LL | /// [true]
    |      ^^^^ ambiguous link
    |
 note: the lint level is defined here
-  --> $DIR/intra-links-ambiguity.rs:1:9
+  --> $DIR/ambiguity.rs:1:9
    |
 LL | #![deny(broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL | /// [prim@true]
    |      ^^^^^^^^^
 
 error: `ambiguous` is both a struct and a function
-  --> $DIR/intra-links-ambiguity.rs:27:6
+  --> $DIR/ambiguity.rs:27:6
    |
 LL | /// [`ambiguous`] is ambiguous.
    |      ^^^^^^^^^^^ ambiguous link
@@ -34,7 +34,7 @@ LL | /// [`ambiguous()`] is ambiguous.
    |      ^^^^^^^^^^^^^
 
 error: `ambiguous` is both a struct and a function
-  --> $DIR/intra-links-ambiguity.rs:29:6
+  --> $DIR/ambiguity.rs:29:6
    |
 LL | /// [ambiguous] is ambiguous.
    |      ^^^^^^^^^ ambiguous link
@@ -49,7 +49,7 @@ LL | /// [ambiguous()] is ambiguous.
    |      ^^^^^^^^^^^
 
 error: `multi_conflict` is a struct, a function, and a macro
-  --> $DIR/intra-links-ambiguity.rs:31:6
+  --> $DIR/ambiguity.rs:31:6
    |
 LL | /// [`multi_conflict`] is a three-way conflict.
    |      ^^^^^^^^^^^^^^^^ ambiguous link
@@ -68,7 +68,7 @@ LL | /// [`multi_conflict!`] is a three-way conflict.
    |      ^^^^^^^^^^^^^^^^^
 
 error: `type_and_value` is both a module and a constant
-  --> $DIR/intra-links-ambiguity.rs:33:16
+  --> $DIR/ambiguity.rs:33:16
    |
 LL | /// Ambiguous [type_and_value].
    |                ^^^^^^^^^^^^^^ ambiguous link
@@ -83,7 +83,7 @@ LL | /// Ambiguous [const@type_and_value].
    |                ^^^^^^^^^^^^^^^^^^^^
 
 error: `foo::bar` is both an enum and a function
-  --> $DIR/intra-links-ambiguity.rs:35:42
+  --> $DIR/ambiguity.rs:35:42
    |
 LL | /// Ambiguous non-implied shortcut link [`foo::bar`].
    |                                          ^^^^^^^^^^ ambiguous link
diff --git a/src/test/rustdoc-ui/intra-links-anchors.rs b/src/test/rustdoc-ui/intra-doc/anchors.rs
index ccefd2e6fab..ccefd2e6fab 100644
--- a/src/test/rustdoc-ui/intra-links-anchors.rs
+++ b/src/test/rustdoc-ui/intra-doc/anchors.rs
diff --git a/src/test/rustdoc-ui/intra-links-anchors.stderr b/src/test/rustdoc-ui/intra-doc/anchors.stderr
index 1825a4ad1fa..5b272d960d5 100644
--- a/src/test/rustdoc-ui/intra-links-anchors.stderr
+++ b/src/test/rustdoc-ui/intra-doc/anchors.stderr
@@ -1,29 +1,29 @@
 error: `Foo::f#hola` contains an anchor, but links to fields are already anchored
-  --> $DIR/intra-links-anchors.rs:25:15
+  --> $DIR/anchors.rs:25:15
    |
 LL | /// Or maybe [Foo::f#hola].
    |               ^^^^^^^^^^^ contains invalid anchor
    |
 note: the lint level is defined here
-  --> $DIR/intra-links-anchors.rs:1:9
+  --> $DIR/anchors.rs:1:9
    |
 LL | #![deny(broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: `hello#people#!` contains multiple anchors
-  --> $DIR/intra-links-anchors.rs:31:28
+  --> $DIR/anchors.rs:31:28
    |
 LL | /// Another anchor error: [hello#people#!].
    |                            ^^^^^^^^^^^^^^ contains invalid anchor
 
 error: `Enum::A#whatever` contains an anchor, but links to variants are already anchored
-  --> $DIR/intra-links-anchors.rs:37:28
+  --> $DIR/anchors.rs:37:28
    |
 LL | /// Damn enum's variants: [Enum::A#whatever].
    |                            ^^^^^^^^^^^^^^^^ contains invalid anchor
 
 error: `u32#hello` contains an anchor, but links to builtin types are already anchored
-  --> $DIR/intra-links-anchors.rs:43:6
+  --> $DIR/anchors.rs:43:6
    |
 LL | /// [u32#hello]
    |      ^^^^^^^^^ contains invalid anchor
diff --git a/src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs b/src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs
index 31a8310d472..31a8310d472 100644
--- a/src/test/rustdoc-ui/auxiliary/intra-doc-broken.rs
+++ b/src/test/rustdoc-ui/intra-doc/auxiliary/intra-doc-broken.rs
diff --git a/src/test/rustdoc-ui/intra-doc-broken-reexport.rs b/src/test/rustdoc-ui/intra-doc/broken-reexport.rs
index ef261359ebd..ef261359ebd 100644
--- a/src/test/rustdoc-ui/intra-doc-broken-reexport.rs
+++ b/src/test/rustdoc-ui/intra-doc/broken-reexport.rs
diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
index b9c8e033b1b..b9c8e033b1b 100644
--- a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs
+++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.rs
diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
index 2e732baf6e0..2f5f3daa297 100644
--- a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr
+++ b/src/test/rustdoc-ui/intra-doc/disambiguator-mismatch.stderr
@@ -1,18 +1,18 @@
 error: incompatible link kind for `S`
-  --> $DIR/intra-links-disambiguator-mismatch.rs:14:14
+  --> $DIR/disambiguator-mismatch.rs:14:14
    |
 LL | /// Link to [struct@S]
    |              ^^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S`
    |
 note: the lint level is defined here
-  --> $DIR/intra-links-disambiguator-mismatch.rs:1:9
+  --> $DIR/disambiguator-mismatch.rs:1:9
    |
 LL | #![deny(broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
    = note: this link resolved to an enum, which is not a struct
 
 error: incompatible link kind for `S`
-  --> $DIR/intra-links-disambiguator-mismatch.rs:19:14
+  --> $DIR/disambiguator-mismatch.rs:19:14
    |
 LL | /// Link to [mod@S]
    |              ^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S`
@@ -20,7 +20,7 @@ LL | /// Link to [mod@S]
    = note: this link resolved to an enum, which is not a module
 
 error: incompatible link kind for `S`
-  --> $DIR/intra-links-disambiguator-mismatch.rs:24:14
+  --> $DIR/disambiguator-mismatch.rs:24:14
    |
 LL | /// Link to [union@S]
    |              ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S`
@@ -28,7 +28,7 @@ LL | /// Link to [union@S]
    = note: this link resolved to an enum, which is not a union
 
 error: incompatible link kind for `S`
-  --> $DIR/intra-links-disambiguator-mismatch.rs:29:14
+  --> $DIR/disambiguator-mismatch.rs:29:14
    |
 LL | /// Link to [trait@S]
    |              ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S`
@@ -36,7 +36,7 @@ LL | /// Link to [trait@S]
    = note: this link resolved to an enum, which is not a trait
 
 error: incompatible link kind for `T`
-  --> $DIR/intra-links-disambiguator-mismatch.rs:34:14
+  --> $DIR/disambiguator-mismatch.rs:34:14
    |
 LL | /// Link to [struct@T]
    |              ^^^^^^^^ help: to link to the trait, prefix with `trait@`: `trait@T`
@@ -44,7 +44,7 @@ LL | /// Link to [struct@T]
    = note: this link resolved to a trait, which is not a struct
 
 error: incompatible link kind for `m`
-  --> $DIR/intra-links-disambiguator-mismatch.rs:39:14
+  --> $DIR/disambiguator-mismatch.rs:39:14
    |
 LL | /// Link to [derive@m]
    |              ^^^^^^^^ help: to link to the macro, add an exclamation mark: `m!`
@@ -52,7 +52,7 @@ LL | /// Link to [derive@m]
    = note: this link resolved to a macro, which is not a derive macro
 
 error: incompatible link kind for `s`
-  --> $DIR/intra-links-disambiguator-mismatch.rs:44:14
+  --> $DIR/disambiguator-mismatch.rs:44:14
    |
 LL | /// Link to [const@s]
    |              ^^^^^^^ help: to link to the static, prefix with `static@`: `static@s`
@@ -60,7 +60,7 @@ LL | /// Link to [const@s]
    = note: this link resolved to a static, which is not a constant
 
 error: incompatible link kind for `c`
-  --> $DIR/intra-links-disambiguator-mismatch.rs:49:14
+  --> $DIR/disambiguator-mismatch.rs:49:14
    |
 LL | /// Link to [static@c]
    |              ^^^^^^^^ help: to link to the constant, prefix with `const@`: `const@c`
@@ -68,7 +68,7 @@ LL | /// Link to [static@c]
    = note: this link resolved to a constant, which is not a static
 
 error: incompatible link kind for `c`
-  --> $DIR/intra-links-disambiguator-mismatch.rs:54:14
+  --> $DIR/disambiguator-mismatch.rs:54:14
    |
 LL | /// Link to [fn@c]
    |              ^^^^ help: to link to the constant, prefix with `const@`: `const@c`
@@ -76,7 +76,7 @@ LL | /// Link to [fn@c]
    = note: this link resolved to a constant, which is not a function
 
 error: incompatible link kind for `c`
-  --> $DIR/intra-links-disambiguator-mismatch.rs:59:14
+  --> $DIR/disambiguator-mismatch.rs:59:14
    |
 LL | /// Link to [c()]
    |              ^^^ help: to link to the constant, prefix with `const@`: `const@c`
@@ -84,7 +84,7 @@ LL | /// Link to [c()]
    = note: this link resolved to a constant, which is not a function
 
 error: incompatible link kind for `f`
-  --> $DIR/intra-links-disambiguator-mismatch.rs:64:14
+  --> $DIR/disambiguator-mismatch.rs:64:14
    |
 LL | /// Link to [const@f]
    |              ^^^^^^^ help: to link to the function, add parentheses: `f()`
diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.rs b/src/test/rustdoc-ui/intra-doc/double-anchor.rs
index a01211c4f32..a01211c4f32 100644
--- a/src/test/rustdoc-ui/intra-link-double-anchor.rs
+++ b/src/test/rustdoc-ui/intra-doc/double-anchor.rs
diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.stderr b/src/test/rustdoc-ui/intra-doc/double-anchor.stderr
index 3282ec8b793..1cd9231eded 100644
--- a/src/test/rustdoc-ui/intra-link-double-anchor.stderr
+++ b/src/test/rustdoc-ui/intra-doc/double-anchor.stderr
@@ -1,5 +1,5 @@
 warning: `with#anchor#error` contains multiple anchors
-  --> $DIR/intra-link-double-anchor.rs:5:18
+  --> $DIR/double-anchor.rs:5:18
    |
 LL | /// docs [label][with#anchor#error]
    |                  ^^^^^^^^^^^^^^^^^ contains invalid anchor
diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-doc/errors.rs
index 81e42643ae8..81e42643ae8 100644
--- a/src/test/rustdoc-ui/intra-link-errors.rs
+++ b/src/test/rustdoc-ui/intra-doc/errors.rs
diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-doc/errors.stderr
index be98cac94ec..21c806108e3 100644
--- a/src/test/rustdoc-ui/intra-link-errors.stderr
+++ b/src/test/rustdoc-ui/intra-doc/errors.stderr
@@ -1,95 +1,95 @@
 error: unresolved link to `path::to::nonexistent::module`
-  --> $DIR/intra-link-errors.rs:7:6
+  --> $DIR/errors.rs:7:6
    |
 LL | /// [path::to::nonexistent::module]
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
    |
 note: the lint level is defined here
-  --> $DIR/intra-link-errors.rs:1:9
+  --> $DIR/errors.rs:1:9
    |
 LL | #![deny(broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: unresolved link to `path::to::nonexistent::macro`
-  --> $DIR/intra-link-errors.rs:11:6
+  --> $DIR/errors.rs:11:6
    |
 LL | /// [path::to::nonexistent::macro!]
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
 
 error: unresolved link to `path::to::nonexistent::type`
-  --> $DIR/intra-link-errors.rs:15:6
+  --> $DIR/errors.rs:15:6
    |
 LL | /// [type@path::to::nonexistent::type]
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no item named `path` in scope
 
 error: unresolved link to `std::io::not::here`
-  --> $DIR/intra-link-errors.rs:19:6
+  --> $DIR/errors.rs:19:6
    |
 LL | /// [std::io::not::here]
    |      ^^^^^^^^^^^^^^^^^^ no item named `not` in module `io`
 
 error: unresolved link to `std::io::not::here`
-  --> $DIR/intra-link-errors.rs:23:6
+  --> $DIR/errors.rs:23:6
    |
 LL | /// [type@std::io::not::here]
    |      ^^^^^^^^^^^^^^^^^^^^^^^ no item named `not` in module `io`
 
 error: unresolved link to `std::io::Error::x`
-  --> $DIR/intra-link-errors.rs:27:6
+  --> $DIR/errors.rs:27:6
    |
 LL | /// [std::io::Error::x]
    |      ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x`
 
 error: unresolved link to `std::io::ErrorKind::x`
-  --> $DIR/intra-link-errors.rs:31:6
+  --> $DIR/errors.rs:31:6
    |
 LL | /// [std::io::ErrorKind::x]
    |      ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x`
 
 error: unresolved link to `f::A`
-  --> $DIR/intra-link-errors.rs:35:6
+  --> $DIR/errors.rs:35:6
    |
 LL | /// [f::A]
    |      ^^^^ `f` is a function, not a module or type, and cannot have associated items
 
 error: unresolved link to `f::A`
-  --> $DIR/intra-link-errors.rs:39:6
+  --> $DIR/errors.rs:39:6
    |
 LL | /// [f::A!]
    |      ^^^^^ `f` is a function, not a module or type, and cannot have associated items
 
 error: unresolved link to `S::A`
-  --> $DIR/intra-link-errors.rs:43:6
+  --> $DIR/errors.rs:43:6
    |
 LL | /// [S::A]
    |      ^^^^ the struct `S` has no field or associated item named `A`
 
 error: unresolved link to `S::fmt`
-  --> $DIR/intra-link-errors.rs:47:6
+  --> $DIR/errors.rs:47:6
    |
 LL | /// [S::fmt]
    |      ^^^^^^ the struct `S` has no field or associated item named `fmt`
 
 error: unresolved link to `E::D`
-  --> $DIR/intra-link-errors.rs:51:6
+  --> $DIR/errors.rs:51:6
    |
 LL | /// [E::D]
    |      ^^^^ the enum `E` has no variant or associated item named `D`
 
 error: unresolved link to `u8::not_found`
-  --> $DIR/intra-link-errors.rs:55:6
+  --> $DIR/errors.rs:55:6
    |
 LL | /// [u8::not_found]
    |      ^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found`
 
 error: unresolved link to `std::primitive::u8::not_found`
-  --> $DIR/intra-link-errors.rs:59:6
+  --> $DIR/errors.rs:59:6
    |
 LL | /// [std::primitive::u8::not_found]
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found`
 
 error: unresolved link to `Vec::into_iter`
-  --> $DIR/intra-link-errors.rs:63:6
+  --> $DIR/errors.rs:63:6
    |
 LL | /// [type@Vec::into_iter]
    |      ^^^^^^^^^^^^^^^^^^^
@@ -98,7 +98,7 @@ LL | /// [type@Vec::into_iter]
    |      help: to link to the associated function, add parentheses: `Vec::into_iter()`
 
 error: unresolved link to `S`
-  --> $DIR/intra-link-errors.rs:68:6
+  --> $DIR/errors.rs:68:6
    |
 LL | /// [S!]
    |      ^^
@@ -107,7 +107,7 @@ LL | /// [S!]
    |      help: to link to the struct, prefix with `struct@`: `struct@S`
 
 error: unresolved link to `S::h`
-  --> $DIR/intra-link-errors.rs:78:6
+  --> $DIR/errors.rs:78:6
    |
 LL | /// [type@S::h]
    |      ^^^^^^^^^
@@ -116,7 +116,7 @@ LL | /// [type@S::h]
    |      help: to link to the associated function, add parentheses: `S::h()`
 
 error: unresolved link to `T::g`
-  --> $DIR/intra-link-errors.rs:86:6
+  --> $DIR/errors.rs:86:6
    |
 LL | /// [type@T::g]
    |      ^^^^^^^^^
@@ -125,13 +125,13 @@ LL | /// [type@T::g]
    |      help: to link to the associated function, add parentheses: `T::g()`
 
 error: unresolved link to `T::h`
-  --> $DIR/intra-link-errors.rs:91:6
+  --> $DIR/errors.rs:91:6
    |
 LL | /// [T::h!]
    |      ^^^^^ the trait `T` has no macro named `h`
 
 error: unresolved link to `m`
-  --> $DIR/intra-link-errors.rs:98:6
+  --> $DIR/errors.rs:98:6
    |
 LL | /// [m()]
    |      ^^^
diff --git a/src/test/rustdoc-ui/intra-link-malformed-generics.rs b/src/test/rustdoc-ui/intra-doc/malformed-generics.rs
index 9c54092146f..9c54092146f 100644
--- a/src/test/rustdoc-ui/intra-link-malformed-generics.rs
+++ b/src/test/rustdoc-ui/intra-doc/malformed-generics.rs
diff --git a/src/test/rustdoc-ui/intra-link-malformed-generics.stderr b/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr
index fe5d4cd1bbf..2e1b22807bc 100644
--- a/src/test/rustdoc-ui/intra-link-malformed-generics.stderr
+++ b/src/test/rustdoc-ui/intra-doc/malformed-generics.stderr
@@ -1,89 +1,89 @@
 error: unresolved link to `Vec<`
-  --> $DIR/intra-link-malformed-generics.rs:3:6
+  --> $DIR/malformed-generics.rs:3:6
    |
 LL | //! [Vec<]
    |      ^^^^ unbalanced angle brackets
    |
 note: the lint level is defined here
-  --> $DIR/intra-link-malformed-generics.rs:1:9
+  --> $DIR/malformed-generics.rs:1:9
    |
 LL | #![deny(broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
 
 error: unresolved link to `Vec<Box<T`
-  --> $DIR/intra-link-malformed-generics.rs:4:6
+  --> $DIR/malformed-generics.rs:4:6
    |
 LL | //! [Vec<Box<T]
    |      ^^^^^^^^^ unbalanced angle brackets
 
 error: unresolved link to `Vec<Box<T>`
-  --> $DIR/intra-link-malformed-generics.rs:5:6
+  --> $DIR/malformed-generics.rs:5:6
    |
 LL | //! [Vec<Box<T>]
    |      ^^^^^^^^^^ unbalanced angle brackets
 
 error: unresolved link to `Vec<Box<T>>>`
-  --> $DIR/intra-link-malformed-generics.rs:6:6
+  --> $DIR/malformed-generics.rs:6:6
    |
 LL | //! [Vec<Box<T>>>]
    |      ^^^^^^^^^^^^ unbalanced angle brackets
 
 error: unresolved link to `Vec<T>>>`
-  --> $DIR/intra-link-malformed-generics.rs:7:6
+  --> $DIR/malformed-generics.rs:7:6
    |
 LL | //! [Vec<T>>>]
    |      ^^^^^^^^ unbalanced angle brackets
 
 error: unresolved link to `<Vec`
-  --> $DIR/intra-link-malformed-generics.rs:8:6
+  --> $DIR/malformed-generics.rs:8:6
    |
 LL | //! [<Vec]
    |      ^^^^ unbalanced angle brackets
 
 error: unresolved link to `Vec::<`
-  --> $DIR/intra-link-malformed-generics.rs:9:6
+  --> $DIR/malformed-generics.rs:9:6
    |
 LL | //! [Vec::<]
    |      ^^^^^^ unbalanced angle brackets
 
 error: unresolved link to `<T>`
-  --> $DIR/intra-link-malformed-generics.rs:10:6
+  --> $DIR/malformed-generics.rs:10:6
    |
 LL | //! [<T>]
    |      ^^^ missing type for generic parameters
 
 error: unresolved link to `<invalid syntax>`
-  --> $DIR/intra-link-malformed-generics.rs:11:6
+  --> $DIR/malformed-generics.rs:11:6
    |
 LL | //! [<invalid syntax>]
    |      ^^^^^^^^^^^^^^^^ missing type for generic parameters
 
 error: unresolved link to `Vec:<T>:new`
-  --> $DIR/intra-link-malformed-generics.rs:12:6
+  --> $DIR/malformed-generics.rs:12:6
    |
 LL | //! [Vec:<T>:new()]
    |      ^^^^^^^^^^^^^ has invalid path separator
 
 error: unresolved link to `Vec<<T>>`
-  --> $DIR/intra-link-malformed-generics.rs:13:6
+  --> $DIR/malformed-generics.rs:13:6
    |
 LL | //! [Vec<<T>>]
    |      ^^^^^^^^ too many angle brackets
 
 error: unresolved link to `Vec<>`
-  --> $DIR/intra-link-malformed-generics.rs:14:6
+  --> $DIR/malformed-generics.rs:14:6
    |
 LL | //! [Vec<>]
    |      ^^^^^ empty angle brackets
 
 error: unresolved link to `Vec<<>>`
-  --> $DIR/intra-link-malformed-generics.rs:15:6
+  --> $DIR/malformed-generics.rs:15:6
    |
 LL | //! [Vec<<>>]
    |      ^^^^^^^ too many angle brackets
 
 error: unresolved link to `<Vec as IntoIterator>::into_iter`
-  --> $DIR/intra-link-malformed-generics.rs:18:6
+  --> $DIR/malformed-generics.rs:18:6
    |
 LL | //! [<Vec as IntoIterator>::into_iter]
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported
@@ -91,7 +91,7 @@ LL | //! [<Vec as IntoIterator>::into_iter]
    = note: see https://github.com/rust-lang/rust/issues/74563 for more information
 
 error: unresolved link to `<Vec<T> as IntoIterator>::iter`
-  --> $DIR/intra-link-malformed-generics.rs:19:6
+  --> $DIR/malformed-generics.rs:19:6
    |
 LL | //! [<Vec<T> as IntoIterator>::iter]
    |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ fully-qualified syntax is unsupported
diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.rs b/src/test/rustdoc-ui/intra-doc/prim-conflict.rs
index 85738ceae8e..85738ceae8e 100644
--- a/src/test/rustdoc-ui/intra-link-prim-conflict.rs
+++ b/src/test/rustdoc-ui/intra-doc/prim-conflict.rs
diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr b/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr
index 43587a80021..01275f8d9af 100644
--- a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr
+++ b/src/test/rustdoc-ui/intra-doc/prim-conflict.stderr
@@ -1,11 +1,11 @@
 error: `char` is both a module and a builtin type
-  --> $DIR/intra-link-prim-conflict.rs:4:6
+  --> $DIR/prim-conflict.rs:4:6
    |
 LL | /// [char]
    |      ^^^^ ambiguous link
    |
 note: the lint level is defined here
-  --> $DIR/intra-link-prim-conflict.rs:1:9
+  --> $DIR/prim-conflict.rs:1:9
    |
 LL | #![deny(broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
@@ -19,7 +19,7 @@ LL | /// [prim@char]
    |      ^^^^^^^^^
 
 error: `char` is both a module and a builtin type
-  --> $DIR/intra-link-prim-conflict.rs:10:6
+  --> $DIR/prim-conflict.rs:10:6
    |
 LL | /// [type@char]
    |      ^^^^^^^^^ ambiguous link
@@ -34,7 +34,7 @@ LL | /// [prim@char]
    |      ^^^^^^^^^
 
 error: incompatible link kind for `char`
-  --> $DIR/intra-link-prim-conflict.rs:19:6
+  --> $DIR/prim-conflict.rs:19:6
    |
 LL | /// [struct@char]
    |      ^^^^^^^^^^^ help: to link to the module, prefix with `mod@`: `mod@char`
@@ -42,7 +42,7 @@ LL | /// [struct@char]
    = note: this link resolved to a module, which is not a struct
 
 error: incompatible link kind for `char`
-  --> $DIR/intra-link-prim-conflict.rs:26:10
+  --> $DIR/prim-conflict.rs:26:10
    |
 LL |     //! [struct@char]
    |          ^^^^^^^^^^^ help: to link to the builtin type, prefix with `prim@`: `prim@char`
diff --git a/src/test/rustdoc-ui/intra-links-private.private.stderr b/src/test/rustdoc-ui/intra-doc/private.private.stderr
index eeef24b4797..6e11ec3e87b 100644
--- a/src/test/rustdoc-ui/intra-links-private.private.stderr
+++ b/src/test/rustdoc-ui/intra-doc/private.private.stderr
@@ -1,5 +1,5 @@
 warning: public documentation for `DocMe` links to private item `DontDocMe`
-  --> $DIR/intra-links-private.rs:5:11
+  --> $DIR/private.rs:5:11
    |
 LL | /// docs [DontDocMe]
    |           ^^^^^^^^^ this item is private
diff --git a/src/test/rustdoc-ui/intra-links-private.public.stderr b/src/test/rustdoc-ui/intra-doc/private.public.stderr
index 3f7b17586f1..3a6a4b66452 100644
--- a/src/test/rustdoc-ui/intra-links-private.public.stderr
+++ b/src/test/rustdoc-ui/intra-doc/private.public.stderr
@@ -1,5 +1,5 @@
 warning: public documentation for `DocMe` links to private item `DontDocMe`
-  --> $DIR/intra-links-private.rs:5:11
+  --> $DIR/private.rs:5:11
    |
 LL | /// docs [DontDocMe]
    |           ^^^^^^^^^ this item is private
diff --git a/src/test/rustdoc-ui/intra-links-private.rs b/src/test/rustdoc-ui/intra-doc/private.rs
index 613236d75d2..613236d75d2 100644
--- a/src/test/rustdoc-ui/intra-links-private.rs
+++ b/src/test/rustdoc-ui/intra-doc/private.rs
diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs b/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs
index 7764a6df6ee..7764a6df6ee 100644
--- a/src/test/rustdoc-ui/intra-link-span-ice-55723.rs
+++ b/src/test/rustdoc-ui/intra-doc/span-ice-55723.rs
diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr
index d8afa9e7efd..10ca14e850f 100644
--- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr
+++ b/src/test/rustdoc-ui/intra-doc/span-ice-55723.stderr
@@ -1,11 +1,11 @@
 error: unresolved link to `i`
-  --> $DIR/intra-link-span-ice-55723.rs:9:10
+  --> $DIR/span-ice-55723.rs:9:10
    |
 LL | /// (arr[i])
    |           ^ no item named `i` in scope
    |
 note: the lint level is defined here
-  --> $DIR/intra-link-span-ice-55723.rs:1:9
+  --> $DIR/span-ice-55723.rs:1:9
    |
 LL | #![deny(broken_intra_doc_links)]
    |         ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.rs b/src/test/rustdoc-ui/intra-doc/warning-crlf.rs
index a19c33b53be..a19c33b53be 100644
--- a/src/test/rustdoc-ui/intra-links-warning-crlf.rs
+++ b/src/test/rustdoc-ui/intra-doc/warning-crlf.rs
diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr
index 67c48378fd2..01e42820037 100644
--- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr
+++ b/src/test/rustdoc-ui/intra-doc/warning-crlf.stderr
@@ -1,5 +1,5 @@
 warning: unresolved link to `error`
-  --> $DIR/intra-links-warning-crlf.rs:7:6
+  --> $DIR/warning-crlf.rs:7:6
    |
 LL | /// [error]
    |      ^^^^^ no item named `error` in scope
@@ -8,7 +8,7 @@ LL | /// [error]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error1`
-  --> $DIR/intra-links-warning-crlf.rs:12:11
+  --> $DIR/warning-crlf.rs:12:11
    |
 LL | /// docs [error1]
    |           ^^^^^^ no item named `error1` in scope
@@ -16,7 +16,7 @@ LL | /// docs [error1]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error2`
-  --> $DIR/intra-links-warning-crlf.rs:15:11
+  --> $DIR/warning-crlf.rs:15:11
    |
 LL | /// docs [error2]
    |           ^^^^^^ no item named `error2` in scope
@@ -24,7 +24,7 @@ LL | /// docs [error2]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
-  --> $DIR/intra-links-warning-crlf.rs:23:20
+  --> $DIR/warning-crlf.rs:23:20
    |
 LL |  * It also has an [error].
    |                    ^^^^^ no item named `error` in scope
diff --git a/src/test/rustdoc-ui/intra-links-warning.rs b/src/test/rustdoc-ui/intra-doc/warning.rs
index eab1f034804..eab1f034804 100644
--- a/src/test/rustdoc-ui/intra-links-warning.rs
+++ b/src/test/rustdoc-ui/intra-doc/warning.rs
diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-doc/warning.stderr
index 0b074e9d53e..430d18165a0 100644
--- a/src/test/rustdoc-ui/intra-links-warning.stderr
+++ b/src/test/rustdoc-ui/intra-doc/warning.stderr
@@ -1,5 +1,5 @@
 warning: unresolved link to `Foo::baz`
-  --> $DIR/intra-links-warning.rs:3:23
+  --> $DIR/warning.rs:3:23
    |
 LL |        //! Test with [Foo::baz], [Bar::foo], ...
    |                       ^^^^^^^^ the struct `Foo` has no field or associated item named `baz`
@@ -7,37 +7,37 @@ LL |        //! Test with [Foo::baz], [Bar::foo], ...
    = note: `#[warn(broken_intra_doc_links)]` on by default
 
 warning: unresolved link to `Bar::foo`
-  --> $DIR/intra-links-warning.rs:3:35
+  --> $DIR/warning.rs:3:35
    |
 LL |        //! Test with [Foo::baz], [Bar::foo], ...
    |                                   ^^^^^^^^ no item named `Bar` in scope
 
 warning: unresolved link to `Uniooon::X`
-  --> $DIR/intra-links-warning.rs:6:13
+  --> $DIR/warning.rs:6:13
    |
 LL |      //! , [Uniooon::X] and [Qux::Z].
    |             ^^^^^^^^^^ no item named `Uniooon` in scope
 
 warning: unresolved link to `Qux::Z`
-  --> $DIR/intra-links-warning.rs:6:30
+  --> $DIR/warning.rs:6:30
    |
 LL |      //! , [Uniooon::X] and [Qux::Z].
    |                              ^^^^^^ no item named `Qux` in scope
 
 warning: unresolved link to `Uniooon::X`
-  --> $DIR/intra-links-warning.rs:10:14
+  --> $DIR/warning.rs:10:14
    |
 LL |       //! , [Uniooon::X] and [Qux::Z].
    |              ^^^^^^^^^^ no item named `Uniooon` in scope
 
 warning: unresolved link to `Qux::Z`
-  --> $DIR/intra-links-warning.rs:10:31
+  --> $DIR/warning.rs:10:31
    |
 LL |       //! , [Uniooon::X] and [Qux::Z].
    |                               ^^^^^^ no item named `Qux` in scope
 
 warning: unresolved link to `Qux:Y`
-  --> $DIR/intra-links-warning.rs:14:13
+  --> $DIR/warning.rs:14:13
    |
 LL |        /// [Qux:Y]
    |             ^^^^^ no item named `Qux:Y` in scope
@@ -45,7 +45,7 @@ LL |        /// [Qux:Y]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `BarA`
-  --> $DIR/intra-links-warning.rs:21:10
+  --> $DIR/warning.rs:21:10
    |
 LL | /// bar [BarA] bar
    |          ^^^^ no item named `BarA` in scope
@@ -53,7 +53,7 @@ LL | /// bar [BarA] bar
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `BarB`
-  --> $DIR/intra-links-warning.rs:27:9
+  --> $DIR/warning.rs:27:9
    |
 LL |  * bar [BarB] bar
    |         ^^^^ no item named `BarB` in scope
@@ -61,7 +61,7 @@ LL |  * bar [BarB] bar
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `BarC`
-  --> $DIR/intra-links-warning.rs:34:6
+  --> $DIR/warning.rs:34:6
    |
 LL | bar [BarC] bar
    |      ^^^^ no item named `BarC` in scope
@@ -69,7 +69,7 @@ LL | bar [BarC] bar
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `BarD`
-  --> $DIR/intra-links-warning.rs:45:1
+  --> $DIR/warning.rs:45:1
    |
 LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -82,7 +82,7 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `BarF`
-  --> $DIR/intra-links-warning.rs:50:9
+  --> $DIR/warning.rs:50:9
    |
 LL |         #[doc = $f]
    |         ^^^^^^^^^^^
@@ -99,7 +99,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz");
    = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: unresolved link to `error`
-  --> $DIR/intra-links-warning.rs:58:30
+  --> $DIR/warning.rs:58:30
    |
 LL |  * time to introduce a link [error]*/
    |                              ^^^^^ no item named `error` in scope
@@ -107,7 +107,7 @@ LL |  * time to introduce a link [error]*/
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
-  --> $DIR/intra-links-warning.rs:64:30
+  --> $DIR/warning.rs:64:30
    |
 LL |  * time to introduce a link [error]
    |                              ^^^^^ no item named `error` in scope
@@ -115,7 +115,7 @@ LL |  * time to introduce a link [error]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
-  --> $DIR/intra-links-warning.rs:68:1
+  --> $DIR/warning.rs:68:1
    |
 LL | #[doc = "single line [error]"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -128,7 +128,7 @@ LL | #[doc = "single line [error]"]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
-  --> $DIR/intra-links-warning.rs:71:1
+  --> $DIR/warning.rs:71:1
    |
 LL | #[doc = "single line with \"escaping\" [error]"]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -141,7 +141,7 @@ LL | #[doc = "single line with \"escaping\" [error]"]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error`
-  --> $DIR/intra-links-warning.rs:74:1
+  --> $DIR/warning.rs:74:1
    |
 LL | / /// Item docs.
 LL | | #[doc="Hello there!"]
@@ -156,7 +156,7 @@ LL | | /// [error]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error1`
-  --> $DIR/intra-links-warning.rs:80:11
+  --> $DIR/warning.rs:80:11
    |
 LL | /// docs [error1]
    |           ^^^^^^ no item named `error1` in scope
@@ -164,7 +164,7 @@ LL | /// docs [error1]
    = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]`
 
 warning: unresolved link to `error2`
-  --> $DIR/intra-links-warning.rs:82:11
+  --> $DIR/warning.rs:82:11
    |
 LL | /// docs [error2]
    |           ^^^^^^ no item named `error2` in scope
diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs
index b3fbe377f0b..11ba68a388f 100644
--- a/src/test/rustdoc/const-display.rs
+++ b/src/test/rustdoc/const-display.rs
@@ -1,3 +1,5 @@
+// ignore-tidy-linelength
+
 #![crate_name = "foo"]
 
 #![unstable(feature = "humans",
@@ -17,6 +19,7 @@ pub const unsafe fn foo() -> u32 { 42 }
 pub const fn foo2() -> u32 { 42 }
 
 // @has 'foo/fn.bar2.html' '//pre' 'pub const fn bar2() -> u32'
+// @has - //span '1.0.0 (const: 1.0.0)'
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 pub const fn bar2() -> u32 { 42 }
@@ -26,6 +29,7 @@ pub const fn bar2() -> u32 { 42 }
 pub const unsafe fn foo2_gated() -> u32 { 42 }
 
 // @has 'foo/fn.bar2_gated.html' '//pre' 'pub const unsafe fn bar2_gated() -> u32'
+// @has - '//span[@class="since"]' '1.0.0 (const: 1.0.0)'
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_const_stable(feature = "rust1", since = "1.0.0")]
 pub const unsafe fn bar2_gated() -> u32 { 42 }
@@ -40,4 +44,10 @@ impl Foo {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature="foo", issue = "none")]
     pub const unsafe fn gated() -> u32 { 42 }
+
+    // @has 'foo/struct.Foo.html' '//h4[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32'
+    // @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)'
+    #[stable(feature = "rust1", since = "1.0.0")]
+    #[rustc_const_stable(feature = "rust1", since = "1.2.0")]
+    pub const fn stable_impl() -> u32 { 42 }
 }
diff --git a/src/test/rustdoc/intra-doc-link-mod-ambiguity.rs b/src/test/rustdoc/intra-doc-link-mod-ambiguity.rs
deleted file mode 100644
index bd733e10230..00000000000
--- a/src/test/rustdoc/intra-doc-link-mod-ambiguity.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-// ignore-tidy-linelength
-
-#![deny(broken_intra_doc_links)]
-
-
-pub fn foo() {
-
-}
-
-pub mod foo {}
-// @has intra_doc_link_mod_ambiguity/struct.A.html '//a/@href' '../intra_doc_link_mod_ambiguity/foo/index.html'
-/// Module is [`module@foo`]
-pub struct A;
-
-
-// @has intra_doc_link_mod_ambiguity/struct.B.html '//a/@href' '../intra_doc_link_mod_ambiguity/fn.foo.html'
-/// Function is [`fn@foo`]
-pub struct B;
diff --git a/src/test/rustdoc/intra-links-anchors.rs b/src/test/rustdoc/intra-doc/anchors.rs
index f554e16b4f4..e4f0c737bdd 100644
--- a/src/test/rustdoc/intra-links-anchors.rs
+++ b/src/test/rustdoc/intra-doc/anchors.rs
@@ -3,8 +3,8 @@
 /// # Anchor!
 pub struct Something;
 
-// @has intra_links_anchors/struct.SomeOtherType.html
-// @has - '//a/@href' '../intra_links_anchors/struct.Something.html#Anchor!'
+// @has anchors/struct.SomeOtherType.html
+// @has - '//a/@href' '../anchors/struct.Something.html#Anchor!'
 
 /// I want...
 ///
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/auxiliary/intra-link-extern-crate.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs
index db3bb38ada0..db3bb38ada0 100644
--- a/src/test/rustdoc/auxiliary/intra-link-extern-crate.rs
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-extern-crate.rs
diff --git a/src/test/rustdoc/auxiliary/intra-link-pub-use.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs
index a4db2ffc445..a4db2ffc445 100644
--- a/src/test/rustdoc/auxiliary/intra-link-pub-use.rs
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-pub-use.rs
diff --git a/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs
index fc51995a94e..fc51995a94e 100644
--- a/src/test/rustdoc/auxiliary/intra-link-reexport-additional-docs.rs
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-link-reexport-additional-docs.rs
diff --git a/src/test/rustdoc/auxiliary/intra-links-external-traits.rs b/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs
index 6142dcda986..6142dcda986 100644
--- a/src/test/rustdoc/auxiliary/intra-links-external-traits.rs
+++ b/src/test/rustdoc/intra-doc/auxiliary/intra-links-external-traits.rs
diff --git a/src/test/rustdoc/auxiliary/my-core.rs b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs
index 54e986be9ec..54e986be9ec 100644
--- a/src/test/rustdoc/auxiliary/my-core.rs
+++ b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs
diff --git a/src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs b/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs
index 04a431d9902..5ba132f25b4 100644
--- a/src/test/rustdoc/auxiliary/intra-link-proc-macro-macro.rs
+++ b/src/test/rustdoc/intra-doc/auxiliary/proc-macro-macro.rs
@@ -3,7 +3,6 @@
 // compile-flags: --crate-type proc-macro
 
 #![crate_type="proc-macro"]
-#![crate_name="intra_link_proc_macro_macro"]
 
 extern crate proc_macro;
 
diff --git a/src/test/rustdoc/auxiliary/through-proc-macro-aux.rs b/src/test/rustdoc/intra-doc/auxiliary/through-proc-macro-aux.rs
index 5c4a01ee3a7..5c4a01ee3a7 100644
--- a/src/test/rustdoc/auxiliary/through-proc-macro-aux.rs
+++ b/src/test/rustdoc/intra-doc/auxiliary/through-proc-macro-aux.rs
diff --git a/src/test/rustdoc/intra-links.rs b/src/test/rustdoc/intra-doc/basic.rs
index 751c10925c0..7760546e1fa 100644
--- a/src/test/rustdoc/intra-links.rs
+++ b/src/test/rustdoc/intra-doc/basic.rs
@@ -1,21 +1,21 @@
-// @has intra_links/index.html
-// @has - '//a/@href' '../intra_links/struct.ThisType.html'
-// @has - '//a/@href' '../intra_links/struct.ThisType.html#method.this_method'
-// @has - '//a/@href' '../intra_links/enum.ThisEnum.html'
-// @has - '//a/@href' '../intra_links/enum.ThisEnum.html#variant.ThisVariant'
-// @has - '//a/@href' '../intra_links/trait.ThisTrait.html'
-// @has - '//a/@href' '../intra_links/trait.ThisTrait.html#tymethod.this_associated_method'
-// @has - '//a/@href' '../intra_links/trait.ThisTrait.html#associatedtype.ThisAssociatedType'
-// @has - '//a/@href' '../intra_links/trait.ThisTrait.html#associatedconstant.THIS_ASSOCIATED_CONST'
-// @has - '//a/@href' '../intra_links/trait.ThisTrait.html'
-// @has - '//a/@href' '../intra_links/type.ThisAlias.html'
-// @has - '//a/@href' '../intra_links/union.ThisUnion.html'
-// @has - '//a/@href' '../intra_links/fn.this_function.html'
-// @has - '//a/@href' '../intra_links/constant.THIS_CONST.html'
-// @has - '//a/@href' '../intra_links/static.THIS_STATIC.html'
-// @has - '//a/@href' '../intra_links/macro.this_macro.html'
-// @has - '//a/@href' '../intra_links/trait.SoAmbiguous.html'
-// @has - '//a/@href' '../intra_links/fn.SoAmbiguous.html'
+// @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)
@@ -46,7 +46,7 @@ macro_rules! this_macro {
     () => {};
 }
 
-// @has intra_links/struct.ThisType.html '//a/@href' '../intra_links/macro.this_macro.html'
+// @has basic/struct.ThisType.html '//a/@href' '../basic/macro.this_macro.html'
 /// another link to [`this_macro!()`]
 pub struct ThisType;
 
@@ -72,10 +72,10 @@ pub trait SoAmbiguous {}
 pub fn SoAmbiguous() {}
 
 
-// @has intra_links/struct.SomeOtherType.html '//a/@href' '../intra_links/struct.ThisType.html'
-// @has - '//a/@href' '../intra_links/struct.ThisType.html#method.this_method'
-// @has - '//a/@href' '../intra_links/enum.ThisEnum.html'
-// @has - '//a/@href' '../intra_links/enum.ThisEnum.html#variant.ThisVariant'
+// @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`]
diff --git a/src/test/rustdoc/intra-link-builtin-macros.rs b/src/test/rustdoc/intra-doc/builtin-macros.rs
index 4d40eb3b88f..74216a587e1 100644
--- a/src/test/rustdoc/intra-link-builtin-macros.rs
+++ b/src/test/rustdoc/intra-doc/builtin-macros.rs
@@ -1,3 +1,3 @@
-// @has intra_link_builtin_macros/index.html
+// @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-crate/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs
index 837390b3c71..837390b3c71 100644
--- a/src/test/rustdoc/intra-doc-crate/additional_doc.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/additional_doc.rs
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs
index 849d2568733..849d2568733 100644
--- a/src/test/rustdoc/intra-doc-crate/auxiliary/additional_doc.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/additional_doc.rs
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs
index b543ae764c0..b543ae764c0 100644
--- a/src/test/rustdoc/intra-doc-crate/auxiliary/hidden.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/hidden.rs
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs
index 5342baecbc4..5342baecbc4 100644
--- a/src/test/rustdoc/intra-doc-crate/auxiliary/intra-doc-basic.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-doc-basic.rs
diff --git a/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs
index a37848e23d9..a37848e23d9 100644
--- a/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/intra-link-cross-crate-crate.rs
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs
index a94f9e5dcca..a94f9e5dcca 100644
--- a/src/test/rustdoc/intra-doc-crate/auxiliary/macro_inner.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/macro_inner.rs
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/module.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs
index b7e3913f108..b7e3913f108 100644
--- a/src/test/rustdoc/intra-doc-crate/auxiliary/module.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/module.rs
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs
index 0d5a954075d..0d5a954075d 100644
--- a/src/test/rustdoc/intra-doc-crate/auxiliary/proc_macro.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/proc_macro.rs
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs
index 8ae0f6c16b3..8ae0f6c16b3 100644
--- a/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-inner.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-inner.rs
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs
index d90c529e385..d90c529e385 100644
--- a/src/test/rustdoc/intra-doc-crate/auxiliary/submodule-outer.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/submodule-outer.rs
diff --git a/src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs
index c16e39d56f3..c16e39d56f3 100644
--- a/src/test/rustdoc/intra-doc-crate/auxiliary/traits.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/auxiliary/traits.rs
diff --git a/src/test/rustdoc/intra-doc-crate/basic.rs b/src/test/rustdoc/intra-doc/cross-crate/basic.rs
index 6ab9140c3c3..6ab9140c3c3 100644
--- a/src/test/rustdoc/intra-doc-crate/basic.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/basic.rs
diff --git a/src/test/rustdoc/intra-link-cross-crate-crate.rs b/src/test/rustdoc/intra-doc/cross-crate/crate.rs
index edf544708b6..edf544708b6 100644
--- a/src/test/rustdoc/intra-link-cross-crate-crate.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/crate.rs
diff --git a/src/test/rustdoc/intra-doc-crate/hidden.rs b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs
index 9c9d4c64945..9c9d4c64945 100644
--- a/src/test/rustdoc/intra-doc-crate/hidden.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/hidden.rs
diff --git a/src/test/rustdoc/intra-doc-crate/macro.rs b/src/test/rustdoc/intra-doc/cross-crate/macro.rs
index 311b16dff13..311b16dff13 100644
--- a/src/test/rustdoc/intra-doc-crate/macro.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/macro.rs
diff --git a/src/test/rustdoc/intra-doc-crate/module.rs b/src/test/rustdoc/intra-doc/cross-crate/module.rs
index 9039e344f7b..9039e344f7b 100644
--- a/src/test/rustdoc/intra-doc-crate/module.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/module.rs
diff --git a/src/test/rustdoc/intra-doc-crate/submodule-inner.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs
index e1465816368..e1465816368 100644
--- a/src/test/rustdoc/intra-doc-crate/submodule-inner.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/submodule-inner.rs
diff --git a/src/test/rustdoc/intra-doc-crate/submodule-outer.rs b/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs
index 45f561328f2..45f561328f2 100644
--- a/src/test/rustdoc/intra-doc-crate/submodule-outer.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/submodule-outer.rs
diff --git a/src/test/rustdoc/intra-doc-crate/traits.rs b/src/test/rustdoc/intra-doc/cross-crate/traits.rs
index 07decb48019..07decb48019 100644
--- a/src/test/rustdoc/intra-doc-crate/traits.rs
+++ b/src/test/rustdoc/intra-doc/cross-crate/traits.rs
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-link-enum-struct-field.rs b/src/test/rustdoc/intra-doc/enum-struct-field.rs
index 70bf343a9a5..70bf343a9a5 100644
--- a/src/test/rustdoc/intra-doc-link-enum-struct-field.rs
+++ b/src/test/rustdoc/intra-doc/enum-struct-field.rs
diff --git a/src/test/rustdoc/intra-link-extern-crate.rs b/src/test/rustdoc/intra-doc/extern-crate.rs
index 193bca704bf..193bca704bf 100644
--- a/src/test/rustdoc/intra-link-extern-crate.rs
+++ b/src/test/rustdoc/intra-doc/extern-crate.rs
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-links-external-traits.rs b/src/test/rustdoc/intra-doc/external-traits.rs
index de76f29476c..de76f29476c 100644
--- a/src/test/rustdoc/intra-links-external-traits.rs
+++ b/src/test/rustdoc/intra-doc/external-traits.rs
diff --git a/src/test/rustdoc/intra-doc-link-generic-params.rs b/src/test/rustdoc/intra-doc/generic-params.rs
index 1de6410f10c..1de6410f10c 100644
--- a/src/test/rustdoc/intra-doc-link-generic-params.rs
+++ b/src/test/rustdoc/intra-doc/generic-params.rs
diff --git a/src/test/rustdoc/intra-link-in-bodies.rs b/src/test/rustdoc/intra-doc/in-bodies.rs
index ec965a99dc2..ec965a99dc2 100644
--- a/src/test/rustdoc/intra-link-in-bodies.rs
+++ b/src/test/rustdoc/intra-doc/in-bodies.rs
diff --git a/src/test/rustdoc/intra-link-libstd-re-export.rs b/src/test/rustdoc/intra-doc/libstd-re-export.rs
index d0af3aec660..d0af3aec660 100644
--- a/src/test/rustdoc/intra-link-libstd-re-export.rs
+++ b/src/test/rustdoc/intra-doc/libstd-re-export.rs
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-link-prim-methods-external-core.rs b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs
index c8ef4c01599..434e0338983 100644
--- a/src/test/rustdoc/intra-link-prim-methods-external-core.rs
+++ b/src/test/rustdoc/intra-doc/prim-methods-external-core.rs
@@ -9,7 +9,7 @@
 #![no_core]
 #![crate_type = "rlib"]
 
-// @has intra_link_prim_methods_external_core/index.html
+// @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'
 
diff --git a/src/test/rustdoc/intra-link-prim-methods-local.rs b/src/test/rustdoc/intra-doc/prim-methods-local.rs
index d448acf7f96..9888f29db5b 100644
--- a/src/test/rustdoc/intra-link-prim-methods-local.rs
+++ b/src/test/rustdoc/intra-doc/prim-methods-local.rs
@@ -5,7 +5,7 @@
 
 // ignore-tidy-linelength
 
-// @has intra_link_prim_methods_local/index.html
+// @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'
 
diff --git a/src/test/rustdoc/intra-link-prim-methods.rs b/src/test/rustdoc/intra-doc/prim-methods.rs
index 94c80c996c1..f19cff7d34a 100644
--- a/src/test/rustdoc/intra-link-prim-methods.rs
+++ b/src/test/rustdoc/intra-doc/prim-methods.rs
@@ -2,7 +2,7 @@
 
 // ignore-tidy-linelength
 
-// @has intra_link_prim_methods/index.html
+// @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'
 
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-link-primitive-non-default-impl.rs b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs
index 160b18a967b..548eb090a32 100644
--- a/src/test/rustdoc/intra-link-primitive-non-default-impl.rs
+++ b/src/test/rustdoc/intra-doc/primitive-non-default-impl.rs
@@ -2,7 +2,7 @@
 
 // ignore-tidy-linelength
 
-// @has intra_link_primitive_non_default_impl/fn.str_methods.html
+// @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`]
@@ -13,7 +13,7 @@
 // @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html#method.replace"]' 'str::replace'
 pub fn str_methods() {}
 
-// @has intra_link_primitive_non_default_impl/fn.f32_methods.html
+// @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]
@@ -22,7 +22,7 @@ pub fn str_methods() {}
 // @has - '//*[@href="https://doc.rust-lang.org/nightly/std/primitive.f32.html#method.mul_add"]' 'f32::mul_add'
 pub fn f32_methods() {}
 
-// @has intra_link_primitive_non_default_impl/fn.f64_methods.html
+// @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`]
diff --git a/src/test/rustdoc/intra-link-private.rs b/src/test/rustdoc/intra-doc/private-failures-ignored.rs
index cf8bc0b1586..cf8bc0b1586 100644
--- a/src/test/rustdoc/intra-link-private.rs
+++ b/src/test/rustdoc/intra-doc/private-failures-ignored.rs
diff --git a/src/test/rustdoc/intra-doc-link-private.rs b/src/test/rustdoc/intra-doc/private.rs
index f86ca44403d..f86ca44403d 100644
--- a/src/test/rustdoc/intra-doc-link-private.rs
+++ b/src/test/rustdoc/intra-doc/private.rs
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-link-pub-use.rs b/src/test/rustdoc/intra-doc/pub-use.rs
index dd52249abc6..dd52249abc6 100644
--- a/src/test/rustdoc/intra-link-pub-use.rs
+++ b/src/test/rustdoc/intra-doc/pub-use.rs
diff --git a/src/test/rustdoc/intra-link-reexport-additional-docs.rs b/src/test/rustdoc/intra-doc/reexport-additional-docs.rs
index 96f3580f305..96f3580f305 100644
--- a/src/test/rustdoc/intra-link-reexport-additional-docs.rs
+++ b/src/test/rustdoc/intra-doc/reexport-additional-docs.rs
diff --git a/src/test/rustdoc/intra-link-self.rs b/src/test/rustdoc/intra-doc/self.rs
index 81545fec741..81545fec741 100644
--- a/src/test/rustdoc/intra-link-self.rs
+++ b/src/test/rustdoc/intra-doc/self.rs
diff --git a/src/test/rustdoc/through-proc-macro.rs b/src/test/rustdoc/intra-doc/through-proc-macro.rs
index 613410871f0..613410871f0 100644
--- a/src/test/rustdoc/through-proc-macro.rs
+++ b/src/test/rustdoc/intra-doc/through-proc-macro.rs
diff --git a/src/test/rustdoc/intra-link-trait-impl.rs b/src/test/rustdoc/intra-doc/trait-impl.rs
index fab8406d525..fab8406d525 100644
--- a/src/test/rustdoc/intra-link-trait-impl.rs
+++ b/src/test/rustdoc/intra-doc/trait-impl.rs
diff --git a/src/test/rustdoc/intra-link-trait-item.rs b/src/test/rustdoc/intra-doc/trait-item.rs
index 54270414c9d..de8585f4c9a 100644
--- a/src/test/rustdoc/intra-link-trait-item.rs
+++ b/src/test/rustdoc/intra-doc/trait-item.rs
@@ -3,7 +3,7 @@
 
 /// Link to [S::assoc_fn()]
 /// Link to [Default::default()]
-// @has intra_link_trait_item/struct.S.html '//*[@href="../intra_link_trait_item/struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
+// @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;
 
diff --git a/src/test/rustdoc/intra-doc-link-true-false.rs b/src/test/rustdoc/intra-doc/true-false.rs
index 7b21e934147..7b21e934147 100644
--- a/src/test/rustdoc/intra-doc-link-true-false.rs
+++ b/src/test/rustdoc/intra-doc/true-false.rs
diff --git a/src/test/rustdoc/intra-link-associated-defaults.rs b/src/test/rustdoc/intra-link-associated-defaults.rs
deleted file mode 100644
index 2051129b948..00000000000
--- a/src/test/rustdoc/intra-link-associated-defaults.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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 'intra_link_associated_defaults/struct.UsesDefaults.html' '//a[@href="../intra_link_associated_defaults/struct.UsesDefaults.html#associatedtype.T"]' 'UsesDefaults::T'
-// @has 'intra_link_associated_defaults/struct.UsesDefaults.html' '//a[@href="../intra_link_associated_defaults/struct.UsesDefaults.html#method.f"]' 'UsesDefaults::f'
-pub struct UsesDefaults;
-impl TraitWithDefault for UsesDefaults {}
-
-/// Link to [OverridesDefaults::T] and [OverridesDefaults::f]
-// @has 'intra_link_associated_defaults/struct.OverridesDefaults.html' '//a[@href="../intra_link_associated_defaults/struct.OverridesDefaults.html#associatedtype.T"]' 'OverridesDefaults::T'
-// @has 'intra_link_associated_defaults/struct.OverridesDefaults.html' '//a[@href="../intra_link_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-link-associated-items.rs b/src/test/rustdoc/intra-link-associated-items.rs
deleted file mode 100644
index daf7075a917..00000000000
--- a/src/test/rustdoc/intra-link-associated-items.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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 'intra_link_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 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from'
-// @has 'intra_link_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 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html"]' 'MyStruct'
-// @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html#method.method"]' 'link from struct'
-// @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_associated_items/struct.MyStruct.html#method.clone"]' 'MyStruct::clone'
-// @has 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_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 'intra_link_associated_items/struct.MyStruct.html' '//a[@href="../intra_link_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-link-disambiguators-removed.rs b/src/test/rustdoc/intra-link-disambiguators-removed.rs
deleted file mode 100644
index 26d05b484b9..00000000000
--- a/src/test/rustdoc/intra-link-disambiguators-removed.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// ignore-tidy-linelength
-#![deny(intra_doc_link_resolution_failure)]
-// first try backticks
-/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`]
-// @has intra_link_disambiguators_removed/struct.AtDisambiguator.html
-// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"][code]' "Name"
-// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name"
-// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"][code]' "Name"
-pub struct AtDisambiguator;
-
-/// fn: [`Name()`], macro: [`Name!`]
-// @has intra_link_disambiguators_removed/struct.SymbolDisambiguator.html
-// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name()"
-// @has - '//a[@href="../intra_link_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 intra_link_disambiguators_removed/trait.Name.html
-// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"]' "Name"
-// @!has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name"
-
-// FIXME: this will turn !() into ! alone
-/// [Name!()]
-// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name!"
-pub trait Name {}
-
-#[allow(non_snake_case)]
-
-// Try collapsed reference links
-/// [macro@Name][]
-// @has intra_link_disambiguators_removed/fn.Name.html
-// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name"
-
-// Try links that have the same text as a generated URL
-/// Weird URL aligned [../intra_link_disambiguators_removed/macro.Name.html][trait@Name]
-// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"]' "../intra_link_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 intra_link_disambiguators_removed/macro.Name.html
-// @has - '//a[@href="../intra_link_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="../intra_link_disambiguators_removed/trait.Name.html"]' "trait@Name"
-macro_rules! Name {
-    () => ()
-}
diff --git a/src/test/rustdoc/intra-link-extern-type.rs b/src/test/rustdoc/intra-link-extern-type.rs
deleted file mode 100644
index 418e0d91ea7..00000000000
--- a/src/test/rustdoc/intra-link-extern-type.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-#![feature(extern_types)]
-
-extern {
-    pub type ExternType;
-}
-
-impl ExternType {
-    pub fn f(&self) {
-
-    }
-}
-
-// @has 'intra_link_extern_type/foreigntype.ExternType.html'
-// @has 'intra_link_extern_type/fn.links_to_extern_type.html' \
-// 'href="../intra_link_extern_type/foreigntype.ExternType.html#method.f"'
-/// See also [ExternType::f]
-pub fn links_to_extern_type() {
-}
diff --git a/src/test/rustdoc/intra-link-prim-assoc.rs b/src/test/rustdoc/intra-link-prim-assoc.rs
deleted file mode 100644
index c0066885e19..00000000000
--- a/src/test/rustdoc/intra-link-prim-assoc.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// ignore-tidy-linelength
-#![deny(broken_intra_doc_links)]
-
-//! [i32::MAX]
-// @has intra_link_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-link-prim-precedence.rs b/src/test/rustdoc/intra-link-prim-precedence.rs
deleted file mode 100644
index 0a4e57ef643..00000000000
--- a/src/test/rustdoc/intra-link-prim-precedence.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// ignore-tidy-linelength
-#![deny(broken_intra_doc_links)]
-
-pub mod char {
-    /// [char]
-    // @has intra_link_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 intra_link_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 intra_link_prim_precedence/struct.MyString2.html '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'crate::char'
-// @has - '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'mod@char'
-pub struct MyString2;
diff --git a/src/test/rustdoc/intra-link-proc-macro.rs b/src/test/rustdoc/intra-link-proc-macro.rs
deleted file mode 100644
index 7a8403255ed..00000000000
--- a/src/test/rustdoc/intra-link-proc-macro.rs
+++ /dev/null
@@ -1,27 +0,0 @@
-// aux-build:intra-link-proc-macro-macro.rs
-// build-aux-docs
-#![deny(broken_intra_doc_links)]
-
-extern crate intra_link_proc_macro_macro;
-
-
-pub use intra_link_proc_macro_macro::{DeriveA, attr_a};
-use intra_link_proc_macro_macro::{DeriveB, attr_b};
-
-// @has intra_link_proc_macro/struct.Foo.html
-// @has - '//a/@href' '../intra_link_proc_macro/derive.DeriveA.html'
-// @has - '//a/@href' '../intra_link_proc_macro/attr.attr_a.html'
-// @has - '//a/@href' '../intra_link_proc_macro/trait.DeriveTrait.html'
-// @has - '//a/@href' '../intra_link_proc_macro_macro/derive.DeriveB.html'
-// @has - '//a/@href' '../intra_link_proc_macro_macro/attr.attr_b.html'
-/// Link to [DeriveA], [attr_a], [DeriveB], [attr_b], [DeriveTrait]
-pub struct Foo;
-
-// @has intra_link_proc_macro/struct.Bar.html
-// @has - '//a/@href' '../intra_link_proc_macro/derive.DeriveA.html'
-// @has - '//a/@href' '../intra_link_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/normalize-assoc-item.rs b/src/test/rustdoc/normalize-assoc-item.rs
index 70b3c66fd2b..ad1a868ee32 100644
--- a/src/test/rustdoc/normalize-assoc-item.rs
+++ b/src/test/rustdoc/normalize-assoc-item.rs
@@ -1,7 +1,7 @@
 // ignore-tidy-linelength
 // aux-build:normalize-assoc-item.rs
 // build-aux-docs
-// ignore-test
+// compile-flags:-Znormalize-docs
 
 pub trait Trait {
     type X;
diff --git a/src/test/ui/assert-eq-trailing-comma.rs b/src/test/ui/assert-eq-trailing-comma.rs
deleted file mode 100644
index 7071f80d7f7..00000000000
--- a/src/test/ui/assert-eq-trailing-comma.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// run-pass
-
-fn main() {
-    assert_eq!(1, 1,);
-}
diff --git a/src/test/ui/assert-escape.rs b/src/test/ui/assert-escape.rs
deleted file mode 100644
index 00e51d42cab..00000000000
--- a/src/test/ui/assert-escape.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// run-pass
-
-fn main() {
-    assert!(r#"☃\backslash"#.contains("\\"));
-}
diff --git a/src/test/ui/assert-ne-trailing-comma.rs b/src/test/ui/assert-ne-trailing-comma.rs
deleted file mode 100644
index 03308db9a1f..00000000000
--- a/src/test/ui/assert-ne-trailing-comma.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-// run-pass
-
-fn main() {
-    assert_ne!(1, 2,);
-}
diff --git a/src/test/ui/atomic-access-bool.rs b/src/test/ui/atomic-access-bool.rs
deleted file mode 100644
index e9d48bb3b43..00000000000
--- a/src/test/ui/atomic-access-bool.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-// run-pass
-
-#![allow(stable_features)]
-#![feature(atomic_access)]
-use std::sync::atomic::AtomicBool;
-use std::sync::atomic::Ordering::*;
-
-static mut ATOMIC: AtomicBool = AtomicBool::new(false);
-
-fn main() {
-    unsafe {
-        assert_eq!(*ATOMIC.get_mut(), false);
-        ATOMIC.store(true, SeqCst);
-        assert_eq!(*ATOMIC.get_mut(), true);
-        ATOMIC.fetch_or(false, SeqCst);
-        assert_eq!(*ATOMIC.get_mut(), true);
-        ATOMIC.fetch_and(false, SeqCst);
-        assert_eq!(*ATOMIC.get_mut(), false);
-        ATOMIC.fetch_nand(true, SeqCst);
-        assert_eq!(*ATOMIC.get_mut(), true);
-        ATOMIC.fetch_xor(true, SeqCst);
-        assert_eq!(*ATOMIC.get_mut(), false);
-    }
-}
diff --git a/src/test/ui/atomic-alignment.rs b/src/test/ui/atomic-alignment.rs
deleted file mode 100644
index 5bda90d2eab..00000000000
--- a/src/test/ui/atomic-alignment.rs
+++ /dev/null
@@ -1,38 +0,0 @@
-// run-pass
-
-#![feature(cfg_target_has_atomic)]
-#![feature(integer_atomics)]
-
-use std::mem::{align_of, size_of};
-use std::sync::atomic::*;
-
-fn main() {
-    #[cfg(target_has_atomic = "8")]
-    assert_eq!(align_of::<AtomicBool>(), size_of::<AtomicBool>());
-    #[cfg(target_has_atomic = "ptr")]
-    assert_eq!(align_of::<AtomicPtr<u8>>(), size_of::<AtomicPtr<u8>>());
-    #[cfg(target_has_atomic = "8")]
-    assert_eq!(align_of::<AtomicU8>(), size_of::<AtomicU8>());
-    #[cfg(target_has_atomic = "8")]
-    assert_eq!(align_of::<AtomicI8>(), size_of::<AtomicI8>());
-    #[cfg(target_has_atomic = "16")]
-    assert_eq!(align_of::<AtomicU16>(), size_of::<AtomicU16>());
-    #[cfg(target_has_atomic = "16")]
-    assert_eq!(align_of::<AtomicI16>(), size_of::<AtomicI16>());
-    #[cfg(target_has_atomic = "32")]
-    assert_eq!(align_of::<AtomicU32>(), size_of::<AtomicU32>());
-    #[cfg(target_has_atomic = "32")]
-    assert_eq!(align_of::<AtomicI32>(), size_of::<AtomicI32>());
-    #[cfg(target_has_atomic = "64")]
-    assert_eq!(align_of::<AtomicU64>(), size_of::<AtomicU64>());
-    #[cfg(target_has_atomic = "64")]
-    assert_eq!(align_of::<AtomicI64>(), size_of::<AtomicI64>());
-    #[cfg(target_has_atomic = "128")]
-    assert_eq!(align_of::<AtomicU128>(), size_of::<AtomicU128>());
-    #[cfg(target_has_atomic = "128")]
-    assert_eq!(align_of::<AtomicI128>(), size_of::<AtomicI128>());
-    #[cfg(target_has_atomic = "ptr")]
-    assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
-    #[cfg(target_has_atomic = "ptr")]
-    assert_eq!(align_of::<AtomicIsize>(), size_of::<AtomicIsize>());
-}
diff --git a/src/test/ui/atomic-compare_exchange.rs b/src/test/ui/atomic-compare_exchange.rs
deleted file mode 100644
index 9b327eef3c8..00000000000
--- a/src/test/ui/atomic-compare_exchange.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// run-pass
-
-#![allow(stable_features)]
-
-#![feature(extended_compare_and_swap)]
-use std::sync::atomic::AtomicIsize;
-use std::sync::atomic::Ordering::*;
-
-static ATOMIC: AtomicIsize = AtomicIsize::new(0);
-
-fn main() {
-    // Make sure codegen can emit all the intrinsics correctly
-    ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok();
-    ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok();
-    ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok();
-    ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok();
-    ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok();
-    ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok();
-    ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok();
-    ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok();
-    ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok();
-    ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok();
-    ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok();
-    ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok();
-    ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok();
-    ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok();
-    ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok();
-    ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok();
-    ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok();
-    ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok();
-}
diff --git a/src/test/ui/bool-not.rs b/src/test/ui/bool-not.rs
deleted file mode 100644
index 84713d6818a..00000000000
--- a/src/test/ui/bool-not.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-// run-pass
-
-pub fn main() {
-    if !false { assert!((true)); } else { assert!((false)); }
-    if !true { assert!((false)); } else { assert!((true)); }
-}
diff --git a/src/test/ui/bool.rs b/src/test/ui/bool.rs
deleted file mode 100644
index 92f36c8fd25..00000000000
--- a/src/test/ui/bool.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-// run-pass
-// Basic boolean tests
-
-
-use std::cmp::Ordering::{Equal, Greater, Less};
-use std::ops::{BitAnd, BitOr, BitXor};
-
-fn main() {
-    assert_eq!(false.eq(&true), false);
-    assert_eq!(false == false, true);
-    assert_eq!(false != true, true);
-    assert_eq!(false.ne(&false), false);
-
-    assert_eq!(false.bitand(false), false);
-    assert_eq!(true.bitand(false), false);
-    assert_eq!(false.bitand(true), false);
-    assert_eq!(true.bitand(true), true);
-
-    assert_eq!(false & false, false);
-    assert_eq!(true & false, false);
-    assert_eq!(false & true, false);
-    assert_eq!(true & true, true);
-
-    assert_eq!(false.bitor(false), false);
-    assert_eq!(true.bitor(false), true);
-    assert_eq!(false.bitor(true), true);
-    assert_eq!(true.bitor(true), true);
-
-    assert_eq!(false | false, false);
-    assert_eq!(true | false, true);
-    assert_eq!(false | true, true);
-    assert_eq!(true | true, true);
-
-    assert_eq!(false.bitxor(false), false);
-    assert_eq!(true.bitxor(false), true);
-    assert_eq!(false.bitxor(true), true);
-    assert_eq!(true.bitxor(true), false);
-
-    assert_eq!(false ^ false, false);
-    assert_eq!(true ^ false, true);
-    assert_eq!(false ^ true, true);
-    assert_eq!(true ^ true, false);
-
-    assert_eq!(!true, false);
-    assert_eq!(!false, true);
-
-    let s = false.to_string();
-    assert_eq!(s, "false");
-    let s = true.to_string();
-    assert_eq!(s, "true");
-
-    assert!(true > false);
-    assert!(!(false > true));
-
-    assert!(false < true);
-    assert!(!(true < false));
-
-    assert!(false <= false);
-    assert!(false >= false);
-    assert!(true <= true);
-    assert!(true >= true);
-
-    assert!(false <= true);
-    assert!(!(false >= true));
-    assert!(true >= false);
-    assert!(!(true <= false));
-
-    assert_eq!(true.cmp(&true), Equal);
-    assert_eq!(false.cmp(&false), Equal);
-    assert_eq!(true.cmp(&false), Greater);
-    assert_eq!(false.cmp(&true), Less);
-}
diff --git a/src/test/ui/char_unicode.rs b/src/test/ui/char_unicode.rs
deleted file mode 100644
index 65dda47066f..00000000000
--- a/src/test/ui/char_unicode.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// run-pass
-
-/// Tests access to the Unicode version constant.
-pub fn main() {
-    check(std::char::UNICODE_VERSION);
-}
-
-pub fn check(unicode_version: (u8, u8, u8)) {
-    assert!(unicode_version.0 >= 10);
-}
diff --git a/src/test/ui/cmp-default.rs b/src/test/ui/cmp-default.rs
deleted file mode 100644
index bb5c39f5cde..00000000000
--- a/src/test/ui/cmp-default.rs
+++ /dev/null
@@ -1,73 +0,0 @@
-// run-pass
-
-use std::cmp::Ordering;
-
-// Test default methods in PartialOrd and PartialEq
-//
-#[derive(Debug)]
-struct Fool(bool);
-
-impl PartialEq for Fool {
-    fn eq(&self, other: &Fool) -> bool {
-        let Fool(this) = *self;
-        let Fool(other) = *other;
-        this != other
-    }
-}
-
-struct Int(isize);
-
-impl PartialEq for Int {
-    fn eq(&self, other: &Int) -> bool {
-        let Int(this) = *self;
-        let Int(other) = *other;
-        this == other
-    }
-}
-
-impl PartialOrd for Int {
-    fn partial_cmp(&self, other: &Int) -> Option<Ordering> {
-        let Int(this) = *self;
-        let Int(other) = *other;
-        this.partial_cmp(&other)
-    }
-}
-
-struct RevInt(isize);
-
-impl PartialEq for RevInt {
-    fn eq(&self, other: &RevInt) -> bool {
-        let RevInt(this) = *self;
-        let RevInt(other) = *other;
-        this == other
-    }
-}
-
-impl PartialOrd for RevInt {
-    fn partial_cmp(&self, other: &RevInt) -> Option<Ordering> {
-        let RevInt(this) = *self;
-        let RevInt(other) = *other;
-        other.partial_cmp(&this)
-    }
-}
-
-pub fn main() {
-    assert!(Int(2) >  Int(1));
-    assert!(Int(2) >= Int(1));
-    assert!(Int(1) >= Int(1));
-    assert!(Int(1) <  Int(2));
-    assert!(Int(1) <= Int(2));
-    assert!(Int(1) <= Int(1));
-
-    assert!(RevInt(2) <  RevInt(1));
-    assert!(RevInt(2) <= RevInt(1));
-    assert!(RevInt(1) <= RevInt(1));
-    assert!(RevInt(1) >  RevInt(2));
-    assert!(RevInt(1) >= RevInt(2));
-    assert!(RevInt(1) >= RevInt(1));
-
-    assert_eq!(Fool(true), Fool(false));
-    assert!(Fool(true)  != Fool(true));
-    assert!(Fool(false) != Fool(false));
-    assert_eq!(Fool(false), Fool(true));
-}
diff --git a/src/test/ui/consts/ascii_ctype.rs b/src/test/ui/consts/ascii_ctype.rs
deleted file mode 100644
index ef2f7322f27..00000000000
--- a/src/test/ui/consts/ascii_ctype.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-// run-pass
-
-macro_rules! suite {
-    ( $( $fn:ident => [$a:ident, $A:ident, $nine:ident, $dot:ident, $space:ident]; )* ) => {
-        $(
-            mod $fn {
-                const CHAR_A_LOWER: bool = 'a'.$fn();
-                const CHAR_A_UPPER: bool = 'A'.$fn();
-                const CHAR_NINE: bool = '9'.$fn();
-                const CHAR_DOT: bool = '.'.$fn();
-                const CHAR_SPACE: bool = ' '.$fn();
-
-                const U8_A_LOWER: bool = b'a'.$fn();
-                const U8_A_UPPER: bool = b'A'.$fn();
-                const U8_NINE: bool = b'9'.$fn();
-                const U8_DOT: bool = b'.'.$fn();
-                const U8_SPACE: bool = b' '.$fn();
-
-                pub fn run() {
-                    assert_eq!(CHAR_A_LOWER, $a);
-                    assert_eq!(CHAR_A_UPPER, $A);
-                    assert_eq!(CHAR_NINE, $nine);
-                    assert_eq!(CHAR_DOT, $dot);
-                    assert_eq!(CHAR_SPACE, $space);
-
-                    assert_eq!(U8_A_LOWER, $a);
-                    assert_eq!(U8_A_UPPER, $A);
-                    assert_eq!(U8_NINE, $nine);
-                    assert_eq!(U8_DOT, $dot);
-                    assert_eq!(U8_SPACE, $space);
-                }
-            }
-        )*
-
-        fn main() {
-            $( $fn::run(); )*
-        }
-    }
-}
-
-suite! {
-    //                        'a'    'A'    '9'    '.'    ' '
-    is_ascii_alphabetic   => [true,  true,  false, false, false];
-    is_ascii_uppercase    => [false, true,  false, false, false];
-    is_ascii_lowercase    => [true,  false, false, false, false];
-    is_ascii_alphanumeric => [true,  true,  true,  false, false];
-    is_ascii_digit        => [false, false, true,  false, false];
-    is_ascii_hexdigit     => [true,  true,  true,  false, false];
-    is_ascii_punctuation  => [false, false, false, true,  false];
-    is_ascii_graphic      => [true,  true,  true,  true,  false];
-    is_ascii_whitespace   => [false, false, false, false, true];
-    is_ascii_control      => [false, false, false, false, false];
-}
diff --git a/src/test/ui/consts/const-fn-feature-flags.rs b/src/test/ui/consts/const-fn-feature-flags.rs
deleted file mode 100644
index 30e7e102b86..00000000000
--- a/src/test/ui/consts/const-fn-feature-flags.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// run-pass
-// Test use of stabilized const fns in std formerly using individual feature gates.
-
-use std::cell::Cell;
-
-const CELL: Cell<i32> = Cell::new(42);
-
-fn main() {
-    let v = CELL.get();
-    CELL.set(v+1);
-
-    assert_eq!(CELL.get(), v);
-}
diff --git a/src/test/ui/consts/const-str-ptr.rs b/src/test/ui/consts/const-str-ptr.rs
deleted file mode 100644
index 56fd9d9f55f..00000000000
--- a/src/test/ui/consts/const-str-ptr.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-// run-pass
-#![allow(unused_imports)]
-use std::{str, string};
-
-const A: [u8; 2] = ['h' as u8, 'i' as u8];
-const B: &'static [u8; 2] = &A;
-const C: *const u8 = B as *const u8;
-
-pub fn main() {
-    unsafe {
-        let foo = &A as *const u8;
-        assert_eq!(foo, C);
-        assert_eq!(str::from_utf8_unchecked(&A), "hi");
-        assert_eq!(*C, A[0]);
-        assert_eq!(*(&B[0] as *const u8), A[0]);
-    }
-}
diff --git a/src/test/ui/consts/std/net/ip.rs b/src/test/ui/consts/std/net/ip.rs
deleted file mode 100644
index 6730946577d..00000000000
--- a/src/test/ui/consts/std/net/ip.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// run-pass
-
-use std::net::{IpAddr, Ipv4Addr};
-
-fn main() {
-    const IP_ADDRESS : IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST);
-
-    const IS_IP_V4 : bool = IP_ADDRESS.is_ipv4();
-    assert!(IS_IP_V4);
-
-    const IS_IP_V6 : bool = IP_ADDRESS.is_ipv6();
-    assert!(!IS_IP_V6);
-}
diff --git a/src/test/ui/deref-mut-on-ref.rs b/src/test/ui/deref-mut-on-ref.rs
deleted file mode 100644
index a6df5495a27..00000000000
--- a/src/test/ui/deref-mut-on-ref.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-// run-pass
-// Test that `&mut T` implements `DerefMut<T>`
-
-
-use std::ops::{Deref, DerefMut};
-
-fn inc<T: Deref<Target=isize> + DerefMut>(mut t: T) {
-    *t += 1;
-}
-
-fn main() {
-    let mut x: isize = 5;
-    inc(&mut x);
-    assert_eq!(x, 6);
-}
diff --git a/src/test/ui/deref-on-ref.rs b/src/test/ui/deref-on-ref.rs
deleted file mode 100644
index 973e61c9d59..00000000000
--- a/src/test/ui/deref-on-ref.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// run-pass
-// Test that `&T` and `&mut T` implement `Deref<T>`
-
-
-use std::ops::Deref;
-
-fn deref<U:Copy,T:Deref<Target=U>>(t: T) -> U {
-    *t
-}
-
-fn main() {
-    let x: isize = 3;
-    let y = deref(&x);
-    assert_eq!(y, 3);
-
-    let mut x: isize = 4;
-    let y = deref(&mut x);
-    assert_eq!(y, 4);
-}
diff --git a/src/test/ui/env-home-dir.rs b/src/test/ui/env-home-dir.rs
deleted file mode 100644
index c597b4732d1..00000000000
--- a/src/test/ui/env-home-dir.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// run-pass
-
-#![allow(unused_variables)]
-#![allow(deprecated)]
-// ignore-emscripten env vars don't work?
-// ignore-sgx env vars cannot be modified
-
-use std::env::*;
-use std::path::PathBuf;
-
-#[cfg(unix)]
-fn main() {
-    let oldhome = var("HOME");
-
-    set_var("HOME", "/home/MountainView");
-    assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
-
-    remove_var("HOME");
-    if cfg!(target_os = "android") {
-        assert!(home_dir().is_none());
-    } else {
-        // When HOME is not set, some platforms return `None`,
-        // but others return `Some` with a default.
-        // Just check that it is not "/home/MountainView".
-        assert_ne!(home_dir(), Some(PathBuf::from("/home/MountainView")));
-    }
-}
-
-#[cfg(windows)]
-fn main() {
-    let oldhome = var("HOME");
-    let olduserprofile = var("USERPROFILE");
-
-    remove_var("HOME");
-    remove_var("USERPROFILE");
-
-    assert!(home_dir().is_some());
-
-    set_var("HOME", "/home/MountainView");
-    assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
-
-    remove_var("HOME");
-
-    set_var("USERPROFILE", "/home/MountainView");
-    assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
-
-    set_var("HOME", "/home/MountainView");
-    set_var("USERPROFILE", "/home/PaloAlto");
-    assert_eq!(home_dir(), Some(PathBuf::from("/home/MountainView")));
-}
diff --git a/src/test/ui/extend-for-unit.rs b/src/test/ui/extend-for-unit.rs
deleted file mode 100644
index 01d743f70bc..00000000000
--- a/src/test/ui/extend-for-unit.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-// run-pass
-
-pub fn main() {
-    let mut x = 0;
-    {
-        let iter = (0..5).map(|_| {
-            x += 1;
-        });
-        ().extend(iter);
-    }
-    assert_eq!(x, 5);
-}
diff --git a/src/test/ui/offset_from.rs b/src/test/ui/offset_from.rs
deleted file mode 100644
index aa59c119706..00000000000
--- a/src/test/ui/offset_from.rs
+++ /dev/null
@@ -1,13 +0,0 @@
-// run-pass
-
-fn main() {
-    let mut a = [0; 5];
-    let ptr1: *mut i32 = &mut a[1];
-    let ptr2: *mut i32 = &mut a[3];
-    unsafe {
-        assert_eq!(ptr2.offset_from(ptr1), 2);
-        assert_eq!(ptr1.offset_from(ptr2), -2);
-        assert_eq!(ptr1.offset(2), ptr2);
-        assert_eq!(ptr2.offset(-2), ptr1);
-    }
-}
diff --git a/src/test/ui/option-ext.rs b/src/test/ui/option-ext.rs
deleted file mode 100644
index 76d0cf43984..00000000000
--- a/src/test/ui/option-ext.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// run-pass
-
-pub fn main() {
-    let thing = "{{ f }}";
-    let f = thing.find("{{");
-
-    if f.is_none() {
-        println!("None!");
-    }
-}
diff --git a/src/test/ui/result-opt-conversions.rs b/src/test/ui/result-opt-conversions.rs
deleted file mode 100644
index 57f258aab65..00000000000
--- a/src/test/ui/result-opt-conversions.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-// run-pass
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-struct BadNumErr;
-
-fn try_num(x: i32) -> Result<i32, BadNumErr> {
-    if x <= 5 {
-        Ok(x + 1)
-    } else {
-        Err(BadNumErr)
-    }
-}
-
-type ResOpt = Result<Option<i32>, BadNumErr>;
-type OptRes = Option<Result<i32, BadNumErr>>;
-
-fn main() {
-    let mut x: ResOpt = Ok(Some(5));
-    let mut y: OptRes = Some(Ok(5));
-    assert_eq!(x, y.transpose());
-    assert_eq!(x.transpose(), y);
-
-    x = Ok(None);
-    y = None;
-    assert_eq!(x, y.transpose());
-    assert_eq!(x.transpose(), y);
-
-    x = Err(BadNumErr);
-    y = Some(Err(BadNumErr));
-    assert_eq!(x, y.transpose());
-    assert_eq!(x.transpose(), y);
-
-    let res: Result<Vec<i32>, BadNumErr> =
-        (0..10)
-            .map(|x| {
-                let y = try_num(x)?;
-                Ok(if y % 2 == 0 {
-                    Some(y - 1)
-                } else {
-                    None
-                })
-            })
-            .filter_map(Result::transpose)
-            .collect();
-
-    assert_eq!(res, Err(BadNumErr))
-}
diff --git a/src/test/ui/utf8.rs b/src/test/ui/utf8.rs
deleted file mode 100644
index 75b6ddf7895..00000000000
--- a/src/test/ui/utf8.rs
+++ /dev/null
@@ -1,50 +0,0 @@
-// run-pass
-
-pub fn main() {
-    let yen: char = '¥'; // 0xa5
-    let c_cedilla: char = 'ç'; // 0xe7
-    let thorn: char = 'þ'; // 0xfe
-    let y_diaeresis: char = 'ÿ'; // 0xff
-    let pi: char = 'Π'; // 0x3a0
-
-    assert_eq!(yen as isize, 0xa5);
-    assert_eq!(c_cedilla as isize, 0xe7);
-    assert_eq!(thorn as isize, 0xfe);
-    assert_eq!(y_diaeresis as isize, 0xff);
-    assert_eq!(pi as isize, 0x3a0);
-
-    assert_eq!(pi as isize, '\u{3a0}' as isize);
-    assert_eq!('\x0a' as isize, '\n' as isize);
-
-    let bhutan: String = "འབྲུག་ཡུལ།".to_string();
-    let japan: String = "日本".to_string();
-    let uzbekistan: String = "Ўзбекистон".to_string();
-    let austria: String = "Österreich".to_string();
-
-    let bhutan_e: String =
-        "\u{f60}\u{f56}\u{fb2}\u{f74}\u{f42}\u{f0b}\u{f61}\u{f74}\u{f63}\u{f0d}".to_string();
-    let japan_e: String = "\u{65e5}\u{672c}".to_string();
-    let uzbekistan_e: String =
-        "\u{40e}\u{437}\u{431}\u{435}\u{43a}\u{438}\u{441}\u{442}\u{43e}\u{43d}".to_string();
-    let austria_e: String = "\u{d6}sterreich".to_string();
-
-    let oo: char = 'Ö';
-    assert_eq!(oo as isize, 0xd6);
-
-    fn check_str_eq(a: String, b: String) {
-        let mut i: isize = 0;
-        for ab in a.bytes() {
-            println!("{}", i);
-            println!("{}", ab);
-            let bb: u8 = b.as_bytes()[i as usize];
-            println!("{}", bb);
-            assert_eq!(ab, bb);
-            i += 1;
-        }
-    }
-
-    check_str_eq(bhutan, bhutan_e);
-    check_str_eq(japan, japan_e);
-    check_str_eq(uzbekistan, uzbekistan_e);
-    check_str_eq(austria, austria_e);
-}
diff --git a/src/test/ui/utf8_chars.rs b/src/test/ui/utf8_chars.rs
deleted file mode 100644
index d764509813d..00000000000
--- a/src/test/ui/utf8_chars.rs
+++ /dev/null
@@ -1,31 +0,0 @@
-// run-pass
-
-use std::str;
-
-pub fn main() {
-    // Chars of 1, 2, 3, and 4 bytes
-    let chs: Vec<char> = vec!['e', 'é', '€', '\u{10000}'];
-    let s: String = chs.iter().cloned().collect();
-    let schs: Vec<char> = s.chars().collect();
-
-    assert_eq!(s.len(), 10);
-    assert_eq!(s.chars().count(), 4);
-    assert_eq!(schs.len(), 4);
-    assert_eq!(schs.iter().cloned().collect::<String>(), s);
-
-    assert!((str::from_utf8(s.as_bytes()).is_ok()));
-    // invalid prefix
-    assert!((!str::from_utf8(&[0x80]).is_ok()));
-    // invalid 2 byte prefix
-    assert!((!str::from_utf8(&[0xc0]).is_ok()));
-    assert!((!str::from_utf8(&[0xc0, 0x10]).is_ok()));
-    // invalid 3 byte prefix
-    assert!((!str::from_utf8(&[0xe0]).is_ok()));
-    assert!((!str::from_utf8(&[0xe0, 0x10]).is_ok()));
-    assert!((!str::from_utf8(&[0xe0, 0xff, 0x10]).is_ok()));
-    // invalid 4 byte prefix
-    assert!((!str::from_utf8(&[0xf0]).is_ok()));
-    assert!((!str::from_utf8(&[0xf0, 0x10]).is_ok()));
-    assert!((!str::from_utf8(&[0xf0, 0xff, 0x10]).is_ok()));
-    assert!((!str::from_utf8(&[0xf0, 0xff, 0xff, 0x10]).is_ok()));
-}
diff --git a/src/test/ui/wrapping-int-api.rs b/src/test/ui/wrapping-int-api.rs
deleted file mode 100644
index 6e2fc7f80b9..00000000000
--- a/src/test/ui/wrapping-int-api.rs
+++ /dev/null
@@ -1,225 +0,0 @@
-// run-pass
-// Test inherent wrapping_* methods for {i,u}{size,8,16,32,64}.
-
-// Don't warn about overflowing ops on 32-bit platforms
-#![cfg_attr(target_pointer_width = "32", allow(const_err))]
-
-fn main() {
-    assert_eq!(   i8::MAX.wrapping_add(1),    i8::MIN);
-    assert_eq!(  i16::MAX.wrapping_add(1),   i16::MIN);
-    assert_eq!(  i32::MAX.wrapping_add(1),   i32::MIN);
-    assert_eq!(  i64::MAX.wrapping_add(1),   i64::MIN);
-    assert_eq!(isize::MAX.wrapping_add(1), isize::MIN);
-
-    assert_eq!(   i8::MIN.wrapping_sub(1),    i8::MAX);
-    assert_eq!(  i16::MIN.wrapping_sub(1),   i16::MAX);
-    assert_eq!(  i32::MIN.wrapping_sub(1),   i32::MAX);
-    assert_eq!(  i64::MIN.wrapping_sub(1),   i64::MAX);
-    assert_eq!(isize::MIN.wrapping_sub(1), isize::MAX);
-
-    assert_eq!(   u8::MAX.wrapping_add(1),    u8::MIN);
-    assert_eq!(  u16::MAX.wrapping_add(1),   u16::MIN);
-    assert_eq!(  u32::MAX.wrapping_add(1),   u32::MIN);
-    assert_eq!(  u64::MAX.wrapping_add(1),   u64::MIN);
-    assert_eq!(usize::MAX.wrapping_add(1), usize::MIN);
-
-    assert_eq!(   u8::MIN.wrapping_sub(1),    u8::MAX);
-    assert_eq!(  u16::MIN.wrapping_sub(1),   u16::MAX);
-    assert_eq!(  u32::MIN.wrapping_sub(1),   u32::MAX);
-    assert_eq!(  u64::MIN.wrapping_sub(1),   u64::MAX);
-    assert_eq!(usize::MIN.wrapping_sub(1), usize::MAX);
-
-    assert_eq!((0xfe_u8 as i8).wrapping_mul(16),
-               (0xe0_u8 as i8));
-    assert_eq!((0xfedc_u16 as i16).wrapping_mul(16),
-               (0xedc0_u16 as i16));
-    assert_eq!((0xfedc_ba98_u32 as i32).wrapping_mul(16),
-               (0xedcb_a980_u32 as i32));
-    assert_eq!((0xfedc_ba98_7654_3217_u64 as i64).wrapping_mul(16),
-               (0xedcb_a987_6543_2170_u64 as i64));
-
-    match () {
-        #[cfg(target_pointer_width = "32")]
-        () => {
-            assert_eq!((0xfedc_ba98_u32 as isize).wrapping_mul(16),
-                       (0xedcb_a980_u32 as isize));
-        }
-        #[cfg(target_pointer_width = "64")]
-        () => {
-            assert_eq!((0xfedc_ba98_7654_3217_u64 as isize).wrapping_mul(16),
-                       (0xedcb_a987_6543_2170_u64 as isize));
-        }
-    }
-
-    assert_eq!((0xfe as u8).wrapping_mul(16),
-               (0xe0 as u8));
-    assert_eq!((0xfedc as u16).wrapping_mul(16),
-               (0xedc0 as u16));
-    assert_eq!((0xfedc_ba98 as u32).wrapping_mul(16),
-               (0xedcb_a980 as u32));
-    assert_eq!((0xfedc_ba98_7654_3217 as u64).wrapping_mul(16),
-               (0xedcb_a987_6543_2170 as u64));
-
-    match () {
-        #[cfg(target_pointer_width = "32")]
-        () => {
-            assert_eq!((0xfedc_ba98 as usize).wrapping_mul(16),
-                       (0xedcb_a980 as usize));
-        }
-        #[cfg(target_pointer_width = "64")]
-        () => {
-            assert_eq!((0xfedc_ba98_7654_3217 as usize).wrapping_mul(16),
-                       (0xedcb_a987_6543_2170 as usize));
-        }
-    }
-
-    macro_rules! check_mul_no_wrap {
-        ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_mul($f), ($e) * $f); }
-    }
-    macro_rules! check_mul_wraps {
-        ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_mul($f), $e); }
-    }
-
-    check_mul_no_wrap!(0xfe_u8 as i8, -1);
-    check_mul_no_wrap!(0xfedc_u16 as i16, -1);
-    check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -1);
-    check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1);
-    check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1);
-
-    check_mul_no_wrap!(0xfe_u8 as i8, -2);
-    check_mul_no_wrap!(0xfedc_u16 as i16, -2);
-    check_mul_no_wrap!(0xfedc_ba98_u32 as i32, -2);
-    check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2);
-    check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, -2);
-
-    check_mul_no_wrap!(0xfe_u8 as i8, 2);
-    check_mul_no_wrap!(0xfedc_u16 as i16, 2);
-    check_mul_no_wrap!(0xfedc_ba98_u32 as i32, 2);
-    check_mul_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2);
-    check_mul_no_wrap!(0xfedc_ba98_fedc_ba98_u64 as u64 as isize, 2);
-
-    check_mul_wraps!(0x80_u8 as i8, -1);
-    check_mul_wraps!(0x8000_u16 as i16, -1);
-    check_mul_wraps!(0x8000_0000_u32 as i32, -1);
-    check_mul_wraps!(0x8000_0000_0000_0000_u64 as i64, -1);
-    match () {
-        #[cfg(target_pointer_width = "32")]
-        () => {
-            check_mul_wraps!(0x8000_0000_u32 as isize, -1);
-        }
-        #[cfg(target_pointer_width = "64")]
-        () => {
-            check_mul_wraps!(0x8000_0000_0000_0000_u64 as isize, -1);
-        }
-    }
-
-    macro_rules! check_div_no_wrap {
-        ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_div($f), ($e) / $f); }
-    }
-    macro_rules! check_div_wraps {
-        ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_div($f), $e); }
-    }
-
-    check_div_no_wrap!(0xfe_u8 as i8, -1);
-    check_div_no_wrap!(0xfedc_u16 as i16, -1);
-    check_div_no_wrap!(0xfedc_ba98_u32 as i32, -1);
-    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1);
-    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1);
-
-    check_div_no_wrap!(0xfe_u8 as i8, -2);
-    check_div_no_wrap!(0xfedc_u16 as i16, -2);
-    check_div_no_wrap!(0xfedc_ba98_u32 as i32, -2);
-    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2);
-    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2);
-
-    check_div_no_wrap!(0xfe_u8 as i8, 2);
-    check_div_no_wrap!(0xfedc_u16 as i16, 2);
-    check_div_no_wrap!(0xfedc_ba98_u32 as i32, 2);
-    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2);
-    check_div_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2);
-
-    check_div_wraps!(-128 as i8, -1);
-    check_div_wraps!(0x8000_u16 as i16, -1);
-    check_div_wraps!(0x8000_0000_u32 as i32, -1);
-    check_div_wraps!(0x8000_0000_0000_0000_u64 as i64, -1);
-    match () {
-        #[cfg(target_pointer_width = "32")]
-        () => {
-            check_div_wraps!(0x8000_0000_u32 as isize, -1);
-        }
-        #[cfg(target_pointer_width = "64")]
-        () => {
-            check_div_wraps!(0x8000_0000_0000_0000_u64 as isize, -1);
-        }
-    }
-
-
-    macro_rules! check_rem_no_wrap {
-        ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_rem($f), ($e) % $f); }
-    }
-    macro_rules! check_rem_wraps {
-        ($e:expr, $f:expr) => { assert_eq!(($e).wrapping_rem($f), 0); }
-    }
-
-    check_rem_no_wrap!(0xfe_u8 as i8, -1);
-    check_rem_no_wrap!(0xfedc_u16 as i16, -1);
-    check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -1);
-    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -1);
-    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -1);
-
-    check_rem_no_wrap!(0xfe_u8 as i8, -2);
-    check_rem_no_wrap!(0xfedc_u16 as i16, -2);
-    check_rem_no_wrap!(0xfedc_ba98_u32 as i32, -2);
-    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, -2);
-    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, -2);
-
-    check_rem_no_wrap!(0xfe_u8 as i8, 2);
-    check_rem_no_wrap!(0xfedc_u16 as i16, 2);
-    check_rem_no_wrap!(0xfedc_ba98_u32 as i32, 2);
-    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64, 2);
-    check_rem_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize, 2);
-
-    check_rem_wraps!(0x80_u8 as i8, -1);
-    check_rem_wraps!(0x8000_u16 as i16, -1);
-    check_rem_wraps!(0x8000_0000_u32 as i32, -1);
-    check_rem_wraps!(0x8000_0000_0000_0000_u64 as i64, -1);
-    match () {
-        #[cfg(target_pointer_width = "32")]
-        () => {
-            check_rem_wraps!(0x8000_0000_u32 as isize, -1);
-        }
-        #[cfg(target_pointer_width = "64")]
-        () => {
-            check_rem_wraps!(0x8000_0000_0000_0000_u64 as isize, -1);
-        }
-    }
-
-    macro_rules! check_neg_no_wrap {
-        ($e:expr) => { assert_eq!(($e).wrapping_neg(), -($e)); }
-    }
-    macro_rules! check_neg_wraps {
-        ($e:expr) => { assert_eq!(($e).wrapping_neg(),  ($e)); }
-    }
-
-    check_neg_no_wrap!(0xfe_u8 as i8);
-    check_neg_no_wrap!(0xfedc_u16 as i16);
-    check_neg_no_wrap!(0xfedc_ba98_u32 as i32);
-    check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as i64);
-    check_neg_no_wrap!(0xfedc_ba98_7654_3217_u64 as u64 as isize);
-
-    check_neg_wraps!(0x80_u8 as i8);
-    check_neg_wraps!(0x8000_u16 as i16);
-    check_neg_wraps!(0x8000_0000_u32 as i32);
-    check_neg_wraps!(0x8000_0000_0000_0000_u64 as i64);
-    match () {
-        #[cfg(target_pointer_width = "32")]
-        () => {
-            check_neg_wraps!(0x8000_0000_u32 as isize);
-        }
-        #[cfg(target_pointer_width = "64")]
-        () => {
-            check_neg_wraps!(0x8000_0000_0000_0000_u64 as isize);
-        }
-    }
-
-}
diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs
index 6b32ebdc284..0a69b18a332 100644
--- a/src/tools/lint-docs/src/groups.rs
+++ b/src/tools/lint-docs/src/groups.rs
@@ -1,11 +1,11 @@
-use crate::Lint;
+use crate::{Lint, LintExtractor};
 use std::collections::{BTreeMap, BTreeSet};
 use std::error::Error;
 use std::fmt::Write;
 use std::fs;
-use std::path::Path;
 use std::process::Command;
 
+/// Descriptions of rustc lint groups.
 static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
     ("unused", "Lints that detect things being declared but not used, or excess syntax"),
     ("rustdoc", "Rustdoc-specific lints"),
@@ -15,100 +15,123 @@ static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
     ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"),
 ];
 
-/// Updates the documentation of lint groups.
-pub(crate) fn generate_group_docs(
-    lints: &[Lint],
-    rustc: crate::Rustc<'_>,
-    out_path: &Path,
-) -> Result<(), Box<dyn Error>> {
-    let groups = collect_groups(rustc)?;
-    let groups_path = out_path.join("groups.md");
-    let contents = fs::read_to_string(&groups_path)
-        .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
-    let new_contents = contents.replace("{{groups-table}}", &make_groups_table(lints, &groups)?);
-    // Delete the output because rustbuild uses hard links in its copies.
-    let _ = fs::remove_file(&groups_path);
-    fs::write(&groups_path, new_contents)
-        .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
-    Ok(())
-}
-
 type LintGroups = BTreeMap<String, BTreeSet<String>>;
 
-/// Collects the group names from rustc.
-fn collect_groups(rustc: crate::Rustc<'_>) -> Result<LintGroups, Box<dyn Error>> {
-    let mut result = BTreeMap::new();
-    let mut cmd = Command::new(rustc.path);
-    cmd.arg("-Whelp");
-    let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
-    if !output.status.success() {
-        return Err(format!(
-            "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
-            output.status,
-            std::str::from_utf8(&output.stderr).unwrap(),
-            std::str::from_utf8(&output.stdout).unwrap(),
-        )
-        .into());
+impl<'a> LintExtractor<'a> {
+    /// Updates the documentation of lint groups.
+    pub(crate) fn generate_group_docs(&self, lints: &[Lint]) -> Result<(), Box<dyn Error>> {
+        let groups = self.collect_groups()?;
+        let groups_path = self.out_path.join("groups.md");
+        let contents = fs::read_to_string(&groups_path)
+            .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?;
+        let new_contents =
+            contents.replace("{{groups-table}}", &self.make_groups_table(lints, &groups)?);
+        // Delete the output because rustbuild uses hard links in its copies.
+        let _ = fs::remove_file(&groups_path);
+        fs::write(&groups_path, new_contents)
+            .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?;
+        Ok(())
     }
-    let stdout = std::str::from_utf8(&output.stdout).unwrap();
-    let lines = stdout.lines();
-    let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
-    let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
-    for line in table_start {
-        if line.is_empty() {
-            break;
+
+    /// Collects the group names from rustc.
+    fn collect_groups(&self) -> Result<LintGroups, Box<dyn Error>> {
+        let mut result = BTreeMap::new();
+        let mut cmd = Command::new(self.rustc_path);
+        cmd.arg("-Whelp");
+        let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
+        if !output.status.success() {
+            return Err(format!(
+                "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n",
+                output.status,
+                std::str::from_utf8(&output.stderr).unwrap(),
+                std::str::from_utf8(&output.stdout).unwrap(),
+            )
+            .into());
         }
-        let mut parts = line.trim().splitn(2, ' ');
-        let name = parts.next().expect("name in group");
-        if name == "warnings" {
-            // This is special.
-            continue;
+        let stdout = std::str::from_utf8(&output.stdout).unwrap();
+        let lines = stdout.lines();
+        let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1);
+        let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1);
+        for line in table_start {
+            if line.is_empty() {
+                break;
+            }
+            let mut parts = line.trim().splitn(2, ' ');
+            let name = parts.next().expect("name in group");
+            if name == "warnings" {
+                // This is special.
+                continue;
+            }
+            let lints = parts
+                .next()
+                .ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
+            let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
+            assert!(result.insert(name.to_string(), lints).is_none());
         }
-        let lints =
-            parts.next().ok_or_else(|| format!("expected lints following name, got `{}`", line))?;
-        let lints = lints.split(',').map(|l| l.trim().to_string()).collect();
-        assert!(result.insert(name.to_string(), lints).is_none());
-    }
-    if result.is_empty() {
-        return Err(
-            format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
-        );
+        if result.is_empty() {
+            return Err(
+                format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
+            );
+        }
+        Ok(result)
     }
-    Ok(result)
-}
 
-fn make_groups_table(lints: &[Lint], groups: &LintGroups) -> Result<String, Box<dyn Error>> {
-    let mut result = String::new();
-    let mut to_link = Vec::new();
-    result.push_str("| Group | Description | Lints |\n");
-    result.push_str("|-------|-------------|-------|\n");
-    result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n");
-    for (group_name, group_lints) in groups {
-        let description = GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name)
-            .ok_or_else(|| format!("lint group `{}` does not have a description, please update the GROUP_DESCRIPTIONS list", group_name))?
-            .1;
-        to_link.extend(group_lints);
-        let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
-        write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")).unwrap();
-    }
-    result.push('\n');
-    result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
-    for lint_name in to_link {
-        let lint_def =
-            lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| {
-                format!(
-                    "`rustc -W help` defined lint `{}` but that lint does not appear to exist",
-                    lint_name
-                )
-            })?;
-        write!(
-            result,
-            "[{}]: listing/{}#{}\n",
-            lint_name,
-            lint_def.level.doc_filename(),
-            lint_name
-        )
-        .unwrap();
+    fn make_groups_table(
+        &self,
+        lints: &[Lint],
+        groups: &LintGroups,
+    ) -> Result<String, Box<dyn Error>> {
+        let mut result = String::new();
+        let mut to_link = Vec::new();
+        result.push_str("| Group | Description | Lints |\n");
+        result.push_str("|-------|-------------|-------|\n");
+        result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n");
+        for (group_name, group_lints) in groups {
+            let description = match GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name) {
+                Some((_, desc)) => desc,
+                None if self.validate => {
+                    return Err(format!(
+                        "lint group `{}` does not have a description, \
+                         please update the GROUP_DESCRIPTIONS list in \
+                         src/tools/lint-docs/src/groups.rs",
+                        group_name
+                    )
+                    .into());
+                }
+                None => {
+                    eprintln!(
+                        "warning: lint group `{}` is missing from the GROUP_DESCRIPTIONS list\n\
+                         If this is a new lint group, please update the GROUP_DESCRIPTIONS in \
+                         src/tools/lint-docs/src/groups.rs",
+                        group_name
+                    );
+                    continue;
+                }
+            };
+            to_link.extend(group_lints);
+            let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect();
+            write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", "))
+                .unwrap();
+        }
+        result.push('\n');
+        result.push_str("[warn-by-default]: listing/warn-by-default.md\n");
+        for lint_name in to_link {
+            let lint_def =
+                lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| {
+                    format!(
+                        "`rustc -W help` defined lint `{}` but that lint does not appear to exist",
+                        lint_name
+                    )
+                })?;
+            write!(
+                result,
+                "[{}]: listing/{}#{}\n",
+                lint_name,
+                lint_def.level.doc_filename(),
+                lint_name
+            )
+            .unwrap();
+        }
+        Ok(result)
     }
-    Ok(result)
 }
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
index 6ca71dcaf3c..326b7948098 100644
--- a/src/tools/lint-docs/src/lib.rs
+++ b/src/tools/lint-docs/src/lib.rs
@@ -7,6 +7,22 @@ use walkdir::WalkDir;
 
 mod groups;
 
+pub struct LintExtractor<'a> {
+    /// Path to the `src` directory, where it will scan for `.rs` files to
+    /// find lint declarations.
+    pub src_path: &'a Path,
+    /// Path where to save the output.
+    pub out_path: &'a Path,
+    /// Path to the `rustc` executable.
+    pub rustc_path: &'a Path,
+    /// The target arch to build the docs for.
+    pub rustc_target: &'a str,
+    /// Verbose output.
+    pub verbose: bool,
+    /// Validate the style and the code example.
+    pub validate: bool,
+}
+
 struct Lint {
     name: String,
     doc: Vec<String>,
@@ -26,6 +42,28 @@ impl Lint {
             .filter(|line| line.starts_with("```rust"))
             .all(|line| line.contains(",ignore"))
     }
+
+    /// Checks the doc style of the lint.
+    fn check_style(&self) -> Result<(), Box<dyn Error>> {
+        for &expected in &["### Example", "### Explanation", "{{produces}}"] {
+            if expected == "{{produces}}" && self.is_ignored() {
+                continue;
+            }
+            if !self.doc_contains(expected) {
+                return Err(format!("lint docs should contain the line `{}`", expected).into());
+            }
+        }
+        if let Some(first) = self.doc.first() {
+            if !first.starts_with(&format!("The `{}` lint", self.name)) {
+                return Err(format!(
+                    "lint docs should start with the text \"The `{}` lint\" to introduce the lint",
+                    self.name
+                )
+                .into());
+            }
+        }
+        Ok(())
+    }
 }
 
 #[derive(Clone, Copy, PartialEq)]
@@ -45,382 +83,396 @@ impl Level {
     }
 }
 
-#[derive(Copy, Clone)]
-pub struct Rustc<'a> {
-    pub path: &'a Path,
-    pub target: &'a str,
-}
-
-/// Collects all lints, and writes the markdown documentation at the given directory.
-pub fn extract_lint_docs(
-    src_path: &Path,
-    out_path: &Path,
-    rustc: Rustc<'_>,
-    verbose: bool,
-) -> Result<(), Box<dyn Error>> {
-    let mut lints = gather_lints(src_path)?;
-    for lint in &mut lints {
-        generate_output_example(lint, rustc, verbose).map_err(|e| {
-            format!(
-                "failed to test example in lint docs for `{}` in {}:{}: {}",
-                lint.name,
-                lint.path.display(),
-                lint.lineno,
-                e
-            )
-        })?;
+impl<'a> LintExtractor<'a> {
+    /// Collects all lints, and writes the markdown documentation at the given directory.
+    pub fn extract_lint_docs(&self) -> Result<(), Box<dyn Error>> {
+        let mut lints = self.gather_lints()?;
+        for lint in &mut lints {
+            self.generate_output_example(lint).map_err(|e| {
+                format!(
+                    "failed to test example in lint docs for `{}` in {}:{}: {}",
+                    lint.name,
+                    lint.path.display(),
+                    lint.lineno,
+                    e
+                )
+            })?;
+        }
+        self.save_lints_markdown(&lints)?;
+        self.generate_group_docs(&lints)?;
+        Ok(())
     }
-    save_lints_markdown(&lints, &out_path.join("listing"))?;
-    groups::generate_group_docs(&lints, rustc, out_path)?;
-    Ok(())
-}
 
-/// Collects all lints from all files in the given directory.
-fn gather_lints(src_path: &Path) -> Result<Vec<Lint>, Box<dyn Error>> {
-    let mut lints = Vec::new();
-    for entry in WalkDir::new(src_path).into_iter().filter_map(|e| e.ok()) {
-        if !entry.path().extension().map_or(false, |ext| ext == "rs") {
-            continue;
+    /// Collects all lints from all files in the given directory.
+    fn gather_lints(&self) -> Result<Vec<Lint>, Box<dyn Error>> {
+        let mut lints = Vec::new();
+        for entry in WalkDir::new(self.src_path).into_iter().filter_map(|e| e.ok()) {
+            if !entry.path().extension().map_or(false, |ext| ext == "rs") {
+                continue;
+            }
+            lints.extend(self.lints_from_file(entry.path())?);
         }
-        lints.extend(lints_from_file(entry.path())?);
-    }
-    if lints.is_empty() {
-        return Err("no lints were found!".into());
+        if lints.is_empty() {
+            return Err("no lints were found!".into());
+        }
+        Ok(lints)
     }
-    Ok(lints)
-}
 
-/// Collects all lints from the given file.
-fn lints_from_file(path: &Path) -> Result<Vec<Lint>, Box<dyn Error>> {
-    let mut lints = Vec::new();
-    let contents = fs::read_to_string(path)
-        .map_err(|e| format!("could not read {}: {}", path.display(), e))?;
-    let mut lines = contents.lines().enumerate();
-    loop {
-        // Find a lint declaration.
-        let lint_start = loop {
-            match lines.next() {
-                Some((lineno, line)) => {
-                    if line.trim().starts_with("declare_lint!") {
-                        break lineno + 1;
+    /// Collects all lints from the given file.
+    fn lints_from_file(&self, path: &Path) -> Result<Vec<Lint>, Box<dyn Error>> {
+        let mut lints = Vec::new();
+        let contents = fs::read_to_string(path)
+            .map_err(|e| format!("could not read {}: {}", path.display(), e))?;
+        let mut lines = contents.lines().enumerate();
+        'outer: loop {
+            // Find a lint declaration.
+            let lint_start = loop {
+                match lines.next() {
+                    Some((lineno, line)) => {
+                        if line.trim().starts_with("declare_lint!") {
+                            break lineno + 1;
+                        }
+                    }
+                    None => return Ok(lints),
+                }
+            };
+            // Read the lint.
+            let mut doc_lines = Vec::new();
+            let (doc, name) = loop {
+                match lines.next() {
+                    Some((lineno, line)) => {
+                        let line = line.trim();
+                        if let Some(text) = line.strip_prefix("/// ") {
+                            doc_lines.push(text.trim().to_string());
+                        } else if line.starts_with("///") {
+                            doc_lines.push("".to_string());
+                        } else if line.starts_with("// ") {
+                            // Ignore comments.
+                            continue;
+                        } else {
+                            let name = lint_name(line).map_err(|e| {
+                                format!(
+                                    "could not determine lint name in {}:{}: {}, line was `{}`",
+                                    path.display(),
+                                    lineno,
+                                    e,
+                                    line
+                                )
+                            })?;
+                            if doc_lines.is_empty() {
+                                if self.validate {
+                                    return Err(format!(
+                                        "did not find doc lines for lint `{}` in {}",
+                                        name,
+                                        path.display()
+                                    )
+                                    .into());
+                                } else {
+                                    eprintln!(
+                                        "warning: lint `{}` in {} does not define any doc lines, \
+                                         these are required for the lint documentation",
+                                        name,
+                                        path.display()
+                                    );
+                                    continue 'outer;
+                                }
+                            }
+                            break (doc_lines, name);
+                        }
+                    }
+                    None => {
+                        return Err(format!(
+                            "unexpected EOF for lint definition at {}:{}",
+                            path.display(),
+                            lint_start
+                        )
+                        .into());
                     }
                 }
-                None => return Ok(lints),
+            };
+            // These lints are specifically undocumented. This should be reserved
+            // for internal rustc-lints only.
+            if name == "deprecated_in_future" {
+                continue;
             }
-        };
-        // Read the lint.
-        let mut doc_lines = Vec::new();
-        let (doc, name) = loop {
-            match lines.next() {
-                Some((lineno, line)) => {
-                    let line = line.trim();
-                    if line.starts_with("/// ") {
-                        doc_lines.push(line.trim()[4..].to_string());
-                    } else if line.starts_with("///") {
-                        doc_lines.push("".to_string());
-                    } else if line.starts_with("// ") {
-                        // Ignore comments.
-                        continue;
-                    } else {
-                        let name = lint_name(line).map_err(|e| {
-                            format!(
-                                "could not determine lint name in {}:{}: {}, line was `{}`",
-                                path.display(),
-                                lineno,
-                                e,
-                                line
-                            )
-                        })?;
-                        if doc_lines.is_empty() {
+            // Read the level.
+            let level = loop {
+                match lines.next() {
+                    // Ignore comments.
+                    Some((_, line)) if line.trim().starts_with("// ") => {}
+                    Some((lineno, line)) => match line.trim() {
+                        "Allow," => break Level::Allow,
+                        "Warn," => break Level::Warn,
+                        "Deny," => break Level::Deny,
+                        _ => {
                             return Err(format!(
-                                "did not find doc lines for lint `{}` in {}",
-                                name,
-                                path.display()
+                                "unexpected lint level `{}` in {}:{}",
+                                line,
+                                path.display(),
+                                lineno
                             )
                             .into());
                         }
-                        break (doc_lines, name);
-                    }
-                }
-                None => {
-                    return Err(format!(
-                        "unexpected EOF for lint definition at {}:{}",
-                        path.display(),
-                        lint_start
-                    )
-                    .into());
-                }
-            }
-        };
-        // These lints are specifically undocumented. This should be reserved
-        // for internal rustc-lints only.
-        if name == "deprecated_in_future" {
-            continue;
-        }
-        // Read the level.
-        let level = loop {
-            match lines.next() {
-                // Ignore comments.
-                Some((_, line)) if line.trim().starts_with("// ") => {}
-                Some((lineno, line)) => match line.trim() {
-                    "Allow," => break Level::Allow,
-                    "Warn," => break Level::Warn,
-                    "Deny," => break Level::Deny,
-                    _ => {
+                    },
+                    None => {
                         return Err(format!(
-                            "unexpected lint level `{}` in {}:{}",
-                            line,
+                            "expected lint level in {}:{}, got EOF",
                             path.display(),
-                            lineno
+                            lint_start
                         )
                         .into());
                     }
-                },
-                None => {
-                    return Err(format!(
-                        "expected lint level in {}:{}, got EOF",
-                        path.display(),
-                        lint_start
-                    )
-                    .into());
                 }
-            }
-        };
-        // The rest of the lint definition is ignored.
-        assert!(!doc.is_empty());
-        lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start });
-    }
-}
-
-/// Extracts the lint name (removing the visibility modifier, and checking validity).
-fn lint_name(line: &str) -> Result<String, &'static str> {
-    // Skip over any potential `pub` visibility.
-    match line.trim().split(' ').next_back() {
-        Some(name) => {
-            if !name.ends_with(',') {
-                return Err("lint name should end with comma");
-            }
-            let name = &name[..name.len() - 1];
-            if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() {
-                return Err("lint name did not have expected format");
-            }
-            Ok(name.to_lowercase().to_string())
+            };
+            // The rest of the lint definition is ignored.
+            assert!(!doc.is_empty());
+            lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start });
         }
-        None => Err("could not find lint name"),
-    }
-}
-
-/// Mutates the lint definition to replace the `{{produces}}` marker with the
-/// actual output from the compiler.
-fn generate_output_example(
-    lint: &mut Lint,
-    rustc: Rustc<'_>,
-    verbose: bool,
-) -> Result<(), Box<dyn Error>> {
-    // Explicit list of lints that are allowed to not have an example. Please
-    // try to avoid adding to this list.
-    if matches!(
-        lint.name.as_str(),
-        "unused_features" // broken lint
-        | "unstable_features" // deprecated
-    ) {
-        return Ok(());
-    }
-    if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") {
-        // Rustdoc lints are documented in the rustdoc book, don't check these.
-        return Ok(());
     }
-    check_style(lint)?;
-    // Unfortunately some lints have extra requirements that this simple test
-    // setup can't handle (like extern crates). An alternative is to use a
-    // separate test suite, and use an include mechanism such as mdbook's
-    // `{{#rustdoc_include}}`.
-    if !lint.is_ignored() {
-        replace_produces(lint, rustc, verbose)?;
-    }
-    Ok(())
-}
 
-/// Checks the doc style of the lint.
-fn check_style(lint: &Lint) -> Result<(), Box<dyn Error>> {
-    for &expected in &["### Example", "### Explanation", "{{produces}}"] {
-        if expected == "{{produces}}" && lint.is_ignored() {
-            continue;
+    /// Mutates the lint definition to replace the `{{produces}}` marker with the
+    /// actual output from the compiler.
+    fn generate_output_example(&self, lint: &mut Lint) -> Result<(), Box<dyn Error>> {
+        // Explicit list of lints that are allowed to not have an example. Please
+        // try to avoid adding to this list.
+        if matches!(
+            lint.name.as_str(),
+            "unused_features" // broken lint
+            | "unstable_features" // deprecated
+        ) {
+            return Ok(());
         }
-        if !lint.doc_contains(expected) {
-            return Err(format!("lint docs should contain the line `{}`", expected).into());
+        if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") {
+            // Rustdoc lints are documented in the rustdoc book, don't check these.
+            return Ok(());
         }
-    }
-    if let Some(first) = lint.doc.first() {
-        if !first.starts_with(&format!("The `{}` lint", lint.name)) {
-            return Err(format!(
-                "lint docs should start with the text \"The `{}` lint\" to introduce the lint",
-                lint.name
-            )
-            .into());
+        if self.validate {
+            lint.check_style()?;
+        }
+        // Unfortunately some lints have extra requirements that this simple test
+        // setup can't handle (like extern crates). An alternative is to use a
+        // separate test suite, and use an include mechanism such as mdbook's
+        // `{{#rustdoc_include}}`.
+        if !lint.is_ignored() {
+            if let Err(e) = self.replace_produces(lint) {
+                if self.validate {
+                    return Err(e);
+                }
+                eprintln!(
+                    "warning: the code example in lint `{}` in {} failed to \
+                     generate the expected output: {}",
+                    lint.name,
+                    lint.path.display(),
+                    e
+                );
+            }
         }
+        Ok(())
     }
-    Ok(())
-}
 
-/// Mutates the lint docs to replace the `{{produces}}` marker with the actual
-/// output from the compiler.
-fn replace_produces(
-    lint: &mut Lint,
-    rustc: Rustc<'_>,
-    verbose: bool,
-) -> Result<(), Box<dyn Error>> {
-    let mut lines = lint.doc.iter_mut();
-    loop {
-        // Find start of example.
-        let options = loop {
-            match lines.next() {
-                Some(line) if line.starts_with("```rust") => {
-                    break line[7..].split(',').collect::<Vec<_>>();
+    /// Mutates the lint docs to replace the `{{produces}}` marker with the actual
+    /// output from the compiler.
+    fn replace_produces(&self, lint: &mut Lint) -> Result<(), Box<dyn Error>> {
+        let mut lines = lint.doc.iter_mut();
+        loop {
+            // Find start of example.
+            let options = loop {
+                match lines.next() {
+                    Some(line) if line.starts_with("```rust") => {
+                        break line[7..].split(',').collect::<Vec<_>>();
+                    }
+                    Some(line) if line.contains("{{produces}}") => {
+                        return Err("lint marker {{{{produces}}}} found, \
+                            but expected to immediately follow a rust code block"
+                            .into());
+                    }
+                    Some(_) => {}
+                    None => return Ok(()),
                 }
-                Some(line) if line.contains("{{produces}}") => {
-                    return Err("lint marker {{{{produces}}}} found, \
-                        but expected to immediately follow a rust code block"
+            };
+            // Find the end of example.
+            let mut example = Vec::new();
+            loop {
+                match lines.next() {
+                    Some(line) if line == "```" => break,
+                    Some(line) => example.push(line),
+                    None => {
+                        return Err(format!(
+                            "did not find end of example triple ticks ```, docs were:\n{:?}",
+                            lint.doc
+                        )
                         .into());
-                }
-                Some(_) => {}
-                None => return Ok(()),
-            }
-        };
-        // Find the end of example.
-        let mut example = Vec::new();
-        loop {
-            match lines.next() {
-                Some(line) if line == "```" => break,
-                Some(line) => example.push(line),
-                None => {
-                    return Err(format!(
-                        "did not find end of example triple ticks ```, docs were:\n{:?}",
-                        lint.doc
-                    )
-                    .into());
+                    }
                 }
             }
-        }
-        // Find the {{produces}} line.
-        loop {
-            match lines.next() {
-                Some(line) if line.is_empty() => {}
-                Some(line) if line == "{{produces}}" => {
-                    let output =
-                        generate_lint_output(&lint.name, &example, &options, rustc, verbose)?;
-                    line.replace_range(
-                        ..,
-                        &format!(
-                            "This will produce:\n\
-                        \n\
-                        ```text\n\
-                        {}\
-                        ```",
-                            output
-                        ),
-                    );
-                    break;
+            // Find the {{produces}} line.
+            loop {
+                match lines.next() {
+                    Some(line) if line.is_empty() => {}
+                    Some(line) if line == "{{produces}}" => {
+                        let output = self.generate_lint_output(&lint.name, &example, &options)?;
+                        line.replace_range(
+                            ..,
+                            &format!(
+                                "This will produce:\n\
+                            \n\
+                            ```text\n\
+                            {}\
+                            ```",
+                                output
+                            ),
+                        );
+                        break;
+                    }
+                    // No {{produces}} after example, find next example.
+                    Some(_line) => break,
+                    None => return Ok(()),
                 }
-                // No {{produces}} after example, find next example.
-                Some(_line) => break,
-                None => return Ok(()),
             }
         }
     }
-}
 
-/// Runs the compiler against the example, and extracts the output.
-fn generate_lint_output(
-    name: &str,
-    example: &[&mut String],
-    options: &[&str],
-    rustc: Rustc<'_>,
-    verbose: bool,
-) -> Result<String, Box<dyn Error>> {
-    if verbose {
-        eprintln!("compiling lint {}", name);
-    }
-    let tempdir = tempfile::TempDir::new()?;
-    let tempfile = tempdir.path().join("lint_example.rs");
-    let mut source = String::new();
-    let needs_main = !example.iter().any(|line| line.contains("fn main"));
-    // Remove `# ` prefix for hidden lines.
-    let unhidden =
-        example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line });
-    let mut lines = unhidden.peekable();
-    while let Some(line) = lines.peek() {
-        if line.starts_with("#!") {
+    /// Runs the compiler against the example, and extracts the output.
+    fn generate_lint_output(
+        &self,
+        name: &str,
+        example: &[&mut String],
+        options: &[&str],
+    ) -> Result<String, Box<dyn Error>> {
+        if self.verbose {
+            eprintln!("compiling lint {}", name);
+        }
+        let tempdir = tempfile::TempDir::new()?;
+        let tempfile = tempdir.path().join("lint_example.rs");
+        let mut source = String::new();
+        let needs_main = !example.iter().any(|line| line.contains("fn main"));
+        // Remove `# ` prefix for hidden lines.
+        let unhidden = example.iter().map(|line| line.strip_prefix("# ").unwrap_or(line));
+        let mut lines = unhidden.peekable();
+        while let Some(line) = lines.peek() {
+            if line.starts_with("#!") {
+                source.push_str(line);
+                source.push('\n');
+                lines.next();
+            } else {
+                break;
+            }
+        }
+        if needs_main {
+            source.push_str("fn main() {\n");
+        }
+        for line in lines {
             source.push_str(line);
-            source.push('\n');
-            lines.next();
+            source.push('\n')
+        }
+        if needs_main {
+            source.push_str("}\n");
+        }
+        fs::write(&tempfile, source)
+            .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?;
+        let mut cmd = Command::new(self.rustc_path);
+        if options.contains(&"edition2015") {
+            cmd.arg("--edition=2015");
         } else {
-            break;
+            cmd.arg("--edition=2018");
+        }
+        cmd.arg("--error-format=json");
+        cmd.arg("--target").arg(self.rustc_target);
+        if options.contains(&"test") {
+            cmd.arg("--test");
+        }
+        cmd.arg("lint_example.rs");
+        cmd.current_dir(tempdir.path());
+        let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
+        let stderr = std::str::from_utf8(&output.stderr).unwrap();
+        let msgs = stderr
+            .lines()
+            .filter(|line| line.starts_with('{'))
+            .map(serde_json::from_str)
+            .collect::<Result<Vec<serde_json::Value>, _>>()?;
+        match msgs
+            .iter()
+            .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
+        {
+            Some(msg) => {
+                let rendered = msg["rendered"].as_str().expect("rendered field should exist");
+                Ok(rendered.to_string())
+            }
+            None => {
+                match msgs.iter().find(
+                    |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
+                ) {
+                    Some(msg) => {
+                        let rendered = msg["rendered"].as_str().expect("rendered field should exist");
+                        Ok(rendered.to_string())
+                    }
+                    None => {
+                        let rendered: Vec<&str> =
+                            msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
+                        let non_json: Vec<&str> =
+                            stderr.lines().filter(|line| !line.starts_with('{')).collect();
+                        Err(format!(
+                            "did not find lint `{}` in output of example, got:\n{}\n{}",
+                            name,
+                            non_json.join("\n"),
+                            rendered.join("\n")
+                        )
+                        .into())
+                    }
+                }
+            }
         }
     }
-    if needs_main {
-        source.push_str("fn main() {\n");
-    }
-    for line in lines {
-        source.push_str(line);
-        source.push('\n')
-    }
-    if needs_main {
-        source.push_str("}\n");
-    }
-    fs::write(&tempfile, source)
-        .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?;
-    let mut cmd = Command::new(rustc.path);
-    if options.contains(&"edition2015") {
-        cmd.arg("--edition=2015");
-    } else {
-        cmd.arg("--edition=2018");
-    }
-    cmd.arg("--error-format=json");
-    cmd.arg("--target").arg(rustc.target);
-    if options.contains(&"test") {
-        cmd.arg("--test");
+
+    /// Saves the mdbook lint chapters at the given path.
+    fn save_lints_markdown(&self, lints: &[Lint]) -> Result<(), Box<dyn Error>> {
+        self.save_level(lints, Level::Allow, ALLOWED_MD)?;
+        self.save_level(lints, Level::Warn, WARN_MD)?;
+        self.save_level(lints, Level::Deny, DENY_MD)?;
+        Ok(())
     }
-    cmd.arg("lint_example.rs");
-    cmd.current_dir(tempdir.path());
-    let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?;
-    let stderr = std::str::from_utf8(&output.stderr).unwrap();
-    let msgs = stderr
-        .lines()
-        .filter(|line| line.starts_with('{'))
-        .map(serde_json::from_str)
-        .collect::<Result<Vec<serde_json::Value>, _>>()?;
-    match msgs
-        .iter()
-        .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name))
-    {
-        Some(msg) => {
-            let rendered = msg["rendered"].as_str().expect("rendered field should exist");
-            Ok(rendered.to_string())
+
+    fn save_level(&self, lints: &[Lint], level: Level, header: &str) -> Result<(), Box<dyn Error>> {
+        let mut result = String::new();
+        result.push_str(header);
+        let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect();
+        these_lints.sort_unstable_by_key(|lint| &lint.name);
+        for lint in &these_lints {
+            write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap();
         }
-        None => {
-            match msgs.iter().find(
-                |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)),
-            ) {
-                Some(msg) => {
-                    let rendered = msg["rendered"].as_str().expect("rendered field should exist");
-                    Ok(rendered.to_string())
-                }
-                None => {
-                    let rendered: Vec<&str> =
-                        msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect();
-                    let non_json: Vec<&str> =
-                        stderr.lines().filter(|line| !line.starts_with('{')).collect();
-                    Err(format!(
-                        "did not find lint `{}` in output of example, got:\n{}\n{}",
-                        name,
-                        non_json.join("\n"),
-                        rendered.join("\n")
-                    )
-                    .into())
-                }
+        result.push('\n');
+        for lint in &these_lints {
+            write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap();
+            for line in &lint.doc {
+                result.push_str(line);
+                result.push('\n');
+            }
+            result.push('\n');
+        }
+        let out_path = self.out_path.join("listing").join(level.doc_filename());
+        // Delete the output because rustbuild uses hard links in its copies.
+        let _ = fs::remove_file(&out_path);
+        fs::write(&out_path, result)
+            .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?;
+        Ok(())
+    }
+}
+
+/// Extracts the lint name (removing the visibility modifier, and checking validity).
+fn lint_name(line: &str) -> Result<String, &'static str> {
+    // Skip over any potential `pub` visibility.
+    match line.trim().split(' ').next_back() {
+        Some(name) => {
+            if !name.ends_with(',') {
+                return Err("lint name should end with comma");
             }
+            let name = &name[..name.len() - 1];
+            if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() {
+                return Err("lint name did not have expected format");
+            }
+            Ok(name.to_lowercase().to_string())
         }
+        None => Err("could not find lint name"),
     }
 }
 
@@ -442,41 +494,3 @@ static DENY_MD: &str = r#"# Deny-by-default lints
 These lints are all set to the 'deny' level by default.
 
 "#;
-
-/// Saves the mdbook lint chapters at the given path.
-fn save_lints_markdown(lints: &[Lint], out_dir: &Path) -> Result<(), Box<dyn Error>> {
-    save_level(lints, Level::Allow, out_dir, ALLOWED_MD)?;
-    save_level(lints, Level::Warn, out_dir, WARN_MD)?;
-    save_level(lints, Level::Deny, out_dir, DENY_MD)?;
-    Ok(())
-}
-
-fn save_level(
-    lints: &[Lint],
-    level: Level,
-    out_dir: &Path,
-    header: &str,
-) -> Result<(), Box<dyn Error>> {
-    let mut result = String::new();
-    result.push_str(header);
-    let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect();
-    these_lints.sort_unstable_by_key(|lint| &lint.name);
-    for lint in &these_lints {
-        write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap();
-    }
-    result.push('\n');
-    for lint in &these_lints {
-        write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap();
-        for line in &lint.doc {
-            result.push_str(line);
-            result.push('\n');
-        }
-        result.push('\n');
-    }
-    let out_path = out_dir.join(level.doc_filename());
-    // Delete the output because rustbuild uses hard links in its copies.
-    let _ = fs::remove_file(&out_path);
-    fs::write(&out_path, result)
-        .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?;
-    Ok(())
-}
diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs
index 5db49007d37..2055fed2b48 100644
--- a/src/tools/lint-docs/src/main.rs
+++ b/src/tools/lint-docs/src/main.rs
@@ -3,7 +3,20 @@ use std::path::PathBuf;
 
 fn main() {
     if let Err(e) = doit() {
-        println!("error: {}", e);
+        eprintln!("error: {}", e);
+        eprintln!(
+            "
+This error was generated by the lint-docs tool.
+This tool extracts documentation for lints from the source code and places
+them in the rustc book. See the declare_lint! documentation
+https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint_defs/macro.declare_lint.html
+for an example of the format of documentation this tool expects.
+
+To re-run these tests, run: ./x.py test --keep-stage=0 src/tools/lint-docs
+The --keep-stage flag should be used if you have already built the compiler
+and are only modifying the doc comments to avoid rebuilding the compiler.
+"
+        );
         std::process::exit(1);
     }
 }
@@ -15,6 +28,7 @@ fn doit() -> Result<(), Box<dyn Error>> {
     let mut rustc_path = None;
     let mut rustc_target = None;
     let mut verbose = false;
+    let mut validate = false;
     while let Some(arg) = args.next() {
         match arg.as_str() {
             "--src" => {
@@ -42,6 +56,7 @@ fn doit() -> Result<(), Box<dyn Error>> {
                 };
             }
             "-v" | "--verbose" => verbose = true,
+            "--validate" => validate = true,
             s => return Err(format!("unexpected argument `{}`", s).into()),
         }
     }
@@ -57,13 +72,13 @@ fn doit() -> Result<(), Box<dyn Error>> {
     if rustc_target.is_none() {
         return Err("--rustc-target must be specified to the rustc target".into());
     }
-    lint_docs::extract_lint_docs(
-        &src_path.unwrap(),
-        &out_path.unwrap(),
-        lint_docs::Rustc {
-            path: rustc_path.as_deref().unwrap(),
-            target: rustc_target.as_deref().unwrap(),
-        },
+    let le = lint_docs::LintExtractor {
+        src_path: &src_path.unwrap(),
+        out_path: &out_path.unwrap(),
+        rustc_path: &rustc_path.unwrap(),
+        rustc_target: &rustc_target.unwrap(),
         verbose,
-    )
+        validate,
+    };
+    le.extract_lint_docs()
 }
diff --git a/src/tools/miri b/src/tools/miri
-Subproject 746ea5b141baf1f86c2ad17753a37b135e0c1aa
+Subproject 47acece7aa25d7b5edfae0bfd4b94e6e55a7b4b