about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Huss <eric@huss.org>2020-09-08 15:09:57 -0700
committerEric Huss <eric@huss.org>2020-09-13 08:48:03 -0700
commit45c1e0ae07b9581d8c2d2b39315ac7cc79475d75 (patch)
treebffba54de1eeb0b5dc313e3497b68aead9b9cc97
parenta055c5a1bd95e029e9b31891db63b6dc8258b472 (diff)
downloadrust-45c1e0ae07b9581d8c2d2b39315ac7cc79475d75.tar.gz
rust-45c1e0ae07b9581d8c2d2b39315ac7cc79475d75.zip
Auto-generate lint documentation.
-rw-r--r--Cargo.lock9
-rw-r--r--Cargo.toml1
-rw-r--r--compiler/rustc_lint/src/array_into_iter.rs25
-rw-r--r--compiler/rustc_lint/src/builtin.rs504
-rw-r--r--compiler/rustc_lint/src/non_ascii_idents.rs129
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs49
-rw-r--r--compiler/rustc_lint/src/redundant_semicolon.rs15
-rw-r--r--compiler/rustc_lint/src/types.rs106
-rw-r--r--compiler/rustc_lint/src/unused.rs146
-rw-r--r--compiler/rustc_session/src/lint.rs56
-rw-r--r--compiler/rustc_session/src/lint/builtin.rs2118
-rw-r--r--src/bootstrap/doc.rs67
-rw-r--r--src/bootstrap/tool.rs1
-rw-r--r--src/doc/rustc/src/lints/groups.md9
-rw-r--r--src/doc/rustc/src/lints/index.md32
-rw-r--r--src/doc/rustc/src/lints/listing/allowed-by-default.md453
-rw-r--r--src/doc/rustc/src/lints/listing/deny-by-default.md202
-rw-r--r--src/doc/rustc/src/lints/listing/warn-by-default.md902
-rw-r--r--src/tools/lint-docs/Cargo.toml13
-rw-r--r--src/tools/lint-docs/src/groups.rs114
-rw-r--r--src/tools/lint-docs/src/lib.rs463
-rw-r--r--src/tools/lint-docs/src/main.rs67
22 files changed, 3914 insertions, 1567 deletions
diff --git a/Cargo.lock b/Cargo.lock
index b448baf425b..1a67deacbfe 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1678,6 +1678,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a"
 
 [[package]]
+name = "lint-docs"
+version = "0.1.0"
+dependencies = [
+ "serde_json",
+ "tempfile",
+ "walkdir",
+]
+
+[[package]]
 name = "lock_api"
 version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index fde1cb5a35c..02794d1028b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -9,6 +9,7 @@ members = [
   "src/tools/compiletest",
   "src/tools/error_index_generator",
   "src/tools/linkchecker",
+  "src/tools/lint-docs",
   "src/tools/rustbook",
   "src/tools/unstable-book-gen",
   "src/tools/tidy",
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
index 1d27bdcb282..e6be082da0e 100644
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ b/compiler/rustc_lint/src/array_into_iter.rs
@@ -7,6 +7,31 @@ use rustc_session::lint::FutureIncompatibleInfo;
 use rustc_span::symbol::sym;
 
 declare_lint! {
+    /// The `array_into_iter` lint detects calling `into_iter` on arrays.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// [1, 2, 3].into_iter().for_each(|n| { *n; });
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In the future, it is planned to add an `IntoIter` implementation for
+    /// arrays such that it will iterate over *values* of the array instead of
+    /// references. Due to how method resolution works, this will change
+    /// existing code that uses `into_iter` on arrays. The solution to avoid
+    /// this warning is to use `iter()` instead of `into_iter()`.
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard error
+    /// in the future. See [issue #66145] for more details and a more thorough
+    /// description of the lint.
+    ///
+    /// [issue #66145]: https://github.com/rust-lang/rust/issues/66145
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub ARRAY_INTO_ITER,
     Warn,
     "detects calling `into_iter` on arrays",
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index d18d89ed641..e785ba03d22 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -61,6 +61,23 @@ use tracing::{debug, trace};
 pub use rustc_session::lint::builtin::*;
 
 declare_lint! {
+    /// The `while_true` lint detects `while true { }`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,no_run
+    /// while true {
+    ///
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// `while true` should be replaced with `loop`. A `loop` expression is
+    /// the preferred way to write an infinite loop because it more directly
+    /// expresses the intent of the loop.
     WHILE_TRUE,
     Warn,
     "suggest using `loop { }` instead of `while true { }`"
@@ -102,6 +119,24 @@ impl EarlyLintPass for WhileTrue {
 }
 
 declare_lint! {
+    /// The `box_pointers` lints use of the Box type.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(box_pointers)]
+    /// struct Foo {
+    ///     x: Box<isize>,
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint is mostly historical, and not particularly useful. `Box<T>`
+    /// used to be built into the language, and the only way to do heap
+    /// allocation. Today's Rust can call into other allocators, etc.
     BOX_POINTERS,
     Allow,
     "use of owned (Box type) heap memory"
@@ -156,6 +191,36 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers {
 }
 
 declare_lint! {
+    /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }`
+    /// instead of `Struct { x }` in a pattern.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// struct Point {
+    ///     x: i32,
+    ///     y: i32,
+    /// }
+    ///
+    ///
+    /// fn main() {
+    ///     let p = Point {
+    ///         x: 5,
+    ///         y: 5,
+    ///     };
+    ///
+    ///     match p {
+    ///         Point { x: x, y: y } => (),
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The preferred style is to avoid the repetition of specifying both the
+    /// field name and the binding name if both identifiers are the same.
     NON_SHORTHAND_FIELD_PATTERNS,
     Warn,
     "using `Struct { x: x }` instead of `Struct { x }` in a pattern"
@@ -216,6 +281,25 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns {
 }
 
 declare_lint! {
+    /// The `unsafe_code` lint catches usage of `unsafe` code.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unsafe_code)]
+    /// fn main() {
+    ///     unsafe {
+    ///
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint is intended to restrict the usage of `unsafe`, which can be
+    /// difficult to use correctly.
     UNSAFE_CODE,
     Allow,
     "usage of `unsafe` code"
@@ -303,6 +387,25 @@ impl EarlyLintPass for UnsafeCode {
 }
 
 declare_lint! {
+    /// The `missing_docs` lint detects missing documentation for public items.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(missing_docs)]
+    /// pub fn foo() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint is intended to ensure that a library is well-documented.
+    /// Items without documentation can be difficult for users to understand
+    /// how to use properly.
+    ///
+    /// This lint is "allow" by default because it can be noisy, and not all
+    /// projects may want to enforce everything to be documented.
     pub MISSING_DOCS,
     Allow,
     "detects missing documentation for public members",
@@ -528,6 +631,34 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
 }
 
 declare_lint! {
+    /// The `missing_copy_implementations` lint detects potentially-forgotten
+    /// implementations of [`Copy`].
+    ///
+    /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(missing_copy_implementations)]
+    /// pub struct Foo {
+    ///     pub field: i32
+    /// }
+    /// # fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Historically (before 1.0), types were automatically marked as `Copy`
+    /// if possible. This was changed so that it required an explicit opt-in
+    /// by implementing the `Copy` trait. As part of this change, a lint was
+    /// added to alert if a copyable type was not marked `Copy`.
+    ///
+    /// This lint is "allow" by default because this code isn't bad; it is
+    /// common to write newtypes like this specifically so that a `Copy` type
+    /// is no longer `Copy`. `Copy` types can result in unintended copies of
+    /// large data which can impact performance.
     pub MISSING_COPY_IMPLEMENTATIONS,
     Allow,
     "detects potentially-forgotten implementations of `Copy`"
@@ -584,6 +715,32 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
 }
 
 declare_lint! {
+    /// The `missing_debug_implementations` lint detects missing
+    /// implementations of [`fmt::Debug`].
+    ///
+    /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(missing_debug_implementations)]
+    /// pub struct Foo;
+    /// # fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Having a `Debug` implementation on all types can assist with
+    /// debugging, as it provides a convenient way to format and display a
+    /// value. Using the `#[derive(Debug)]` attribute will automatically
+    /// generate a typical implementation, or a custom implementation can be
+    /// added by manually implementing the `Debug` trait.
+    ///
+    /// This lint is "allow" by default because adding `Debug` to all types can
+    /// have a negative impact on compile time and code size. It also requires
+    /// boilerplate to be added to every type, which can be an impediment.
     MISSING_DEBUG_IMPLEMENTATIONS,
     Allow,
     "detects missing implementations of Debug"
@@ -640,6 +797,45 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
 }
 
 declare_lint! {
+    /// The `anonymous_parameters` lint detects anonymous parameters in trait
+    /// definitions.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2015,compile_fail
+    /// #![deny(anonymous_parameters)]
+    /// // edition 2015
+    /// pub trait Foo {
+    ///     fn foo(usize);
+    /// }
+    /// fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This syntax is mostly a historical accident, and can be worked around
+    /// quite easily by adding an `_` pattern or a descriptive identifier:
+    ///
+    /// ```rust
+    /// trait Foo {
+    ///     fn foo(_: usize);
+    /// }
+    /// ```
+    ///
+    /// This syntax is now a hard error in the 2018 edition. In the 2015
+    /// edition, this lint is "allow" by default, because the old code is
+    /// still valid, and warning for all old code can be noisy. This lint
+    /// enables the [`cargo fix`] tool with the `--edition` flag to
+    /// automatically transition old code from the 2015 edition to 2018. The
+    /// tool will switch this lint to "warn" and will automatically apply the
+    /// suggested fix from the compiler (which is to add `_` to each
+    /// parameter). This provides a completely automated way to update old
+    /// code for a new edition. See [issue #41686] for more details.
+    ///
+    /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686
+    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
     pub ANONYMOUS_PARAMETERS,
     Allow,
     "detects anonymous parameters",
@@ -806,12 +1002,54 @@ impl EarlyLintPass for UnusedDocComment {
 }
 
 declare_lint! {
+    /// The `no_mangle_const_items` lint detects any `const` items with the
+    /// [`no_mangle` attribute].
+    ///
+    /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #[no_mangle]
+    /// const FOO: i32 = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Constants do not have their symbols exported, and therefore, this
+    /// probably means you meant to use a [`static`], not a [`const`].
+    ///
+    /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
+    /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html
     NO_MANGLE_CONST_ITEMS,
     Deny,
     "const items will not have their symbols exported"
 }
 
 declare_lint! {
+    /// The `no_mangle_generic_items` lint detects generic items that must be
+    /// mangled.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #[no_mangle]
+    /// fn foo<T>(t: T) {
+    ///
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// An function with generics must have its symbol mangled to accommodate
+    /// the generic parameter. The [`no_mangle` attribute] has no effect in
+    /// this situation, and should be removed.
+    ///
+    /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute
     NO_MANGLE_GENERIC_ITEMS,
     Warn,
     "generic items must be mangled"
@@ -882,6 +1120,27 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
 }
 
 declare_lint! {
+    /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut
+    /// T` because it is [undefined behavior].
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// unsafe {
+    ///     let y = std::mem::transmute::<&i32, &mut i32>(&5);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Certain assumptions are made about aliasing of data, and this transmute
+    /// violates those assumptions. Consider using [`UnsafeCell`] instead.
+    ///
+    /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html
     MUTABLE_TRANSMUTES,
     Deny,
     "mutating transmuted &mut T from &T may cause undefined behavior"
@@ -931,6 +1190,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes {
 }
 
 declare_lint! {
+    /// The `unstable_features` is deprecated and should no longer be used.
     UNSTABLE_FEATURES,
     Allow,
     "enabling unstable features (deprecated. do not use)"
@@ -956,6 +1216,32 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
 }
 
 declare_lint! {
+    /// The `unreachable_pub` lint triggers for `pub` items not reachable from
+    /// the crate root.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unreachable_pub)]
+    /// mod foo {
+    ///     pub mod bar {
+    ///
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A bare `pub` visibility may be misleading if the item is not actually
+    /// publicly exported from the crate. The `pub(crate)` visibility is
+    /// recommended to be used instead, which more clearly expresses the intent
+    /// that the item is only visible within its own crate.
+    ///
+    /// This lint is "allow" by default because it will trigger for a large
+    /// amount existing Rust code, and has some false-positives. Eventually it
+    /// is desired for this to become warn-by-default.
     pub UNREACHABLE_PUB,
     Allow,
     "`pub` items not reachable from crate root"
@@ -1035,6 +1321,21 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
 }
 
 declare_lint! {
+    /// The `type_alias_bounds` lint detects bounds in type aliases.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// type SendVec<T: Send> = Vec<T>;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The trait bounds in a type alias are currently ignored, and should not
+    /// be included to avoid confusion. This was previously allowed
+    /// unintentionally; this may become a hard error in the future.
     TYPE_ALIAS_BOUNDS,
     Warn,
     "bounds in type aliases are not enforced"
@@ -1194,6 +1495,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst {
 }
 
 declare_lint! {
+    /// The `trivial_bounds` lint detects trait bounds that don't depend on
+    /// any type parameters.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(trivial_bounds)]
+    /// pub struct A where i32: Copy;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Usually you would not write a trait bound that you know is always
+    /// true, or never true. However, when using macros, the macro may not
+    /// know whether or not the constraint would hold or not at the time when
+    /// generating the code. Currently, the compiler does not alert you if the
+    /// constraint is always true, and generates an error if it is never true.
+    /// The `trivial_bounds` feature changes this to be a warning in both
+    /// cases, giving macros more freedom and flexibility to generate code,
+    /// while still providing a signal when writing non-macro code that
+    /// something is amiss.
+    ///
+    /// See [RFC 2056] for more details. This feature is currently only
+    /// available on the nightly channel, see [tracking issue #48214].
+    ///
+    /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md
+    /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214
     TRIVIAL_BOUNDS,
     Warn,
     "these bounds don't depend on an type parameters"
@@ -1269,6 +1599,29 @@ declare_lint_pass!(
 );
 
 declare_lint! {
+    /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range
+    /// pattern], which is deprecated.
+    ///
+    /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 123;
+    /// match x {
+    ///     0...100 => {}
+    ///     _ => {}
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The `...` range pattern syntax was changed to `..=` to avoid potential
+    /// confusion with the [`..` range expression]. Use the new form instead.
+    ///
+    /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html
     pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS,
     Warn,
     "`...` range patterns are deprecated"
@@ -1355,6 +1708,38 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
 }
 
 declare_lint! {
+    /// The `unnameable_test_items` lint detects [`#[test]`][test] functions
+    /// that are not able to be run by the test harness because they are in a
+    /// position where they are not nameable.
+    ///
+    /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute
+    ///
+    /// ### Example
+    ///
+    /// ```rust,test
+    /// fn main() {
+    ///     #[test]
+    ///     fn foo() {
+    ///         // This test will not fail because it does not run.
+    ///         assert_eq!(1, 2);
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In order for the test harness to run a test, the test function must be
+    /// located in a position where it can be accessed from the crate root.
+    /// This generally means it must be defined in a module, and not anywhere
+    /// else such as inside another function. The compiler previously allowed
+    /// this without an error, so a lint was added as an alert that a test is
+    /// not being used. Whether or not this should be allowed has not yet been
+    /// decided, see [RFC 2471] and [issue #36629].
+    ///
+    /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443
+    /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629
     UNNAMEABLE_TEST_ITEMS,
     Warn,
     "detects an item that cannot be named being marked as `#[test_case]`",
@@ -1400,6 +1785,41 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems {
 }
 
 declare_lint! {
+    /// The `keyword_idents` lint detects edition keywords being used as an
+    /// identifier.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2015,compile_fail
+    /// #![deny(keyword_idents)]
+    /// // edition 2015
+    /// fn dyn() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Rust [editions] allow the language to evolve without breaking
+    /// backwards compatibility. This lint catches code that uses new keywords
+    /// that are added to the language that are used as identifiers (such as a
+    /// variable name, function name, etc.). If you switch the compiler to a
+    /// new edition without updating the code, then it will fail to compile if
+    /// you are using a new keyword as an identifier.
+    ///
+    /// You can manually change the identifiers to a non-keyword, or use a
+    /// [raw identifier], for example `r#dyn`, to transition to a new edition.
+    ///
+    /// This lint solves the problem automatically. It is "allow" by default
+    /// because the code is perfectly valid in older editions. The [`cargo
+    /// fix`] tool with the `--edition` flag will switch this lint to "warn"
+    /// and automatically apply the suggested fix from the compiler (which is
+    /// to use a raw identifier). This provides a completely automated way to
+    /// update old code for a new edition.
+    ///
+    /// [editions]: https://doc.rust-lang.org/edition-guide/
+    /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html
+    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
     pub KEYWORD_IDENTS,
     Allow,
     "detects edition keywords being used as an identifier",
@@ -1801,6 +2221,26 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements {
 }
 
 declare_lint! {
+    /// The `incomplete_features` lint detects unstable features enabled with
+    /// the [`feature` attribute] that may function improperly in some or all
+    /// cases.
+    ///
+    /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(generic_associated_types)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Although it is encouraged for people to experiment with unstable
+    /// features, some of them are known to be incomplete or faulty. This lint
+    /// is a signal that the feature has not yet been finished, and you may
+    /// experience problems with it.
     pub INCOMPLETE_FEATURES,
     Warn,
     "incomplete features that may function improperly in some or all cases"
@@ -1841,6 +2281,36 @@ impl EarlyLintPass for IncompleteFeatures {
 }
 
 declare_lint! {
+    /// The `invalid_value` lint detects creating a value that is not valid,
+    /// such as a NULL reference.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,no_run
+    /// # #![allow(unused)]
+    /// unsafe {
+    ///     let x: &'static i32 = std::mem::zeroed();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In some situations the compiler can detect that the code is creating
+    /// an invalid value, which should be avoided.
+    ///
+    /// In particular, this lint will check for improper use of
+    /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and
+    /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The
+    /// lint should provide extra information to indicate what the problem is
+    /// and a possible solution.
+    ///
+    /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html
+    /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html
+    /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html
+    /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
     pub INVALID_VALUE,
     Warn,
     "an invalid value is being created (such as a NULL reference)"
@@ -2072,6 +2542,40 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
 }
 
 declare_lint! {
+    /// The `clashing_extern_declarations` lint detects when an `extern fn`
+    /// has been declared with the same name but different types.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// mod m {
+    ///     extern "C" {
+    ///         fn foo();
+    ///     }
+    /// }
+    ///
+    /// extern "C" {
+    ///     fn foo(_: u32);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Because two symbols of the same name cannot be resolved to two
+    /// different functions at link time, and one function cannot possibly
+    /// have two types, a clashing extern declaration is almost certainly a
+    /// mistake. Check to make sure that the `extern` definitions are correct
+    /// and equivalent, and possibly consider unifying them in one location.
+    ///
+    /// This lint does not run between crates because a project may have
+    /// dependencies which both rely on the same extern function, but declare
+    /// it in a different (but valid) way. For example, they may both declare
+    /// an opaque type for one or more of the arguments (which would end up
+    /// distinct types), or use types that are valid conversions in the
+    /// language the `extern fn` is defined in. In these cases, the compiler
+    /// can't say that the clashing declaration is incorrect.
     pub CLASHING_EXTERN_DECLARATIONS,
     Warn,
     "detects when an extern fn has been declared with the same name but different types"
diff --git a/compiler/rustc_lint/src/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs
index 2f0b2a8d680..ecacdcde49f 100644
--- a/compiler/rustc_lint/src/non_ascii_idents.rs
+++ b/compiler/rustc_lint/src/non_ascii_idents.rs
@@ -4,6 +4,32 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_span::symbol::Symbol;
 
 declare_lint! {
+    /// The `non_ascii_idents` lint detects non-ASCII identifiers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// # #![allow(unused)]
+    /// #![feature(non_ascii_idents)]
+    /// #![deny(non_ascii_idents)]
+    /// fn main() {
+    ///     let föö = 1;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Currently on stable Rust, identifiers must contain ASCII characters.
+    /// The [`non_ascii_idents`] nightly-only feature allows identifiers to
+    /// contain non-ASCII characters. This lint allows projects that wish to
+    /// retain the limit of only using ASCII characters to switch this lint to
+    /// "forbid" (for example to ease collaboration or for security reasons).
+    /// See [RFC 2457] for more details.
+    ///
+    /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
+    /// [RFC 2457]: https://github.com/rust-lang/rfcs/blob/master/text/2457-non-ascii-idents.md
     pub NON_ASCII_IDENTS,
     Allow,
     "detects non-ASCII identifiers",
@@ -11,6 +37,37 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `uncommon_codepoints` lint detects uncommon Unicode codepoints in
+    /// identifiers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// #![feature(non_ascii_idents)]
+    /// const µ: f64 = 0.000001;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// With the [`non_ascii_idents`] nightly-only feature enabled,
+    /// identifiers are allowed to use non-ASCII characters. This lint warns
+    /// about using characters which are not commonly used, and may cause
+    /// visual confusion.
+    ///
+    /// This lint is triggered by identifiers that contain a codepoint that is
+    /// not part of the set of "Allowed" codepoints as described by [Unicode®
+    /// Technical Standard #39 Unicode Security Mechanisms Section 3.1 General
+    /// Security Profile for Identifiers][TR39Allowed].
+    ///
+    /// Note that the set of uncommon codepoints may change over time. Beware
+    /// that if you "forbid" this lint that existing code may fail in the
+    /// future.
+    ///
+    /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
+    /// [TR39Allowed]: https://www.unicode.org/reports/tr39/#General_Security_Profile
     pub UNCOMMON_CODEPOINTS,
     Warn,
     "detects uncommon Unicode codepoints in identifiers",
@@ -18,6 +75,43 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `confusable_idents` lint detects visually confusable pairs between
+    /// identifiers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(non_ascii_idents)]
+    ///
+    /// // Latin Capital Letter E With Caron
+    /// pub const Ě: i32 = 1;
+    /// // Latin Capital Letter E With Breve
+    /// pub const Ĕ: i32 = 2;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// With the [`non_ascii_idents`] nightly-only feature enabled,
+    /// identifiers are allowed to use non-ASCII characters. This lint warns
+    /// when different identifiers may appear visually similar, which can
+    /// cause confusion.
+    ///
+    /// The confusable detection algorithm is based on [Unicode® Technical
+    /// Standard #39 Unicode Security Mechanisms Section 4 Confusable
+    /// Detection][TR39Confusable]. For every distinct identifier X execute
+    /// the function `skeleton(X)`. If there exist two distinct identifiers X
+    /// and Y in the same crate where `skeleton(X) = skeleton(Y)` report it.
+    /// The compiler uses the same mechanism to check if an identifier is too
+    /// similar to a keyword.
+    ///
+    /// Note that the set of confusable characters may change over time.
+    /// Beware that if you "forbid" this lint that existing code may fail in
+    /// the future.
+    ///
+    /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
+    /// [TR39Confusable]: https://www.unicode.org/reports/tr39/#Confusable_Detection
     pub CONFUSABLE_IDENTS,
     Warn,
     "detects visually confusable pairs between identifiers",
@@ -25,6 +119,41 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `mixed_script_confusables` lint detects visually confusable
+    /// characters in identifiers between different [scripts].
+    ///
+    /// [scripts]: https://en.wikipedia.org/wiki/Script_(Unicode)
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(non_ascii_idents)]
+    ///
+    /// // The Japanese katakana character エ can be confused with the Han character 工.
+    /// const エ: &'static str = "アイウ";
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// With the [`non_ascii_idents`] nightly-only feature enabled,
+    /// identifiers are allowed to use non-ASCII characters. This lint warns
+    /// when characters between different scripts may appear visually similar,
+    /// which can cause confusion.
+    ///
+    /// If the crate contains other identifiers in the same script that have
+    /// non-confusable characters, then this lint will *not* be issued. For
+    /// example, if the example given above has another identifier with
+    /// katakana characters (such as `let カタカナ = 123;`), then this indicates
+    /// that you are intentionally using katakana, and it will not warn about
+    /// it.
+    ///
+    /// Note that the set of confusable characters may change over time.
+    /// Beware that if you "forbid" this lint that existing code may fail in
+    /// the future.
+    ///
+    /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html
     pub MIXED_SCRIPT_CONFUSABLES,
     Warn,
     "detects Unicode scripts whose mixed script confusables codepoints are solely used",
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index f23e8c5e208..24467f81172 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -31,6 +31,24 @@ pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext
 }
 
 declare_lint! {
+    /// The `non_camel_case_types` lint detects types, variants, traits and
+    /// type parameters that don't have camel case names.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// struct my_struct;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The preferred style for these identifiers is to use "camel case", such
+    /// as `MyStruct`, where the first letter should not be lowercase, and
+    /// should not use underscores between letters. Underscores are allowed at
+    /// the beginning and end of the identifier, as well as between
+    /// non-letters (such as `X86_64`).
     pub NON_CAMEL_CASE_TYPES,
     Warn,
     "types, variants, traits and type parameters should have camel case names"
@@ -161,6 +179,22 @@ impl EarlyLintPass for NonCamelCaseTypes {
 }
 
 declare_lint! {
+    /// The `non_snake_case` lint detects variables, methods, functions,
+    /// lifetime parameters and modules that don't have snake case names.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let MY_VALUE = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The preferred style for these identifiers is to use "snake case",
+    /// where all the characters are in lowercase, with words separated with a
+    /// single underscore, such as `my_value`.
     pub NON_SNAKE_CASE,
     Warn,
     "variables, methods, functions, lifetime parameters and modules should have snake case names"
@@ -379,6 +413,21 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
 }
 
 declare_lint! {
+    /// The `non_upper_case_globals` lint detects static items that don't have
+    /// uppercase identifiers.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// static max_points: i32 = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The preferred style is for static item names to use all uppercase
+    /// letters such as `MAX_POINTS`.
     pub NON_UPPER_CASE_GLOBALS,
     Warn,
     "static constants should have uppercase identifiers"
diff --git a/compiler/rustc_lint/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs
index d4aa4968f25..a31deb87ff0 100644
--- a/compiler/rustc_lint/src/redundant_semicolon.rs
+++ b/compiler/rustc_lint/src/redundant_semicolon.rs
@@ -4,6 +4,21 @@ use rustc_errors::Applicability;
 use rustc_span::Span;
 
 declare_lint! {
+    /// The `redundant_semicolons` lint detects unnecessary trailing
+    /// semicolons.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let _ = 123;;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Extra semicolons are not needed, and may be removed to avoid confusion
+    /// and visual clutter.
     pub REDUNDANT_SEMICOLONS,
     Warn,
     "detects unnecessary trailing semicolons"
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index af32c16bfe8..a202efa6eda 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -23,18 +23,82 @@ use std::cmp;
 use tracing::debug;
 
 declare_lint! {
+    /// The `unused_comparisons` lint detects comparisons made useless by
+    /// limits of the types involved.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn foo(x: u8) {
+    ///     x >= 0;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A useless comparison may indicate a mistake, and should be fixed or
+    /// removed.
     UNUSED_COMPARISONS,
     Warn,
     "comparisons made useless by limits of the types involved"
 }
 
 declare_lint! {
+    /// The `overflowing_literals` lint detects literal out of range for its
+    /// type.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// let x: u8 = 1000;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is usually a mistake to use a literal that overflows the type where
+    /// it is used. Either use a literal that is within range, or change the
+    /// type to be within the range of the literal.
     OVERFLOWING_LITERALS,
     Deny,
     "literal out of range for its type"
 }
 
 declare_lint! {
+    /// The `variant_size_differences` lint detects enums with widely varying
+    /// variant sizes.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(variant_size_differences)]
+    /// enum En {
+    ///     V0(u8),
+    ///     VBig([u8; 1024]),
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It can be a mistake to add a variant to an enum that is much larger
+    /// than the other variants, bloating the overall size required for all
+    /// variants. This can impact performance and memory usage. This is
+    /// triggered if one variant is more than 3 times larger than the
+    /// second-largest variant.
+    ///
+    /// Consider placing the large variant's contents on the heap (for example
+    /// via [`Box`]) to keep the overall size of the enum itself down.
+    ///
+    /// This lint is "allow" by default because it can be noisy, and may not be
+    /// an actual problem. Decisions about this should be guided with
+    /// profiling and benchmarking.
+    ///
+    /// [`Box`]: https://doc.rust-lang.org/std/boxed/index.html
     VARIANT_SIZE_DIFFERENCES,
     Allow,
     "detects enums with widely varying variant sizes"
@@ -495,6 +559,27 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits {
 }
 
 declare_lint! {
+    /// The `improper_ctypes` lint detects incorrect use of types in foreign
+    /// modules.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// extern "C" {
+    ///     static STATIC: String;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler has several checks to verify that types used in `extern`
+    /// blocks are safe and follow certain rules to ensure proper
+    /// compatibility with the foreign interfaces. This lint is issued when it
+    /// detects a probable mistake in a definition. The lint usually should
+    /// provide a description of the issue, along with possibly a hint on how
+    /// to resolve it.
     IMPROPER_CTYPES,
     Warn,
     "proper use of libc types in foreign modules"
@@ -503,6 +588,27 @@ declare_lint! {
 declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]);
 
 declare_lint! {
+    /// The `improper_ctypes_definitions` lint detects incorrect use of
+    /// [`extern` function] definitions.
+    ///
+    /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// pub extern "C" fn str_type(p: &str) { }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// There are many parameter and return types that may be specified in an
+    /// `extern` function that are not compatible with the given ABI. This
+    /// lint is an alert that these types should not be used. The lint usually
+    /// should provide a description of the issue, along with possibly a hint
+    /// on how to resolve it.
     IMPROPER_CTYPES_DEFINITIONS,
     Warn,
     "proper use of libc types in foreign item definitions"
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 0c06b063e41..1e8c30071e7 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -20,6 +20,29 @@ use rustc_span::{BytePos, Span, DUMMY_SP};
 use tracing::debug;
 
 declare_lint! {
+    /// The `unused_must_use` lint detects unused result of a type flagged as
+    /// `#[must_use]`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn returns_result() -> Result<(), ()> {
+    ///     Ok(())
+    /// }
+    ///
+    /// fn main() {
+    ///     returns_result();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The `#[must_use]` attribute is an indicator that it is a mistake to
+    /// ignore the value. See [the reference] for more details.
+    ///
+    /// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
     pub UNUSED_MUST_USE,
     Warn,
     "unused result of a type flagged as `#[must_use]`",
@@ -27,6 +50,39 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `unused_results` lint checks for the unused result of an
+    /// expression in a statement.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unused_results)]
+    /// fn foo<T>() -> T { panic!() }
+    ///
+    /// fn main() {
+    ///     foo::<usize>();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Ignoring the return value of a function may indicate a mistake. In
+    /// cases were it is almost certain that the result should be used, it is
+    /// recommended to annotate the function with the [`must_use` attribute].
+    /// Failure to use such a return value will trigger the [`unused_must_use`
+    /// lint] which is warn-by-default. The `unused_results` lint is
+    /// essentially the same, but triggers for *all* return values.
+    ///
+    /// This lint is "allow" by default because it can be noisy, and may not be
+    /// an actual problem. For example, calling the `remove` method of a `Vec`
+    /// or `HashMap` returns the previous value, which you may not care about.
+    /// Using this lint would require explicitly ignoring or discarding such
+    /// values.
+    ///
+    /// [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute
+    /// [`unused_must_use` lint]: warn-by-default.html#unused-must-use
     pub UNUSED_RESULTS,
     Allow,
     "unused result of an expression in a statement"
@@ -265,6 +321,21 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
 }
 
 declare_lint! {
+    /// The `path_statements` lint detects path statements with no effect.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 42;
+    ///
+    /// x;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is usually a mistake to have a statement that has no effect.
     pub PATH_STATEMENTS,
     Warn,
     "path statements with no effect"
@@ -635,6 +706,21 @@ trait UnusedDelimLint {
 }
 
 declare_lint! {
+    /// The `unused_parens` lint detects `if`, `match`, `while` and `return`
+    /// with parentheses; they do not need them.
+    ///
+    /// ### Examples
+    ///
+    /// ```rust
+    /// if(true) {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The parenthesis are not needed, and should be removed. This is the
+    /// preferred style for writing these expressions.
     pub(super) UNUSED_PARENS,
     Warn,
     "`if`, `match`, `while` and `return` do not need parentheses"
@@ -808,6 +894,23 @@ impl EarlyLintPass for UnusedParens {
 }
 
 declare_lint! {
+    /// The `unused_braces` lint detects unnecessary braces around an
+    /// expression.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// if { true } {
+    ///     // ...
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The braces are not needed, and should be removed. This is the
+    /// preferred style for writing these expressions.
     pub(super) UNUSED_BRACES,
     Warn,
     "unnecessary braces around an expression"
@@ -929,6 +1032,30 @@ impl EarlyLintPass for UnusedBraces {
 }
 
 declare_lint! {
+    /// The `unused_import_braces` lint catches unnecessary braces around an
+    /// imported item.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unused_import_braces)]
+    /// use test::{A};
+    ///
+    /// pub mod test {
+    ///     pub struct A;
+    /// }
+    /// # fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// If there is only a single item, then remove the braces (`use test::A;`
+    /// for example).
+    ///
+    /// This lint is "allow" by default because it is only enforcing a
+    /// stylistic choice.
     UNUSED_IMPORT_BRACES,
     Allow,
     "unnecessary braces around an imported item"
@@ -978,6 +1105,25 @@ impl EarlyLintPass for UnusedImportBraces {
 }
 
 declare_lint! {
+    /// The `unused_allocation` lint detects unnecessary allocations that can
+    /// be eliminated.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(box_syntax)]
+    /// fn main() {
+    ///     let a = (box [1,2,3]).len();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When a `box` expression is immediately coerced to a reference, then
+    /// the allocation is unnecessary, and a reference (using `&` or `&mut`)
+    /// should be used instead to avoid the allocation.
     pub(super) UNUSED_ALLOCATION,
     Warn,
     "detects unnecessary allocations that can be eliminated"
diff --git a/compiler/rustc_session/src/lint.rs b/compiler/rustc_session/src/lint.rs
index 0dcbee08abe..4a3e59f18e5 100644
--- a/compiler/rustc_session/src/lint.rs
+++ b/compiler/rustc_session/src/lint.rs
@@ -65,9 +65,15 @@ pub struct Lint {
     ///
     /// The name is written with underscores, e.g., "unused_imports".
     /// On the command line, underscores become dashes.
+    ///
+    /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming
+    /// for naming guidelines.
     pub name: &'static str,
 
     /// Default level for the lint.
+    ///
+    /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels
+    /// for guidelines on choosing a default level.
     pub default_level: Level,
 
     /// Description of the lint or the issue it detects.
@@ -275,17 +281,58 @@ impl LintBuffer {
 }
 
 /// Declares a static item of type `&'static Lint`.
+///
+/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html for documentation
+/// and guidelines on writing lints.
+///
+/// The macro call should start with a doc comment explaining the lint
+/// which will be embedded in the rustc user documentation book. It should
+/// be written in markdown and have a format that looks like this:
+///
+/// ```rust,ignore (doc-example)
+/// /// The `my_lint_name` lint detects [short explanation here].
+/// ///
+/// /// ### Example
+/// ///
+/// /// ```rust
+/// /// [insert a concise example that triggers the lint]
+/// /// ```
+/// ///
+/// /// {{produces}}
+/// ///
+/// /// ### Explanation
+/// ///
+/// /// This should be a detailed explanation of *why* the lint exists,
+/// /// and also include suggestions on how the user should fix the problem.
+/// /// Try to keep the text simple enough that a beginner can understand,
+/// /// and include links to other documentation for terminology that a
+/// /// beginner may not be familiar with. If this is "allow" by default,
+/// /// it should explain why (are there false positives or other issues?). If
+/// /// this is a future-incompatible lint, it should say so, with text that
+/// /// looks roughly like this:
+/// ///
+/// /// This is a [future-incompatible] lint to transition this to a hard
+/// /// error in the future. See [issue #xxxxx] for more details.
+/// ///
+/// /// [issue #xxxxx]: https://github.com/rust-lang/rust/issues/xxxxx
+/// ```
+///
+/// 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` (use --stage=0 if just
+/// changing the wording of an existing lint).
 #[macro_export]
 macro_rules! declare_lint {
-    ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
+    ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
         $crate::declare_lint!(
-            $vis $NAME, $Level, $desc,
+            $(#[$attr])* $vis $NAME, $Level, $desc,
         );
     );
-    ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
+    ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
      $(@future_incompatible = $fi:expr;)?
      $(@feature_gate = $gate:expr;)?
      $($v:ident),*) => (
+        $(#[$attr])*
         $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
             name: stringify!($NAME),
             default_level: $crate::lint::$Level,
@@ -298,9 +345,10 @@ macro_rules! declare_lint {
             ..$crate::lint::Lint::default_fields_for_macro()
         };
     );
-    ($vis: vis $NAME: ident, $Level: ident, $desc: expr,
+    ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr,
      $lint_edition: expr => $edition_level: ident
     ) => (
+        $(#[$attr])*
         $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
             name: stringify!($NAME),
             default_level: $crate::lint::$Level,
diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs
index 0fd6cc10382..4c0c7fae29b 100644
--- a/compiler/rustc_session/src/lint/builtin.rs
+++ b/compiler/rustc_session/src/lint/builtin.rs
@@ -10,6 +10,32 @@ use rustc_span::edition::Edition;
 use rustc_span::symbol::sym;
 
 declare_lint! {
+    /// The `ill_formed_attribute_input` lint detects ill-formed attribute
+    /// inputs that were previously accepted and used in practice.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #[inline = "this is not valid"]
+    /// fn foo() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Previously, inputs for many built-in attributes weren't validated and
+    /// nonsensical attribute inputs were accepted. After validation was
+    /// added, it was determined that some existing projects made use of these
+    /// invalid forms. This is a [future-incompatible] lint to transition this
+    /// to a hard error in the future. See [issue #57571] for more details.
+    ///
+    /// Check the [attribute reference] for details on the valid inputs for
+    /// attributes.
+    ///
+    /// [issue #57571]: https://github.com/rust-lang/rust/issues/57571
+    /// [attribute reference]: https://doc.rust-lang.org/nightly/reference/attributes.html
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub ILL_FORMED_ATTRIBUTE_INPUT,
     Deny,
     "ill-formed attribute inputs that were previously accepted and used in practice",
@@ -21,6 +47,32 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `conflicting_repr_hints` lint detects [`repr` attributes] with
+    /// conflicting hints.
+    ///
+    /// [`repr` attributes]: https://doc.rust-lang.org/reference/type-layout.html#representations
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #[repr(u32, u64)]
+    /// enum Foo {
+    ///     Variant1,
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler incorrectly accepted these conflicting representations in
+    /// the past. This is a [future-incompatible] lint to transition this to a
+    /// hard error in the future. See [issue #68585] for more details.
+    ///
+    /// To correct the issue, remove one of the conflicting hints.
+    ///
+    /// [issue #68585]: https://github.com/rust-lang/rust/issues/68585
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub CONFLICTING_REPR_HINTS,
     Deny,
     "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice",
@@ -31,30 +83,198 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `meta_variable_misuse` lint detects possible meta-variable misuse
+    /// in macro definitions.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(meta_variable_misuse)]
+    ///
+    /// macro_rules! foo {
+    ///     () => {};
+    ///     ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* };
+    /// }
+    ///
+    /// fn main() {
+    ///     foo!();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// There are quite a few different ways a [`macro_rules`] macro can be
+    /// improperly defined. Many of these errors were previously only detected
+    /// when the macro was expanded or not at all. This lint is an attempt to
+    /// catch some of these problems when the macro is *defined*.
+    ///
+    /// This lint is "allow" by default because it may have false positives
+    /// and other issues. See [issue #61053] for more details.
+    ///
+    /// [`macro_rules`]: https://doc.rust-lang.org/reference/macros-by-example.html
+    /// [issue #61053]: https://github.com/rust-lang/rust/issues/61053
     pub META_VARIABLE_MISUSE,
     Allow,
     "possible meta-variable misuse at macro definition"
 }
 
 declare_lint! {
+    /// The `incomplete_include` lint detects the use of the [`include!`]
+    /// macro with a file that contains more than one expression.
+    ///
+    /// [`include!`]: https://doc.rust-lang.org/std/macro.include.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// fn main() {
+    ///     include!("foo.txt");
+    /// }
+    /// ```
+    ///
+    /// where the file `foo.txt` contains:
+    ///
+    /// ```text
+    /// println!("hi!");
+    /// ```
+    ///
+    /// produces:
+    ///
+    /// ```text
+    /// error: include macro expected single expression in source
+    ///  --> foo.txt:1:14
+    ///   |
+    /// 1 | println!("1");
+    ///   |              ^
+    ///   |
+    ///   = note: `#[deny(incomplete_include)]` on by default
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// The [`include!`] macro is currently only intended to be used to
+    /// include a single [expression] or multiple [items]. Historically it
+    /// would ignore any contents after the first expression, but that can be
+    /// confusing. In the example above, the `println!` expression ends just
+    /// before the semicolon, making the semicolon "extra" information that is
+    /// ignored. Perhaps even more surprising, if the included file had
+    /// multiple print statements, the subsequent ones would be ignored!
+    ///
+    /// One workaround is to place the contents in braces to create a [block
+    /// expression]. Also consider alternatives, like using functions to
+    /// encapsulate the expressions, or use [proc-macros].
+    ///
+    /// This is a lint instead of a hard error because existing projects were
+    /// found to hit this error. To be cautious, it is a lint for now. The
+    /// future semantics of the `include!` macro are also uncertain, see
+    /// [issue #35560].
+    ///
+    /// [items]: https://doc.rust-lang.org/reference/items.html
+    /// [expression]: https://doc.rust-lang.org/reference/expressions.html
+    /// [block expression]: https://doc.rust-lang.org/reference/expressions/block-expr.html
+    /// [proc-macros]: https://doc.rust-lang.org/reference/procedural-macros.html
+    /// [issue #35560]: https://github.com/rust-lang/rust/issues/35560
     pub INCOMPLETE_INCLUDE,
     Deny,
     "trailing content in included file"
 }
 
 declare_lint! {
+    /// The `arithmetic_overflow` lint detects that an arithmetic operation
+    /// will [overflow].
+    ///
+    /// [overflow]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// 1_i32 << 32;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is very likely a mistake to perform an arithmetic operation that
+    /// overflows its value. If the compiler is able to detect these kinds of
+    /// overflows at compile-time, it will trigger this lint. Consider
+    /// adjusting the expression to avoid overflow, or use a data type that
+    /// will not overflow.
     pub ARITHMETIC_OVERFLOW,
     Deny,
     "arithmetic operation overflows"
 }
 
 declare_lint! {
+    /// The `unconditional_panic` lint detects an operation that will cause a
+    /// panic at runtime.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// # #![allow(unused)]
+    /// let x = 1 / 0;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint detects code that is very likely incorrect. When possible,
+    /// the compiler will attempt to detect situations where code can be
+    /// evaluated at compile-time to generate more efficient code. While
+    /// evaluating such code, if it detects that the code will unconditionally
+    /// panic, this usually indicates that it is doing something incorrectly.
+    /// If this lint is allowed, then the code will not be evaluated at
+    /// compile-time, and instead continue to generate code to evaluate at
+    /// runtime, which may panic during runtime.
     pub UNCONDITIONAL_PANIC,
     Deny,
     "operation will cause a panic at runtime"
 }
 
 declare_lint! {
+    /// The `const_err` lint detects an erroneous expression while doing
+    /// constant evaluation.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![allow(unconditional_panic)]
+    /// let x: &'static i32 = &(1 / 0);
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint detects code that is very likely incorrect. If this lint is
+    /// allowed, then the code will not be evaluated at compile-time, and
+    /// instead continue to generate code to evaluate at runtime, which may
+    /// panic during runtime.
+    ///
+    /// Note that this lint may trigger in either inside or outside of a
+    /// [const context]. Outside of a [const context], the compiler can
+    /// sometimes evaluate an expression at compile-time in order to generate
+    /// more efficient code. As the compiler becomes better at doing this, it
+    /// needs to decide what to do when it encounters code that it knows for
+    /// certain will panic or is otherwise incorrect. Making this a hard error
+    /// would prevent existing code that exhibited this behavior from
+    /// compiling, breaking backwards-compatibility. However, this is almost
+    /// certainly incorrect code, so this is a deny-by-default lint. For more
+    /// details, see [RFC 1229] and [issue #28238].
+    ///
+    /// Note that there are several other more specific lints associated with
+    /// compile-time evaluation, such as [`arithmetic_overflow`],
+    /// [`unconditional_panic`].
+    ///
+    /// [const context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
+    /// [RFC 1229]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md
+    /// [issue #28238]: https://github.com/rust-lang/rust/issues/28238
+    /// [`arithmetic_overflow`]: deny-by-default.html#arithmetic-overflow
+    /// [`unconditional_panic`]: deny-by-default.html#unconditional-panic
     pub CONST_ERR,
     Deny,
     "constant evaluation detected erroneous expression",
@@ -62,18 +282,105 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `unused_imports` lint detects imports that are never used.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// use std::collections::HashMap;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused imports may signal a mistake or unfinished code, and clutter
+    /// the code, and should be removed. If you intended to re-export the item
+    /// to make it available outside of the module, add a visibility modifier
+    /// like `pub`.
     pub UNUSED_IMPORTS,
     Warn,
     "imports that are never used"
 }
 
 declare_lint! {
+    /// The `unused_extern_crates` lint guards against `extern crate` items
+    /// that are never used.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unused_extern_crates)]
+    /// extern crate proc_macro;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// `extern crate` items that are unused have no effect and should be
+    /// removed. Note that there are some cases where specifying an `extern
+    /// crate` is desired for the side effect of ensuring the given crate is
+    /// linked, even though it is not otherwise directly referenced. The lint
+    /// can be silenced by aliasing the crate to an underscore, such as
+    /// `extern crate foo as _`. Also note that it is no longer idiomatic to
+    /// use `extern crate` in the [2018 edition], as extern crates are now
+    /// automatically added in scope.
+    ///
+    /// This lint is "allow" by default because it can be noisy, and produce
+    /// false-positives. If a dependency is being removed from a project, it
+    /// is recommended to remove it from the build configuration (such as
+    /// `Cargo.toml`) to ensure stale build entries aren't left behind.
+    ///
+    /// [2018 edition]: https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html#no-more-extern-crate
     pub UNUSED_EXTERN_CRATES,
     Allow,
     "extern crates that are never used"
 }
 
 declare_lint! {
+    /// The `unused_crate_dependencies` lint detects crate dependencies that
+    /// are never used.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unused_crate_dependencies)]
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// error: external crate `regex` unused in `lint_example`: remove the dependency or add `use regex as _;`
+    ///   |
+    /// note: the lint level is defined here
+    ///  --> src/lib.rs:1:9
+    ///   |
+    /// 1 | #![deny(unused_crate_dependencies)]
+    ///   |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// After removing the code that uses a dependency, this usually also
+    /// requires removing the dependency from the build configuration.
+    /// However, sometimes that step can be missed, which leads to time wasted
+    /// building dependencies that are no longer used. This lint can be
+    /// enabled to detect dependencies that are never used (more specifically,
+    /// any dependency passed with the `--extern` command-line flag that is
+    /// never referenced via [`use`], [`extern crate`], or in any [path]).
+    ///
+    /// This lint is "allow" by default because it can provide false positives
+    /// depending on how the build system is configured. For example, when
+    /// using Cargo, a "package" consists of multiple crates (such as a
+    /// library and a binary), but the dependencies are defined for the
+    /// package as a whole. If there is a dependency that is only used in the
+    /// binary, but not the library, then the lint will be incorrectly issued
+    /// in the library.
+    ///
+    /// [path]: https://doc.rust-lang.org/reference/paths.html
+    /// [`use`]: https://doc.rust-lang.org/reference/items/use-declarations.html
+    /// [`extern crate`]: https://doc.rust-lang.org/reference/items/extern-crates.html
     pub UNUSED_CRATE_DEPENDENCIES,
     Allow,
     "crate dependencies that are never used",
@@ -81,42 +388,174 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `unused_qualifications` lint detects unnecessarily qualified
+    /// names.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unused_qualifications)]
+    /// mod foo {
+    ///     pub fn bar() {}
+    /// }
+    ///
+    /// fn main() {
+    ///     use foo::bar;
+    ///     foo::bar();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// If an item from another module is already brought into scope, then
+    /// there is no need to qualify it in this case. You can call `bar()`
+    /// directly, without the `foo::`.
+    ///
+    /// This lint is "allow" by default because it is somewhat pedantic, and
+    /// doesn't indicate an actual problem, but rather a stylistic choice, and
+    /// can be noisy when refactoring or moving around code.
     pub UNUSED_QUALIFICATIONS,
     Allow,
     "detects unnecessarily qualified names"
 }
 
 declare_lint! {
+    /// The `unknown_lints` lint detects unrecognized lint attribute.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![allow(not_a_real_lint)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is usually a mistake to specify a lint that does not exist. Check
+    /// the spelling, and check the lint listing for the correct name. Also
+    /// consider if you are using an old version of the compiler, and the lint
+    /// is only available in a newer version.
     pub UNKNOWN_LINTS,
     Warn,
     "unrecognized lint attribute"
 }
 
 declare_lint! {
+    /// The `unused_variables` lint detects variables which are not used in
+    /// any way.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused variables may signal a mistake or unfinished code. To silence
+    /// the warning for the individual variable, prefix it with an underscore
+    /// such as `_x`.
     pub UNUSED_VARIABLES,
     Warn,
     "detect variables which are not used in any way"
 }
 
 declare_lint! {
+    /// The `unused_assignments` lint detects assignments that will never be read.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let mut x = 5;
+    /// x = 6;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused assignments may signal a mistake or unfinished code. If the
+    /// variable is never used after being assigned, then the assignment can
+    /// be removed. Variables with an underscore prefix such as `_x` will not
+    /// trigger this lint.
     pub UNUSED_ASSIGNMENTS,
     Warn,
     "detect assignments that will never be read"
 }
 
 declare_lint! {
+    /// The `dead_code` lint detects unused, unexported items.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn foo() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Dead code may signal a mistake or unfinished code. To silence the
+    /// warning for individual items, prefix the name with an underscore such
+    /// as `_foo`. If it was intended to expose the item outside of the crate,
+    /// consider adding a visibility modifier like `pub`. Otherwise consider
+    /// removing the unused code.
     pub DEAD_CODE,
     Warn,
     "detect unused, unexported items"
 }
 
 declare_lint! {
+    /// The `unused_attributes` lint detects attributes that were not used by
+    /// the compiler.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![macro_export]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused [attributes] may indicate the attribute is placed in the wrong
+    /// position. Consider removing it, or placing it in the correct position.
+    /// Also consider if you intended to use an _inner attribute_ (with a `!`
+    /// such as `#![allow(unused)]`) which applies to the item the attribute
+    /// is within, or an _outer attribute_ (without a `!` such as
+    /// `#[allow(unsued)]`) which applies to the item *following* the
+    /// attribute.
+    ///
+    /// [attributes]: https://doc.rust-lang.org/reference/attributes.html
     pub UNUSED_ATTRIBUTES,
     Warn,
     "detects attributes that were not used by the compiler"
 }
 
 declare_lint! {
+    /// The `unreachable_code` lint detects unreachable code paths.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,no_run
+    /// panic!("we never go past here!");
+    ///
+    /// let x = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unreachable code may signal a mistake or unfinished code. If the code
+    /// is no longer in use, consider removing it.
     pub UNREACHABLE_CODE,
     Warn,
     "detects unreachable code paths",
@@ -124,48 +563,217 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `unreachable_patterns` lint detects unreachable patterns.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 5;
+    /// match x {
+    ///     y => (),
+    ///     5 => (),
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This usually indicates a mistake in how the patterns are specified or
+    /// ordered. In this example, the `y` pattern will always match, so the
+    /// five is impossible to reach. Remember, match arms match in order, you
+    /// probably wanted to put the `5` case above the `y` case.
     pub UNREACHABLE_PATTERNS,
     Warn,
     "detects unreachable patterns"
 }
 
 declare_lint! {
+    /// The `overlapping_patterns` lint detects `match` arms that have
+    /// [range patterns] that overlap.
+    ///
+    /// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 123u8;
+    /// match x {
+    ///     0..=100 => { println!("small"); }
+    ///     100..=255 => { println!("large"); }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is likely a mistake to have range patterns in a match expression
+    /// that overlap. Check that the beginning and end values are what you
+    /// expect, and keep in mind that with `..=` the left and right bounds are
+    /// inclusive.
     pub OVERLAPPING_PATTERNS,
     Warn,
     "detects overlapping patterns"
 }
 
 declare_lint! {
+    /// The `bindings_with_variant_name` lint detects pattern bindings with
+    /// the same name as one of the matched variants.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// pub enum Enum {
+    ///     Foo,
+    ///     Bar,
+    /// }
+    ///
+    /// pub fn foo(x: Enum) {
+    ///     match x {
+    ///         Foo => {}
+    ///         Bar => {}
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is usually a mistake to specify an enum variant name as an
+    /// [identifier pattern]. In the example above, the `match` arms are
+    /// specifying a variable name to bind the value of `x` to. The second arm
+    /// is ignored because the first one matches *all* values. The likely
+    /// intent is that the arm was intended to match on the enum variant.
+    ///
+    /// Two possible solutions are:
+    ///
+    /// * Specify the enum variant using a [path pattern], such as
+    ///   `Enum::Foo`.
+    /// * Bring the enum variants into local scope, such as adding `use
+    ///   Enum::*;` to the beginning of the `foo` function in the example
+    ///   above.
+    ///
+    /// [identifier pattern]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns
+    /// [path pattern]: https://doc.rust-lang.org/reference/patterns.html#path-patterns
     pub BINDINGS_WITH_VARIANT_NAME,
     Warn,
     "detects pattern bindings with the same name as one of the matched variants"
 }
 
 declare_lint! {
+    /// The `unused_macros` lint detects macros that were not used.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// macro_rules! unused {
+    ///     () => {};
+    /// }
+    ///
+    /// fn main() {
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused macros may signal a mistake or unfinished code. To silence the
+    /// warning for the individual macro, prefix the name with an underscore
+    /// such as `_my_macro`. If you intended to export the macro to make it
+    /// available outside of the crate, use the [`macro_export` attribute].
+    ///
+    /// [`macro_export` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope
     pub UNUSED_MACROS,
     Warn,
     "detects macros that were not used"
 }
 
 declare_lint! {
+    /// The `warnings` lint allows you to change the level of other
+    /// lints which produce warnings.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![deny(warnings)]
+    /// fn foo() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The `warnings` lint is a bit special; by changing its level, you
+    /// change every other warning that would produce a warning to whatever
+    /// value you'd like. As such, you won't ever trigger this lint in your
+    /// code directly.
     pub WARNINGS,
     Warn,
     "mass-change the level for lints which produce warnings"
 }
 
 declare_lint! {
+    /// The `unused_features` lint detects unused or unknown features found in
+    /// crate-level [`feature` attributes].
+    ///
+    /// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/
+    ///
+    /// Note: This lint is currently not functional, see [issue #44232] for
+    /// more details.
+    ///
+    /// [issue #44232]: https://github.com/rust-lang/rust/issues/44232
     pub UNUSED_FEATURES,
     Warn,
     "unused features found in crate-level `#[feature]` directives"
 }
 
 declare_lint! {
+    /// The `stable_features` lint detects a [`feature` attribute] that
+    /// has since been made stable.
+    ///
+    /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(test_accepted_feature)]
+    /// fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When a feature is stabilized, it is no longer necessary to include a
+    /// `#![feature]` attribute for it. To fix, simply remove the
+    /// `#![feature]` attribute.
     pub STABLE_FEATURES,
     Warn,
     "stable features found in `#[feature]` directive"
 }
 
 declare_lint! {
+    /// The `unknown_crate_types` lint detects an unknown crate type found in
+    /// a [`crate_type` attribute].
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![crate_type="lol"]
+    /// fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// An unknown value give to the `crate_type` attribute is almost
+    /// certainly a mistake.
+    ///
+    /// [`crate_type` attribute]: https://doc.rust-lang.org/reference/linkage.html
     pub UNKNOWN_CRATE_TYPES,
     Deny,
     "unknown crate type found in `#[crate_type]` directive",
@@ -173,18 +781,104 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `trivial_casts` lint detects trivial casts which could be replaced
+    /// with coercion, which may require [type ascription] or a temporary
+    /// variable.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(trivial_casts)]
+    /// let x: &u32 = &42;
+    /// let y = x as *const u32;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A trivial cast is a cast `e as T` where `e` has type `U` and `U` is a
+    /// subtype of `T`. This type of cast is usually unnecessary, as it can be
+    /// usually be inferred.
+    ///
+    /// This lint is "allow" by default because there are situations, such as
+    /// with FFI interfaces or complex type aliases, where it triggers
+    /// incorrectly, or in situations where it will be more difficult to
+    /// clearly express the intent. It may be possible that this will become a
+    /// warning in the future, possibly with [type ascription] providing a
+    /// convenient way to work around the current issues. See [RFC 401] for
+    /// historical context.
+    ///
+    /// [type ascription]: https://github.com/rust-lang/rust/issues/23416
+    /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
     pub TRIVIAL_CASTS,
     Allow,
     "detects trivial casts which could be removed"
 }
 
 declare_lint! {
+    /// The `trivial_numeric_casts` lint detects trivial numeric casts of types
+    /// which could be removed.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(trivial_numeric_casts)]
+    /// let x = 42_i32 as i32;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A trivial numeric cast is a cast of a numeric type to the same numeric
+    /// type. This type of cast is usually unnecessary.
+    ///
+    /// This lint is "allow" by default because there are situations, such as
+    /// with FFI interfaces or complex type aliases, where it triggers
+    /// incorrectly, or in situations where it will be more difficult to
+    /// clearly express the intent. It may be possible that this will become a
+    /// warning in the future, possibly with [type ascription] providing a
+    /// convenient way to work around the current issues. See [RFC 401] for
+    /// historical context.
+    ///
+    /// [type ascription]: https://github.com/rust-lang/rust/issues/23416
+    /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md
     pub TRIVIAL_NUMERIC_CASTS,
     Allow,
     "detects trivial casts of numeric types which could be removed"
 }
 
 declare_lint! {
+    /// The `private_in_public` lint detects private items in public
+    /// interfaces not caught by the old implementation.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// struct SemiPriv;
+    ///
+    /// mod m1 {
+    ///     struct Priv;
+    ///     impl super::SemiPriv {
+    ///         pub fn f(_: Priv) {}
+    ///     }
+    /// }
+    /// # fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The visibility rules are intended to prevent exposing private items in
+    /// public interfaces. This is a [future-incompatible] lint to transition
+    /// this to a hard error in the future. See [issue #34537] for more
+    /// details.
+    ///
+    /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PRIVATE_IN_PUBLIC,
     Warn,
     "detect private items in public interfaces not caught by the old implementation",
@@ -195,12 +889,76 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `exported_private_dependencies` lint detects private dependencies
+    /// that are exposed in a public interface.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs-dependency)
+    /// pub fn foo() -> Option<some_private_dependency::Thing> {
+    ///     None
+    /// }
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: type `bar::Thing` from private dependency 'bar' in public interface
+    ///  --> src/lib.rs:3:1
+    ///   |
+    /// 3 | pub fn foo() -> Option<bar::Thing> {
+    ///   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    ///   |
+    ///   = note: `#[warn(exported_private_dependencies)]` on by default
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Dependencies can be marked as "private" to indicate that they are not
+    /// exposed in the public interface of a crate. This can be used by Cargo
+    /// to independently resolve those dependencies because it can assume it
+    /// does not need to unify them with other packages using that same
+    /// dependency. This lint is an indication of a violation of that
+    /// contract.
+    ///
+    /// To fix this, avoid exposing the dependency in your public interface.
+    /// Or, switch the dependency to a public dependency.
+    ///
+    /// Note that support for this is only available on the nightly channel.
+    /// See [RFC 1977] for more details, as well as the [Cargo documentation].
+    ///
+    /// [RFC 1977]: https://github.com/rust-lang/rfcs/blob/master/text/1977-public-private-dependencies.md
+    /// [Cargo documentation]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#public-dependency
     pub EXPORTED_PRIVATE_DEPENDENCIES,
     Warn,
     "public interface leaks type from a private dependency"
 }
 
 declare_lint! {
+    /// The `pub_use_of_private_extern_crate` lint detects a specific
+    /// situation of re-exporting a private `extern crate`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// extern crate core;
+    /// pub use core as reexported_core;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A public `use` declaration should not be used to publicly re-export a
+    /// private `extern crate`. `pub extern crate` should be used instead.
+    ///
+    /// This was historically allowed, but is not the intended behavior
+    /// according to the visibility rules. This is a [future-incompatible]
+    /// lint to transition this to a hard error in the future. See [issue
+    /// #34537] for more details.
+    ///
+    /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PUB_USE_OF_PRIVATE_EXTERN_CRATE,
     Deny,
     "detect public re-exports of private extern crates",
@@ -211,6 +969,26 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `invalid_type_param_default` lint detects type parameter defaults
+    /// erroneously allowed in an invalid location.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// fn foo<T=i32>(t: T) {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Default type parameters were only intended to be allowed in certain
+    /// situations, but historically the compiler allowed them everywhere.
+    /// This is a [future-incompatible] lint to transition this to a hard
+    /// error in the future. See [issue #36887] for more details.
+    ///
+    /// [issue #36887]: https://github.com/rust-lang/rust/issues/36887
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub INVALID_TYPE_PARAM_DEFAULT,
     Deny,
     "type parameter default erroneously allowed in invalid location",
@@ -221,24 +999,174 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `renamed_and_removed_lints` lint detects lints that have been
+    /// renamed or removed.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![deny(raw_pointer_derive)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// To fix this, either remove the lint or use the new name. This can help
+    /// avoid confusion about lints that are no longer valid, and help
+    /// maintain consistency for renamed lints.
     pub RENAMED_AND_REMOVED_LINTS,
     Warn,
     "lints that have been renamed or removed"
 }
 
 declare_lint! {
+    /// The `unaligned_references` lint detects unaligned references to fields
+    /// of [packed] structs.
+    ///
+    /// [packed]: https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(unaligned_references)]
+    ///
+    /// #[repr(packed)]
+    /// pub struct Foo {
+    ///     field1: u64,
+    ///     field2: u8,
+    /// }
+    ///
+    /// fn main() {
+    ///     unsafe {
+    ///         let foo = Foo { field1: 0, field2: 0 };
+    ///         let _ = &foo.field1;
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Creating a reference to an insufficiently aligned packed field is
+    /// [undefined behavior] and should be disallowed.
+    ///
+    /// This lint is "allow" by default because there is no stable
+    /// alternative, and it is not yet certain how widespread existing code
+    /// will trigger this lint.
+    ///
+    /// See [issue #27060] for more discussion.
+    ///
+    /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+    /// [issue #27060]: https://github.com/rust-lang/rust/issues/27060
     pub UNALIGNED_REFERENCES,
     Allow,
     "detects unaligned references to fields of packed structs",
 }
 
 declare_lint! {
+    /// The `const_item_mutation` lint detects attempts to mutate a `const`
+    /// item.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// const FOO: [i32; 1] = [0];
+    ///
+    /// fn main() {
+    ///     FOO[0] = 1;
+    ///     // This will print "[0]".
+    ///     println!("{:?}", FOO);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Trying to directly mutate a `const` item is almost always a mistake.
+    /// What is happening in the example above is that a temporary copy of the
+    /// `const` is mutated, but the original `const` is not. Each time you
+    /// refer to the `const` by name (such as `FOO` in the example above), a
+    /// separate copy of the value is inlined at that location.
+    ///
+    /// This lint checks for writing directly to a field (`FOO.field =
+    /// some_value`) or array entry (`FOO[0] = val`), or taking a mutable
+    /// reference to the const item (`&mut FOO`), including through an
+    /// autoderef (`FOO.some_mut_self_method()`).
+    ///
+    /// There are various alternatives depending on what you are trying to
+    /// accomplish:
+    ///
+    /// * First, always reconsider using mutable globals, as they can be
+    ///   difficult to use correctly, and can make the code more difficult to
+    ///   use or understand.
+    /// * If you are trying to perform a one-time initialization of a global:
+    ///     * If the value can be computed at compile-time, consider using
+    ///       const-compatible values (see [Constant Evaluation]).
+    ///     * For more complex single-initialization cases, consider using a
+    ///       third-party crate, such as [`lazy_static`] or [`once_cell`].
+    ///     * If you are using the [nightly channel], consider the new
+    ///       [`lazy`] module in the standard library.
+    /// * If you truly need a mutable global, consider using a [`static`],
+    ///   which has a variety of options:
+    ///   * Simple data types can be directly defined and mutated with an
+    ///     [`atomic`] type.
+    ///   * More complex types can be placed in a synchronization primitive
+    ///     like a [`Mutex`], which can be initialized with one of the options
+    ///     listed above.
+    ///   * A [mutable `static`] is a low-level primitive, requiring unsafe.
+    ///     Typically This should be avoided in preference of something
+    ///     higher-level like one of the above.
+    ///
+    /// [Constant Evaluation]: https://doc.rust-lang.org/reference/const_eval.html
+    /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html
+    /// [mutable `static`]: https://doc.rust-lang.org/reference/items/static-items.html#mutable-statics
+    /// [`lazy`]: https://doc.rust-lang.org/nightly/std/lazy/index.html
+    /// [`lazy_static`]: https://crates.io/crates/lazy_static
+    /// [`once_cell`]: https://crates.io/crates/once_cell
+    /// [`atomic`]: https://doc.rust-lang.org/std/sync/atomic/index.html
+    /// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
     pub CONST_ITEM_MUTATION,
     Warn,
     "detects attempts to mutate a `const` item",
 }
 
 declare_lint! {
+    /// The `safe_packed_borrows` lint detects borrowing a field in the
+    /// interior of a packed structure with alignment other than 1.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #[repr(packed)]
+    /// pub struct Unaligned<T>(pub T);
+    ///
+    /// pub struct Foo {
+    ///     start: u8,
+    ///     data: Unaligned<u32>,
+    /// }
+    ///
+    /// fn main() {
+    ///     let x = Foo { start: 0, data: Unaligned(1) };
+    ///     let y = &x.data.0;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This type of borrow is unsafe and can cause errors on some platforms
+    /// and violates some assumptions made by the compiler. This was
+    /// previously allowed unintentionally. This is a [future-incompatible]
+    /// lint to transition this to a hard error in the future. See [issue
+    /// #46043] for more details, including guidance on how to solve the
+    /// problem.
+    ///
+    /// [issue #46043]: https://github.com/rust-lang/rust/issues/46043
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub SAFE_PACKED_BORROWS,
     Warn,
     "safe borrows of fields of packed structs were erroneously allowed",
@@ -249,6 +1177,49 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `patterns_in_fns_without_body` lint detects `mut` identifier
+    /// patterns as a parameter in functions without a body.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// trait Trait {
+    ///     fn foo(mut arg: u8);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// To fix this, remove `mut` from the parameter in the trait definition;
+    /// it can be used in the implementation. That is, the following is OK:
+    ///
+    /// ```rust
+    /// trait Trait {
+    ///     fn foo(arg: u8); // Removed `mut` here
+    /// }
+    ///
+    /// impl Trait for i32 {
+    ///     fn foo(mut arg: u8) { // `mut` here is OK
+    ///
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// Trait definitions can define functions without a body to specify a
+    /// function that implementors must define. The parameter names in the
+    /// body-less functions are only allowed to be `_` or an [identifier] for
+    /// documentation purposes (only the type is relevant). Previous versions
+    /// of the compiler erroneously allowed [identifier patterns] with the
+    /// `mut` keyword, but this was not intended to be allowed. This is a
+    /// [future-incompatible] lint to transition this to a hard error in the
+    /// future. See [issue #35203] for more details.
+    ///
+    /// [identifier]: https://doc.rust-lang.org/reference/identifiers.html
+    /// [identifier patterns]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns
+    /// [issue #35203]: https://github.com/rust-lang/rust/issues/35203
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PATTERNS_IN_FNS_WITHOUT_BODY,
     Deny,
     "patterns in functions without body were erroneously allowed",
@@ -259,6 +1230,38 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `late_bound_lifetime_arguments` lint detects generic lifetime
+    /// arguments in path segments with late bound lifetime parameters.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// struct S;
+    ///
+    /// impl S {
+    ///     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
+    /// }
+    ///
+    /// fn main() {
+    ///     S.late::<'static>(&0, &0);
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is not clear how to provide arguments for early-bound lifetime
+    /// parameters if they are intermixed with late-bound parameters in the
+    /// same list. For now, providing any explicit arguments will trigger this
+    /// lint if late-bound parameters are present, so in the future a solution
+    /// can be adopted without hitting backward compatibility issues. This is
+    /// a [future-incompatible] lint to transition this to a hard error in the
+    /// future. See [issue #42868] for more details, along with a description
+    /// of the difference between early and late-bound parameters.
+    ///
+    /// [issue #42868]: https://github.com/rust-lang/rust/issues/42868
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub LATE_BOUND_LIFETIME_ARGUMENTS,
     Warn,
     "detects generic lifetime arguments in path segments with late bound lifetime parameters",
@@ -269,6 +1272,32 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `order_dependent_trait_objects` lint detects a trait coherency
+    /// violation that would allow creating two trait impls for the same
+    /// dynamic trait object involving marker traits.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// pub trait Trait {}
+    ///
+    /// impl Trait for dyn Send + Sync { }
+    /// impl Trait for dyn Sync + Send { }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// A previous bug caused the compiler to interpret traits with different
+    /// orders (such as `Send + Sync` and `Sync + Send`) as distinct types
+    /// when they were intended to be treated the same. This allowed code to
+    /// define separate trait implementations when there should be a coherence
+    /// error. This is a [future-incompatible] lint to transition this to a
+    /// hard error in the future. See [issue #56484] for more details.
+    ///
+    /// [issue #56484]: https://github.com/rust-lang/rust/issues/56484
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub ORDER_DEPENDENT_TRAIT_OBJECTS,
     Deny,
     "trait-object types were treated as different depending on marker-trait order",
@@ -279,6 +1308,36 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `coherence_leak_check` lint detects conflicting implementations of
+    /// a trait that are only distinguished by the old leak-check code.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// trait SomeTrait { }
+    /// impl SomeTrait for for<'a> fn(&'a u8) { }
+    /// impl<'a> SomeTrait for fn(&'a u8) { }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In the past, the compiler would accept trait implementations for
+    /// identical functions that differed only in where the lifetime binder
+    /// appeared. Due to a change in the borrow checker implementation to fix
+    /// several bugs, this is no longer allowed. However, since this affects
+    /// existing code, this is a [future-incompatible] lint to transition this
+    /// to a hard error in the future.
+    ///
+    /// Code relying on this pattern should introduce "[newtypes]",
+    /// like `struct Foo(for<'a> fn(&'a u8))`.
+    ///
+    /// See [issue #56105] for more details.
+    ///
+    /// [issue #56105]: https://github.com/rust-lang/rust/issues/56105
+    /// [newtypes]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub COHERENCE_LEAK_CHECK,
     Warn,
     "distinct impls distinguished only by the leak-check code",
@@ -289,6 +1348,29 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `deprecated` lint detects use of deprecated items.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #[deprecated]
+    /// fn foo() {}
+    ///
+    /// fn bar() {
+    ///     foo();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Items may be marked "deprecated" with the [`deprecated` attribute] to
+    /// indicate that they should no longer be used. Usually the attribute
+    /// should include a note on what to use instead, or check the
+    /// documentation.
+    ///
+    /// [`deprecated` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute
     pub DEPRECATED,
     Warn,
     "detects use of deprecated items",
@@ -296,36 +1378,158 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `unused_unsafe` lint detects unnecessary use of an `unsafe` block.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// unsafe {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// If nothing within the block requires `unsafe`, then remove the
+    /// `unsafe` marker because it is not required and may cause confusion.
     pub UNUSED_UNSAFE,
     Warn,
     "unnecessary use of an `unsafe` block"
 }
 
 declare_lint! {
+    /// The `unused_mut` lint detects mut variables which don't need to be
+    /// mutable.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let mut x = 5;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The preferred style is to only mark variables as `mut` if it is
+    /// required.
     pub UNUSED_MUT,
     Warn,
     "detect mut variables which don't need to be mutable"
 }
 
 declare_lint! {
+    /// The `unconditional_recursion` lint detects functions that cannot
+    /// return without calling themselves.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// fn foo() {
+    ///     foo();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// It is usually a mistake to have a recursive call that does not have
+    /// some condition to cause it to terminate. If you really intend to have
+    /// an infinite loop, using a `loop` expression is recommended.
     pub UNCONDITIONAL_RECURSION,
     Warn,
     "functions that cannot return without calling themselves"
 }
 
 declare_lint! {
+    /// The `single_use_lifetimes` lint detects lifetimes that are only used
+    /// once.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(single_use_lifetimes)]
+    ///
+    /// fn foo<'a>(x: &'a u32) {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Specifying an explicit lifetime like `'a` in a function or `impl`
+    /// should only be used to link together two things. Otherwise, you should
+    /// just use `'_` to indicate that the lifetime is not linked to anything,
+    /// or elide the lifetime altogether if possible.
+    ///
+    /// This lint is "allow" by default because it was introduced at a time
+    /// when `'_` and elided lifetimes were first being introduced, and this
+    /// lint would be too noisy. Also, there are some known false positives
+    /// that it produces. See [RFC 2115] for historical context, and [issue
+    /// #44752] for more details.
+    ///
+    /// [RFC 2115]: https://github.com/rust-lang/rfcs/blob/master/text/2115-argument-lifetimes.md
+    /// [issue #44752]: https://github.com/rust-lang/rust/issues/44752
     pub SINGLE_USE_LIFETIMES,
     Allow,
     "detects lifetime parameters that are only used once"
 }
 
 declare_lint! {
+    /// The `unused_lifetimes` lint detects lifetime parameters that are never
+    /// used.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #[deny(unused_lifetimes)]
+    ///
+    /// pub fn foo<'a>() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused lifetime parameters may signal a mistake or unfinished code.
+    /// Consider removing the parameter.
     pub UNUSED_LIFETIMES,
     Allow,
     "detects lifetime parameters that are never used"
 }
 
 declare_lint! {
+    /// The `tyvar_behind_raw_pointer` lint detects raw pointer to an
+    /// inference variable.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2015
+    /// // edition 2015
+    /// let data = std::ptr::null();
+    /// let _ = &data as *const *const ();
+    ///
+    /// if data.is_null() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This kind of inference was previously allowed, but with the future
+    /// arrival of [arbitrary self types], this can introduce ambiguity. To
+    /// resolve this, use an explicit type instead of relying on type
+    /// inference.
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard
+    /// error in the 2018 edition. See [issue #46906] for more details. This
+    /// is currently a hard-error on the 2018 edition, and is "warn" by
+    /// default in the 2015 edition.
+    ///
+    /// [arbitrary self types]: https://github.com/rust-lang/rust/issues/44874
+    /// [issue #46906]: https://github.com/rust-lang/rust/issues/46906
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub TYVAR_BEHIND_RAW_POINTER,
     Warn,
     "raw pointer to an inference variable",
@@ -336,6 +1540,34 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `elided_lifetimes_in_paths` lint detects the use of hidden
+    /// lifetime parameters.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(elided_lifetimes_in_paths)]
+    /// struct Foo<'a> {
+    ///     x: &'a u32
+    /// }
+    ///
+    /// fn foo(x: &Foo) {
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Elided lifetime parameters can make it difficult to see at a glance
+    /// that borrowing is occurring. This lint ensures that lifetime
+    /// parameters are always explicitly stated, even if it is the `'_`
+    /// [placeholder lifetime].
+    ///
+    /// This lint is "allow" by default because it has some known issues, and
+    /// may require a significant transition for old code.
+    ///
+    /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions
     pub ELIDED_LIFETIMES_IN_PATHS,
     Allow,
     "hidden lifetime parameters in types are deprecated",
@@ -343,12 +1575,78 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `bare_trait_objects` lint suggests using `dyn Trait` for trait
+    /// objects.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// trait Trait { }
+    ///
+    /// fn takes_trait_object(_: Box<Trait>) {
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Without the `dyn` indicator, it can be ambiguous or confusing when
+    /// reading code as to whether or not you are looking at a trait object.
+    /// The `dyn` keyword makes it explicit, and adds a symmetry to contrast
+    /// with [`impl Trait`].
+    ///
+    /// [`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters
     pub BARE_TRAIT_OBJECTS,
     Warn,
     "suggest using `dyn Trait` for trait objects"
 }
 
 declare_lint! {
+    /// The `absolute_paths_not_starting_with_crate` lint detects fully
+    /// qualified paths that start with a module name instead of `crate`,
+    /// `self`, or an extern crate name
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2015,compile_fail
+    /// #![deny(absolute_paths_not_starting_with_crate)]
+    ///
+    /// mod foo {
+    ///     pub fn bar() {}
+    /// }
+    ///
+    /// fn main() {
+    ///     ::foo::bar();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Rust [editions] allow the language to evolve without breaking
+    /// backwards compatibility. This lint catches code that uses absolute
+    /// paths in the style of the 2015 edition. In the 2015 edition, absolute
+    /// paths (those starting with `::`) refer to either the crate root or an
+    /// external crate. In the 2018 edition it was changed so that they only
+    /// refer to external crates. The path prefix `crate::` should be used
+    /// instead to reference items from the crate root.
+    ///
+    /// If you switch the compiler from the 2015 to 2018 edition without
+    /// updating the code, then it will fail to compile if the old style paths
+    /// are used. You can manually change the paths to use the `crate::`
+    /// prefix to transition to the 2018 edition.
+    ///
+    /// This lint solves the problem automatically. It is "allow" by default
+    /// because the code is perfectly valid in the 2015 edition. The [`cargo
+    /// fix`] tool with the `--edition` flag will switch this lint to "warn"
+    /// and automatically apply the suggested fix from the compiler. This
+    /// provides a completely automated way to update old code to the 2018
+    /// edition.
+    ///
+    /// [editions]: https://doc.rust-lang.org/edition-guide/
+    /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html
     pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
     Allow,
     "fully qualified paths that start with a module name \
@@ -360,6 +1658,45 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `illegal_floating_point_literal_pattern` lint detects
+    /// floating-point literals used in patterns.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let x = 42.0;
+    ///
+    /// match x {
+    ///     5.0 => {}
+    ///     _ => {}
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Previous versions of the compiler accepted floating-point literals in
+    /// patterns, but it was later determined this was a mistake. The
+    /// semantics of comparing floating-point values may not be clear in a
+    /// pattern when contrasted with "structural equality". Typically you can
+    /// work around this by using a [match guard], such as:
+    ///
+    /// ```rust
+    /// # let x = 42.0;
+    ///
+    /// match x {
+    ///     y if y == 5.0 => {}
+    ///     _ => {}
+    /// }
+    /// ```
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard
+    /// error in the future. See [issue #41620] for more details.
+    ///
+    /// [issue #41620]: https://github.com/rust-lang/rust/issues/41620
+    /// [match guard]: https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
     Warn,
     "floating-point literals cannot be used in patterns",
@@ -370,6 +1707,40 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `unstable_name_collisions` lint detects that you have used a name
+    /// that the standard library plans to add in the future.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// trait MyIterator : Iterator {
+    ///     // is_sorted is an unstable method that already exists on the Iterator trait
+    ///     fn is_sorted(self) -> bool where Self: Sized {true}
+    /// }
+    ///
+    /// impl<T: ?Sized> MyIterator for T where T: Iterator { }
+    ///
+    /// let x = vec![1,2,3];
+    /// let _ = x.iter().is_sorted();
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// When new methods are added to traits in the standard library, they are
+    /// usually added in an "unstable" form which is only available on the
+    /// [nightly channel] with a [`feature` attribute]. If there is any
+    /// pre-existing code which extends a trait to have a method with the same
+    /// name, then the names will collide. In the future, when the method is
+    /// stabilized, this will cause an error due to the ambiguity. This lint
+    /// is an early-warning to let you know that there may be a collision in
+    /// the future. This can be avoided by adding type annotations to
+    /// disambiguate which trait method you intend to call, such as
+    /// `MyIterator::is_sorted(my_iter)` or renaming or removing the method.
+    ///
+    /// [nightly channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+    /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/
     pub UNSTABLE_NAME_COLLISIONS,
     Warn,
     "detects name collision with an existing but unstable method",
@@ -382,48 +1753,267 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `irrefutable_let_patterns` lint detects detects [irrefutable
+    /// patterns] in [if-let] and [while-let] statements.
+    ///
+    ///
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// if let _ = 123 {
+    ///     println!("always runs!");
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// There usually isn't a reason to have an irrefutable pattern in an
+    /// if-let or while-let statement, because the pattern will always match
+    /// successfully. A [`let`] or [`loop`] statement will suffice. However,
+    /// when generating code with a macro, forbidding irrefutable patterns
+    /// would require awkward workarounds in situations where the macro
+    /// doesn't know if the pattern is refutable or not. This lint allows
+    /// macros to accept this form, while alerting for a possibly incorrect
+    /// use in normal code.
+    ///
+    /// See [RFC 2086] for more details.
+    ///
+    /// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability
+    /// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
+    /// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops
+    /// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements
+    /// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops
+    /// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md
     pub IRREFUTABLE_LET_PATTERNS,
     Warn,
     "detects irrefutable patterns in if-let and while-let statements"
 }
 
 declare_lint! {
+    /// The `unused_labels` lint detects [labels] that are never used.
+    ///
+    /// [labels]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#loop-labels
+    ///
+    /// ### Example
+    ///
+    /// ```rust,no_run
+    /// 'unused_label: loop {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Unused labels may signal a mistake or unfinished code. To silence the
+    /// warning for the individual label, prefix it with an underscore such as
+    /// `'_my_label:`.
     pub UNUSED_LABELS,
     Warn,
     "detects labels that are never used"
 }
 
 declare_lint! {
+    /// The `broken_intra_doc_links` lint detects failures in resolving
+    /// intra-doc link targets. This is a `rustdoc` only lint, and only works
+    /// on the [**nightly channel**].
+    ///
+    /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,rustdoc
+    /// /// This is a doc comment.
+    /// ///
+    /// /// See also [`bar`].
+    /// pub fn foo() {
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// `rustdoc` allows [linking to items by name][intra] which will
+    /// automatically generate links in the documentation to the item. This
+    /// lint is issued when `rustdoc` is unable to find the named item. Check
+    /// that the name is correct, that it is in scope, or if you need to
+    /// qualify it with a path. If you intended to have square brackets appear
+    /// literally in the text, surround the brackets with backticks such as ``
+    /// `[example]` `` to indicate a code span, or prefix it with a backslash
+    /// such as `\[example]`.
+    ///
+    /// [intra]: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#linking-to-items-by-name
     pub BROKEN_INTRA_DOC_LINKS,
     Warn,
     "failures in resolving intra-doc link targets"
 }
 
 declare_lint! {
+    /// The `invalid_codeblock_attributes` lint detects code block attributes
+    /// in documentation examples that have potentially mis-typed values. This
+    /// is a `rustdoc` only lint.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,rustdoc
+    /// /// Example.
+    /// ///
+    /// /// ```should-panic
+    /// /// assert_eq!(1, 2);
+    /// /// ```
+    /// pub fn foo() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint is issued when `rustdoc` detects an example code block
+    /// attribute that appears similar to a valid one. In the example above,
+    /// the correct form is `should_panic`. This helps detect typo mistakes
+    /// for some common attributes.
     pub INVALID_CODEBLOCK_ATTRIBUTES,
     Warn,
     "codeblock attribute looks a lot like a known one"
 }
 
 declare_lint! {
+    /// The `missing_crate_level_docs` lint detects if documentation is
+    /// missing at the crate root. This is a `rustdoc` only lint. This is a
+    /// `rustdoc` only lint.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,rustdoc
+    /// #![deny(missing_crate_level_docs)]
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint causes `rustdoc` to check if the crate root is missing
+    /// documentation. This is currently "allow" by default, but it is
+    /// intended to make this a warning in the future. This is intended as a
+    /// means to introduce new users on *how* to document their crate by
+    /// pointing them to some instructions on how to get started.
     pub MISSING_CRATE_LEVEL_DOCS,
     Allow,
     "detects crates with no crate-level documentation"
 }
 
 declare_lint! {
+    /// The `missing_doc_code_examples` lint detects publicly-exported items
+    /// without code samples in their documentation. This is a `rustdoc` only
+    /// lint, and only works on the [**nightly channel**].
+    ///
+    /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,rustdoc
+    /// #![warn(missing_doc_code_examples)]
+    ///
+    /// /// There is no code example!
+    /// pub fn no_code_example() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This lint is to ensure a high level of quality for documentation. Code
+    /// examples can be very useful to see how to use an API. To add an
+    /// example, include a markdown code block with an example of how to use
+    /// the item, such as:
+    ///
+    /// ```rust
+    /// /// Adds one to the number given.
+    /// ///
+    /// /// # Examples
+    /// ///
+    /// /// ```
+    /// /// let arg = 5;
+    /// /// let answer = my_crate::add_one(arg);
+    /// ///
+    /// /// assert_eq!(6, answer);
+    /// /// ```
+    /// pub fn add_one(x: i32) -> i32 {
+    ///     x + 1
+    /// }
+    /// ```
     pub MISSING_DOC_CODE_EXAMPLES,
     Allow,
     "detects publicly-exported items without code samples in their documentation"
 }
 
 declare_lint! {
+    /// The `private_doc_tests` lint detects code samples in docs of private
+    /// items not documented by `rustdoc`. This is a `rustdoc` only lint.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,rustdoc
+    /// #![deny(private_doc_tests)]
+    ///
+    /// mod foo {
+    ///     /// private doc test
+    ///     ///
+    ///     /// ```
+    ///     /// assert!(false);
+    ///     /// ```
+    ///     fn bar() {}
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Because documentation examples link against the public API of the
+    /// crate, it is not possible for an example to access a private item.
+    /// This means it was likely a mistake to add a code example to a private
+    /// item.
     pub PRIVATE_DOC_TESTS,
     Allow,
     "detects code samples in docs of private items not documented by rustdoc"
 }
 
 declare_lint! {
+    /// The `where_clauses_object_safety` lint detects for [object safety] of
+    /// [where clauses].
+    ///
+    /// [object safety]: https://doc.rust-lang.org/reference/items/traits.html#object-safety
+    /// [where clauses]: https://doc.rust-lang.org/reference/items/generics.html#where-clauses
+    ///
+    /// ### Example
+    ///
+    /// ```rust,no_run
+    /// trait Trait {}
+    ///
+    /// trait X { fn foo(&self) where Self: Trait; }
+    ///
+    /// impl X for () { fn foo(&self) {} }
+    ///
+    /// impl Trait for dyn X {}
+    ///
+    /// // Segfault at opt-level 0, SIGILL otherwise.
+    /// pub fn main() { <dyn X as X>::foo(&()); }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler previously allowed these object-unsafe bounds, which was
+    /// incorrect. This is a [future-incompatible] lint to transition this to
+    /// a hard error in the future. See [issue #51443] for more details.
+    ///
+    /// [issue #51443]: https://github.com/rust-lang/rust/issues/51443
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub WHERE_CLAUSES_OBJECT_SAFETY,
     Warn,
     "checks the object safety of where clauses",
@@ -434,6 +2024,63 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `proc_macro_derive_resolution_fallback` lint detects proc macro
+    /// derives using inaccessible names from parent modules.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (proc-macro)
+    /// // foo.rs
+    /// #![crate_type = "proc-macro"]
+    ///
+    /// extern crate proc_macro;
+    ///
+    /// use proc_macro::*;
+    ///
+    /// #[proc_macro_derive(Foo)]
+    /// pub fn foo1(a: TokenStream) -> TokenStream {
+    ///     drop(a);
+    ///     "mod __bar { static mut BAR: Option<Something> = None; }".parse().unwrap()
+    /// }
+    /// ```
+    ///
+    /// ```rust,ignore (needs-dependency)
+    /// // bar.rs
+    /// #[macro_use]
+    /// extern crate foo;
+    ///
+    /// struct Something;
+    ///
+    /// #[derive(Foo)]
+    /// struct Another;
+    ///
+    /// fn main() {}
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// warning: cannot find type `Something` in this scope
+    ///  --> src/main.rs:8:10
+    ///   |
+    /// 8 | #[derive(Foo)]
+    ///   |          ^^^ names from parent modules are not accessible without an explicit import
+    ///   |
+    ///   = note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
+    ///   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+    ///   = note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// If a proc-macro generates a module, the compiler unintentionally
+    /// allowed items in that module to refer to items in the crate root
+    /// without importing them. This is a [future-incompatible] lint to
+    /// transition this to a hard error in the future. See [issue #50504] for
+    /// more details.
+    ///
+    /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
     Warn,
     "detects proc macro derives using inaccessible names from parent modules",
@@ -444,6 +2091,53 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `macro_use_extern_crate` lint detects the use of the
+    /// [`macro_use` attribute].
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(macro_use_extern_crate)]
+    ///
+    /// #[macro_use]
+    /// extern crate serde_json;
+    ///
+    /// fn main() {
+    ///     let _ = json!{{}};
+    /// }
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead
+    ///  --> src/main.rs:3:1
+    ///   |
+    /// 3 | #[macro_use]
+    ///   | ^^^^^^^^^^^^
+    ///   |
+    /// note: the lint level is defined here
+    ///  --> src/main.rs:1:9
+    ///   |
+    /// 1 | #![deny(macro_use_extern_crate)]
+    ///   |         ^^^^^^^^^^^^^^^^^^^^^^
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// The [`macro_use` attribute] on an [`extern crate`] item causes
+    /// macros in that external crate to be brought into the prelude of the
+    /// crate, making the macros in scope everywhere. As part of the efforts
+    /// to simplify handling of dependencies in the [2018 edition], the use of
+    /// `extern crate` is being phased out. To bring macros from extern crates
+    /// into scope, it is recommended to use a [`use` import].
+    ///
+    /// This lint is "allow" by default because this is a stylistic choice
+    /// that has not been settled, see [issue #52043] for more information.
+    ///
+    /// [`macro_use` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute
+    /// [`use` import]: https://doc.rust-lang.org/reference/items/use-declarations.html
+    /// [issue #52043]: https://github.com/rust-lang/rust/issues/52043
     pub MACRO_USE_EXTERN_CRATE,
     Allow,
     "the `#[macro_use]` attribute is now deprecated in favor of using macros \
@@ -451,6 +2145,44 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `macro_expanded_macro_exports_accessed_by_absolute_paths` lint
+    /// detects macro-expanded [`macro_export`] macros from the current crate
+    /// that cannot be referred to by absolute paths.
+    ///
+    /// [`macro_export`]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// macro_rules! define_exported {
+    ///     () => {
+    ///         #[macro_export]
+    ///         macro_rules! exported {
+    ///             () => {};
+    ///         }
+    ///     };
+    /// }
+    ///
+    /// define_exported!();
+    ///
+    /// fn main() {
+    ///     crate::exported!();
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The intent is that all macros marked with the `#[macro_export]`
+    /// attribute are made available in the root of the crate. However, when a
+    /// `macro_rules!` definition is generated by another macro, the macro
+    /// expansion is unable to uphold this rule. This is a
+    /// [future-incompatible] lint to transition this to a hard error in the
+    /// future. See [issue #53495] for more details.
+    ///
+    /// [issue #53495]: https://github.com/rust-lang/rust/issues/53495
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
     Deny,
     "macro-expanded `macro_export` macros from the current crate \
@@ -463,12 +2195,92 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `explicit_outlives_requirements` lint detects unnecessary
+    /// lifetime bounds that can be inferred.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// # #![allow(unused)]
+    /// #![deny(explicit_outlives_requirements)]
+    ///
+    /// struct SharedRef<'a, T>
+    /// where
+    ///     T: 'a,
+    /// {
+    ///     data: &'a T,
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// If a `struct` contains a reference, such as `&'a T`, the compiler
+    /// requires that `T` outlives the lifetime `'a`. This historically
+    /// required writing an explicit lifetime bound to indicate this
+    /// requirement. However, this can be overly explicit, causing clutter and
+    /// unnecessary complexity. The language was changed to automatically
+    /// infer the bound if it is not specified. Specifically, if the struct
+    /// contains a reference, directly or indirectly, to `T` with lifetime
+    /// `'x`, then it will infer that `T: 'x` is a requirement.
+    ///
+    /// This lint is "allow" by default because it can be noisy for existing
+    /// code that already had these requirements. This is a stylistic choice,
+    /// as it is still valid to explicitly state the bound. It also has some
+    /// false positives that can cause confusion.
+    ///
+    /// See [RFC 2093] for more details.
+    ///
+    /// [RFC 2093]: https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md
     pub EXPLICIT_OUTLIVES_REQUIREMENTS,
     Allow,
     "outlives requirements can be inferred"
 }
 
 declare_lint! {
+    /// The `indirect_structural_match` lint detects a `const` in a pattern
+    /// that manually implements [`PartialEq`] and [`Eq`].
+    ///
+    /// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html
+    /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![deny(indirect_structural_match)]
+    ///
+    /// struct Plus(i32, i32);
+    /// const ONE_PLUS_TWO: &&Plus = &&Plus(1, 2);
+    ///
+    /// impl PartialEq for Plus {
+    ///     fn eq(&self, other: &Self) -> bool {
+    ///         self.0 + self.1 == other.0 + other.1
+    ///     }
+    /// }
+    ///
+    /// impl Eq for Plus {}
+    ///
+    /// fn main() {
+    ///     if let ONE_PLUS_TWO = &&Plus(3, 0) {
+    ///         println!("semantic!");
+    ///     } else {
+    ///         println!("structural!");
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The compiler unintentionally accepted this form in the past. This is a
+    /// [future-incompatible] lint to transition this to a hard error in the
+    /// future. See [issue #62411] for a complete description of the problem,
+    /// and some possible solutions.
+    ///
+    /// [issue #62411]: https://github.com/rust-lang/rust/issues/62411
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub INDIRECT_STRUCTURAL_MATCH,
     // defaulting to allow until rust-lang/rust#62614 is fixed.
     Allow,
@@ -480,6 +2292,17 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `deprecated_in_future` lint is internal to rustc and should not be
+    /// used by user code.
+    ///
+    /// This lint is only enabled in the standard library. It works with the
+    /// use of `#[rustc_deprecated]` with a `since` field of a version in the
+    /// future. This allows something to be marked as deprecated in a future
+    /// version, and then this lint will ensure that the item is no longer
+    /// used in the standard library. See the [stability documentation] for
+    /// more details.
+    ///
+    /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#rustc_deprecated
     pub DEPRECATED_IN_FUTURE,
     Allow,
     "detects use of items that will be deprecated in a future version",
@@ -487,6 +2310,54 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `ambiguous_associated_items` lint detects ambiguity between
+    /// [associated items] and [enum variants].
+    ///
+    /// [associated items]: https://doc.rust-lang.org/reference/items/associated-items.html
+    /// [enum variants]: https://doc.rust-lang.org/reference/items/enumerations.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// enum E {
+    ///     V
+    /// }
+    ///
+    /// trait Tr {
+    ///     type V;
+    ///     fn foo() -> Self::V;
+    /// }
+    ///
+    /// impl Tr for E {
+    ///     type V = u8;
+    ///     // `Self::V` is ambiguous because it may refer to the associated type or
+    ///     // the enum variant.
+    ///     fn foo() -> Self::V { 0 }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Previous versions of Rust did not allow accessing enum variants
+    /// through [type aliases]. When this ability was added (see [RFC 2338]), this
+    /// introduced some situations where it can be ambiguous what a type
+    /// was referring to.
+    ///
+    /// To fix this ambiguity, you should use a [qualified path] to explicitly
+    /// state which type to use. For example, in the above example the
+    /// function can be written as `fn f() -> <Self as Tr>::V { 0 }` to
+    /// specifically refer to the associated type.
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard
+    /// error in the future. See [issue #57644] for more details.
+    ///
+    /// [issue #57644]: https://github.com/rust-lang/rust/issues/57644
+    /// [type aliases]: https://doc.rust-lang.org/reference/items/type-aliases.html#type-aliases
+    /// [RFC 2338]: https://github.com/rust-lang/rfcs/blob/master/text/2338-type-alias-enum-variants.md
+    /// [qualified path]: https://doc.rust-lang.org/reference/paths.html#qualified-paths
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub AMBIGUOUS_ASSOCIATED_ITEMS,
     Deny,
     "ambiguous associated items",
@@ -497,6 +2368,27 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `mutable_borrow_reservation_conflict` lint detects the reservation
+    /// of a two-phased borrow that conflicts with other shared borrows.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// let mut v = vec![0, 1, 2];
+    /// let shared = &v;
+    /// v.push(shared.len());
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard error
+    /// in the future. See [issue #59159] for a complete description of the
+    /// problem, and some possible solutions.
+    ///
+    /// [issue #59159]: https://github.com/rust-lang/rust/issues/59159
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub MUTABLE_BORROW_RESERVATION_CONFLICT,
     Warn,
     "reservation of a two-phased borrow conflicts with other shared borrows",
@@ -507,6 +2399,38 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `soft_unstable` lint detects unstable features that were
+    /// unintentionally allowed on stable.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #[cfg(test)]
+    /// extern crate test;
+    ///
+    /// #[bench]
+    /// fn name(b: &mut test::Bencher) {
+    ///     b.iter(|| 123)
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The [`bench` attribute] was accidentally allowed to be specified on
+    /// the [stable release channel]. Turning this to a hard error would have
+    /// broken some projects. This lint allows those projects to continue to
+    /// build correctly when [`--cap-lints`] is used, but otherwise signal an
+    /// error that `#[bench]` should not be used on the stable channel. This
+    /// is a [future-incompatible] lint to transition this to a hard error in
+    /// the future. See [issue #64266] for more details.
+    ///
+    /// [issue #64266]: https://github.com/rust-lang/rust/issues/64266
+    /// [`bench` attribute]: https://doc.rust-lang.org/nightly/unstable-book/library-features/test.html
+    /// [stable release channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+    /// [`--cap-lints`]: https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
     pub SOFT_UNSTABLE,
     Deny,
     "a feature gate that doesn't break dependent crates",
@@ -517,18 +2441,123 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `inline_no_sanitize` lint detects incompatible use of
+    /// [`#[inline(always)]`][inline] and [`#[no_sanitize(...)]`][no_sanitize].
+    ///
+    /// [inline]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute
+    /// [no_sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// #![feature(no_sanitize)]
+    ///
+    /// #[inline(always)]
+    /// #[no_sanitize(address)]
+    /// fn x() {}
+    ///
+    /// fn main() {
+    ///     x()
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// The use of the [`#[inline(always)]`][inline] attribute prevents the
+    /// the [`#[no_sanitize(...)]`][no_sanitize] attribute from working.
+    /// Consider temporarily removing `inline` attribute.
     pub INLINE_NO_SANITIZE,
     Warn,
     "detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`",
 }
 
 declare_lint! {
+    /// The `asm_sub_register` lint detects using only a subset of a register
+    /// for inline asm inputs.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (fails on system llvm)
+    /// #![feature(asm)]
+    ///
+    /// fn main() {
+    ///     #[cfg(target_arch="x86_64")]
+    ///     unsafe {
+    ///         asm!("mov {0}, {0}", in(reg) 0i16);
+    ///     }
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Registers on some architectures can use different names to refer to a
+    /// subset of the register. By default, the compiler will use the name for
+    /// the full register size. To explicitly use a subset of the register,
+    /// you can override the default by using a modifier on the template
+    /// string operand to specify when subregister to use. This lint is issued
+    /// if you pass in a value with a smaller data type than the default
+    /// register size, to alert you of possibly using the incorrect width. To
+    /// fix this, add the suggested modifier to the template, or cast the
+    /// value to the correct size.
+    ///
+    /// See [register template modifiers] for more details.
+    ///
+    /// [register template modifiers]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#register-template-modifiers
     pub ASM_SUB_REGISTER,
     Warn,
     "using only a subset of a register for inline asm inputs",
 }
 
 declare_lint! {
+    /// The `unsafe_op_in_unsafe_fn` lint detects unsafe operations in unsafe
+    /// functions without an explicit unsafe block. This lint only works on
+    /// the [**nightly channel**] with the
+    /// `#![feature(unsafe_block_in_unsafe_fn)]` feature.
+    ///
+    /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// #![feature(unsafe_block_in_unsafe_fn)]
+    /// #![deny(unsafe_op_in_unsafe_fn)]
+    ///
+    /// unsafe fn foo() {}
+    ///
+    /// unsafe fn bar() {
+    ///     foo();
+    /// }
+    ///
+    /// fn main() {}
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Currently, an [`unsafe fn`] allows any [unsafe] operation within its
+    /// body. However, this can increase the surface area of code that needs
+    /// to be scrutinized for proper behavior. The [`unsafe` block] provides a
+    /// convenient way to make it clear exactly which parts of the code are
+    /// performing unsafe operations. In the future, it is desired to change
+    /// it so that unsafe operations cannot be performed in an `unsafe fn`
+    /// without an `unsafe` block.
+    ///
+    /// The fix to this is to wrap the unsafe code in an `unsafe` block.
+    ///
+    /// This lint is "allow" by default because it has not yet been
+    /// stabilized, and is not yet complete. See [RFC #2585] and [issue
+    /// #71668] for more details
+    ///
+    /// [`unsafe fn`]: https://doc.rust-lang.org/reference/unsafe-functions.html
+    /// [`unsafe` block]: https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks
+    /// [unsafe]: https://doc.rust-lang.org/reference/unsafety.html
+    /// [RFC #2585]: https://github.com/rust-lang/rfcs/blob/master/text/2585-unsafe-block-in-unsafe-fn.md
+    /// [issue #71668]: https://github.com/rust-lang/rust/issues/71668
     pub UNSAFE_OP_IN_UNSAFE_FN,
     Allow,
     "unsafe operations in unsafe functions without an explicit unsafe block are deprecated",
@@ -536,6 +2565,48 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `cenum_impl_drop_cast` lint detects an `as` cast of a field-less
+    /// `enum` that implements [`Drop`].
+    ///
+    /// [`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// # #![allow(unused)]
+    /// enum E {
+    ///     A,
+    /// }
+    ///
+    /// impl Drop for E {
+    ///     fn drop(&mut self) {
+    ///         println!("Drop");
+    ///     }
+    /// }
+    ///
+    /// fn main() {
+    ///     let e = E::A;
+    ///     let i = e as u32;
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Casting a field-less `enum` that does not implement [`Copy`] to an
+    /// integer moves the value without calling `drop`. This can result in
+    /// surprising behavior if it was expected that `drop` should be called.
+    /// Calling `drop` automatically would be inconsistent with other move
+    /// operations. Since neither behavior is clear or consistent, it was
+    /// decided that a cast of this nature will no longer be allowed.
+    ///
+    /// This is a [future-incompatible] lint to transition this to a hard error
+    /// in the future. See [issue #73333] for more details.
+    ///
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    /// [issue #73333]: https://github.com/rust-lang/rust/issues/73333
+    /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
     pub CENUM_IMPL_DROP_CAST,
     Warn,
     "a C-like enum implementing Drop is cast",
@@ -546,6 +2617,36 @@ declare_lint! {
 }
 
 declare_lint! {
+    /// The `const_evaluatable_unchecked` lint detects a generic constant used
+    /// in a type.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// const fn foo<T>() -> usize {
+    ///     if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T
+    ///         std::mem::size_of::<T>()
+    ///     } else {
+    ///         8
+    ///     }
+    /// }
+    ///
+    /// fn test<T>() {
+    ///     let _ = [0; foo::<T>()];
+    /// }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In the 1.43 release, some uses of generic parameters in array repeat
+    /// expressions were accidentally allowed. This is a [future-incompatible]
+    /// lint to transition this to a hard error in the future. See [issue
+    /// #76200] for a more detailed description and possible fixes.
+    ///
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    /// [issue #76200]: https://github.com/rust-lang/rust/issues/76200
     pub CONST_EVALUATABLE_UNCHECKED,
     Warn,
     "detects a generic constant is used in a type without a emitting a warning",
@@ -641,6 +2742,23 @@ declare_lint_pass! {
 }
 
 declare_lint! {
+    /// The `unused_doc_comments` lint detects doc comments that aren't used
+    /// by `rustdoc`.
+    ///
+    /// ### Example
+    ///
+    /// ```rust
+    /// /// docs for x
+    /// let x = 12;
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// `rustdoc` does not use doc comments in all positions, and so the doc
+    /// comment will be ignored. Try changing it to a normal comment with `//`
+    /// to avoid the warning.
     pub UNUSED_DOC_COMMENTS,
     Warn,
     "detects doc comments that aren't used by rustdoc"
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index d7f3a888edd..be5182b939d 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -66,7 +66,6 @@ book!(
     Nomicon, "src/doc/nomicon", "nomicon";
     Reference, "src/doc/reference", "reference";
     RustByExample, "src/doc/rust-by-example", "rust-by-example";
-    RustcBook, "src/doc/rustc", "rustc";
     RustdocBook, "src/doc/rustdoc", "rustdoc";
 );
 
@@ -718,3 +717,69 @@ fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()>
 
     symlink_dir(config, src, dst)
 }
+
+#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)]
+pub struct RustcBook {
+    pub compiler: Compiler,
+    pub target: TargetSelection,
+}
+
+impl Step for RustcBook {
+    type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        let builder = run.builder;
+        run.path("src/doc/rustc").default_condition(builder.config.docs)
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(RustcBook {
+            compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build),
+            target: run.target,
+        });
+    }
+
+    /// Builds the rustc book.
+    ///
+    /// The lints are auto-generated by a tool, and then merged into the book
+    /// in the "md-doc" directory in the build output directory. Then
+    /// "rustbook" is used to convert it to HTML.
+    fn run(self, builder: &Builder<'_>) {
+        let out_base = builder.md_doc_out(self.target).join("rustc");
+        t!(fs::create_dir_all(&out_base));
+        let out_listing = out_base.join("src/lints");
+        builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base);
+        builder.info(&format!("Generating lint docs ({})", self.target));
+        let rustc = builder.rustc(self.compiler);
+        // The tool runs `rustc` for extracting output examples, so it needs a
+        // functional sysroot.
+        builder.ensure(compile::Std { compiler: self.compiler, target: self.target });
+        let rustdoc = builder.rustdoc(self.compiler);
+        let mut cmd = builder.tool_cmd(Tool::LintDocs);
+        cmd.arg("--src");
+        cmd.arg(builder.src.join("compiler"));
+        cmd.arg("--out");
+        cmd.arg(&out_listing);
+        cmd.arg("--rustc");
+        cmd.arg(rustc);
+        cmd.arg("--rustdoc");
+        cmd.arg(rustdoc);
+        if builder.config.verbose() {
+            cmd.arg("--verbose");
+        }
+        builder.run(&mut cmd);
+        // Run rustbook/mdbook to generate the HTML pages.
+        builder.ensure(RustbookSrc {
+            target: self.target,
+            name: INTERNER.intern_str("rustc"),
+            src: INTERNER.intern_path(out_base),
+        });
+        if is_explicit_request(builder, "src/doc/rustc") {
+            let out = builder.doc_out(self.target);
+            let index = out.join("rustc").join("index.html");
+            open(builder, &index);
+        }
+    }
+}
diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs
index a607f0fe258..99e33e3b006 100644
--- a/src/bootstrap/tool.rs
+++ b/src/bootstrap/tool.rs
@@ -367,6 +367,7 @@ bootstrap_tool!(
     RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true;
     RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes";
     ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors";
+    LintDocs, "src/tools/lint-docs", "lint-docs";
 );
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
diff --git a/src/doc/rustc/src/lints/groups.md b/src/doc/rustc/src/lints/groups.md
index 049e59b6517..44cf42ff0d7 100644
--- a/src/doc/rustc/src/lints/groups.md
+++ b/src/doc/rustc/src/lints/groups.md
@@ -14,14 +14,7 @@ $ rustc -D non-camel-case-types -D non-snake-case -D non-upper-case-globals
 
 Here's a list of each lint group, and the lints that they are made up of:
 
-| group               | description                                                   | lints                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
-|---------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
-| nonstandard-style   | Violation of standard naming conventions                      | non-camel-case-types, non-snake-case, non-upper-case-globals                                                                                                                                                                                                                                                                                                                                                                                                                           |
-| warnings            | all lints that would be issuing warnings                      | all lints that would be issuing warnings                                                                                                                                                                                                                                                                                                                                                                                                                                               |
-| edition-2018        | Lints that will be turned into errors in Rust 2018            | tyvar-behind-raw-pointer                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
-| rust-2018-idioms    | Lints to nudge you toward idiomatic features of Rust 2018     | bare-trait-object, unreachable-pub                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
-| unused              | These lints detect things being declared but not used         | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens                                                                                                                                                                                    |
-| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, tyvar-behind-raw-pointer, unstable-name-collision |
+{{groups-table}}
 
 Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`.
 
diff --git a/src/doc/rustc/src/lints/index.md b/src/doc/rustc/src/lints/index.md
index 9010d436eb5..029c9edc1b5 100644
--- a/src/doc/rustc/src/lints/index.md
+++ b/src/doc/rustc/src/lints/index.md
@@ -26,3 +26,35 @@ warning: unused variable: `x`
 This is the `unused_variables` lint, and it tells you that you've introduced
 a variable that you don't use in your code. That's not *wrong*, so it's not
 an error, but it might be a bug, so you get a warning.
+
+## Future-incompatible lints
+
+Sometimes the compiler needs to be changed to fix an issue that can cause
+existing code to stop compiling. "Future-incompatible" lints are issued in
+these cases to give users of Rust a smooth transition to the new behavior.
+Initially, the compiler will continue to accept the problematic code and issue
+a warning. The warning has a description of the problem, a notice that this
+will become an error in the future, and a link to a tracking issue that
+provides detailed information and an opportunity for feedback. This gives
+users some time to fix the code to accommodate the change. After some time,
+the warning may become an error.
+
+The following is an example of what a future-incompatible looks like:
+
+```text
+warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133)
+  --> lint_example.rs:11:13
+   |
+11 |     let y = &x.data.0;
+   |             ^^^^^^^^^
+   |
+   = note: `#[warn(safe_packed_borrows)]` on by default
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
+   = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
+```
+
+For more information about the process and policy of future-incompatible
+changes, see [RFC 1589].
+
+[RFC 1589]: https://github.com/rust-lang/rfcs/blob/master/text/1589-rustc-bug-fix-procedure.md
diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md
index d2d8c471efc..95dd60bebfb 100644
--- a/src/doc/rustc/src/lints/listing/allowed-by-default.md
+++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md
@@ -1,454 +1,3 @@
 # Allowed-by-default lints
 
-These lints are all set to the 'allow' level by default. As such, they won't show up
-unless you set them to a higher lint level with a flag or attribute.
-
-## anonymous-parameters
-
-This lint detects anonymous parameters. Some example code that triggers this lint:
-
-```rust
-trait Foo {
-    fn foo(usize);
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: use of deprecated anonymous parameter
- --> src/lib.rs:5:11
-  |
-5 |     fn foo(usize);
-  |           ^
-  |
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-  = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
-```
-
-This syntax is mostly a historical accident, and can be worked around quite
-easily:
-
-```rust
-trait Foo {
-    fn foo(_: usize);
-}
-```
-
-## bare-trait-object
-
-This lint suggests using `dyn Trait` for trait objects. Some example code
-that triggers this lint:
-
-```rust
-#![feature(dyn_trait)]
-
-trait Trait { }
-
-fn takes_trait_object(_: Box<Trait>) {
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: trait objects without an explicit `dyn` are deprecated
- --> src/lib.rs:7:30
-  |
-7 | fn takes_trait_object(_: Box<Trait>) {
-  |                              ^^^^^ help: use `dyn`: `dyn Trait`
-  |
-```
-
-To fix it, do as the help message suggests:
-
-```rust
-#![feature(dyn_trait)]
-#![deny(bare_trait_objects)]
-
-trait Trait { }
-
-fn takes_trait_object(_: Box<dyn Trait>) {
-}
-```
-
-## box-pointers
-
-This lints use of the Box type. Some example code that triggers this lint:
-
-```rust
-struct Foo {
-    x: Box<isize>,
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: type uses owned (Box type) pointers: std::boxed::Box<isize>
- --> src/lib.rs:6:5
-  |
-6 |     x: Box<isize> //~ ERROR type uses owned
-  |     ^^^^^^^^^^^^^
-  |
-```
-
-This lint is mostly historical, and not particularly useful. `Box<T>` used to
-be built into the language, and the only way to do heap allocation. Today's
-Rust can call into other allocators, etc.
-
-## elided-lifetime-in-path
-
-This lint detects the use of hidden lifetime parameters. Some example code
-that triggers this lint:
-
-```rust
-struct Foo<'a> {
-    x: &'a u32
-}
-
-fn foo(x: &Foo) {
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: hidden lifetime parameters are deprecated, try `Foo<'_>`
- --> src/lib.rs:5:12
-  |
-5 | fn foo(x: &Foo) {
-  |            ^^^
-  |
-```
-
-Lifetime elision elides this lifetime, but that is being deprecated.
-
-## missing-copy-implementations
-
-This lint detects potentially-forgotten implementations of `Copy`. Some
-example code that triggers this lint:
-
-```rust
-pub struct Foo {
-    pub field: i32
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: type could implement `Copy`; consider adding `impl Copy`
- --> src/main.rs:3:1
-  |
-3 | / pub struct Foo { //~ ERROR type could implement `Copy`; consider adding `impl Copy`
-4 | |     pub field: i32
-5 | | }
-  | |_^
-  |
-```
-
-You can fix the lint by deriving `Copy`.
-
-This lint is set to 'allow' because this code isn't bad; it's common to write
-newtypes like this specifically so that a `Copy` type is no longer `Copy`.
-
-## missing-debug-implementations
-
-This lint detects missing implementations of `fmt::Debug`. Some example code
-that triggers this lint:
-
-```rust
-pub struct Foo;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation
- --> src/main.rs:3:1
-  |
-3 | pub struct Foo;
-  | ^^^^^^^^^^^^^^^
-  |
-```
-
-You can fix the lint by deriving `Debug`.
-
-## missing-docs
-
-This lint detects missing documentation for public items. Some example code
-that triggers this lint:
-
-```rust
-pub fn foo() {}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: missing documentation for crate
- --> src/main.rs:1:1
-  |
-1 | / #![deny(missing_docs)]
-2 | |
-3 | | pub fn foo() {}
-4 | |
-5 | | fn main() {}
-  | |____________^
-  |
-
-error: missing documentation for a function
- --> src/main.rs:3:1
-  |
-3 | pub fn foo() {}
-  | ^^^^^^^^^^^^
-
-```
-
-To fix the lint, add documentation to all items.
-
-## single-use-lifetimes
-
-This lint detects lifetimes that are only used once. Some example code that
-triggers this lint:
-
-```rust
-struct Foo<'x> {
-    x: &'x u32
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: lifetime name `'x` only used once
- --> src/main.rs:3:12
-  |
-3 | struct Foo<'x> {
-  |            ^^
-  |
-```
-
-## trivial-casts
-
-This lint detects trivial casts which could be replaced with coercion, which may require
-type ascription or a temporary variable. Some example code
-that triggers this lint:
-
-```rust
-let x: &u32 = &42;
-let _ = x as *const u32;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: trivial cast: `&u32` as `*const u32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
- --> src/main.rs:5:13
-  |
-5 |     let _ = x as *const u32;
-  |             ^^^^^^^^^^^^^^^
-  |
-note: lint level defined here
- --> src/main.rs:1:9
-  |
-1 | #![deny(trivial_casts)]
-  |         ^^^^^^^^^^^^^
-```
-
-## trivial-numeric-casts
-
-This lint detects trivial casts of numeric types which could be removed. Some
-example code that triggers this lint:
-
-```rust
-let x = 42i32 as i32;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: trivial numeric cast: `i32` as `i32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable
- --> src/main.rs:4:13
-  |
-4 |     let x = 42i32 as i32;
-  |             ^^^^^^^^^^^^
-  |
-```
-
-## unreachable-pub
-
-This lint triggers for `pub` items not reachable from the crate root. Some
-example code that triggers this lint:
-
-```rust
-mod foo {
-    pub mod bar {
-        
-    }
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unreachable `pub` item
- --> src/main.rs:4:5
-  |
-4 |     pub mod bar {
-  |     ---^^^^^^^^
-  |     |
-  |     help: consider restricting its visibility: `pub(crate)`
-  |
-```
-
-## unsafe-code
-
-This lint catches usage of `unsafe` code. Some example code that triggers this lint:
-
-```rust
-fn main() {
-    unsafe {
-
-    }
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: usage of an `unsafe` block
- --> src/main.rs:4:5
-  |
-4 | /     unsafe {
-5 | |         
-6 | |     }
-  | |_____^
-  |
-```
-
-## unstable-features
-
-This lint is deprecated and no longer used.
-
-## unused-extern-crates
-
-This lint guards against `extern crate` items that are never used. Some
-example code that triggers this lint:
-
-```rust,ignore
-extern crate semver;
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unused extern crate
- --> src/main.rs:3:1
-  |
-3 | extern crate semver;
-  | ^^^^^^^^^^^^^^^^^^^^
-  |
-```
-
-## unused-import-braces
-
-This lint catches unnecessary braces around an imported item. Some example
-code that triggers this lint:
-
-```rust
-use test::{A};
-
-pub mod test {
-    pub struct A;
-}
-# fn main() {}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: braces around A is unnecessary
- --> src/main.rs:3:1
-  |
-3 | use test::{A};
-  | ^^^^^^^^^^^^^^
-  |
-```
-
-To fix it, `use test::A;`
-
-## unused-qualifications
-
-This lint detects unnecessarily qualified names. Some example code that triggers this lint:
-
-```rust
-mod foo {
-    pub fn bar() {}
-}
-
-fn main() {
-    use foo::bar;
-    foo::bar();
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unnecessary qualification
- --> src/main.rs:9:5
-  |
-9 |     foo::bar();
-  |     ^^^^^^^^
-  |
-```
-
-You can call `bar()` directly, without the `foo::`.
-
-## unused-results
-
-This lint checks for the unused result of an expression in a statement. Some
-example code that triggers this lint:
-
-```rust,no_run
-fn foo<T>() -> T { panic!() }
-
-fn main() {
-    foo::<usize>();
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: unused result
- --> src/main.rs:6:5
-  |
-6 |     foo::<usize>();
-  |     ^^^^^^^^^^^^^^^
-  |
-```
-
-## variant-size-differences
-
-This lint detects enums with widely varying variant sizes. Some example code that triggers this lint:
-
-```rust
-enum En {
-    V0(u8),
-    VBig([u8; 1024]),
-}
-```
-
-When set to 'deny', this will produce:
-
-```text
-error: enum variant is more than three times larger (1024 bytes) than the next largest
- --> src/main.rs:5:5
-  |
-5 |     VBig([u8; 1024]),   //~ ERROR variant is more than three times larger
-  |     ^^^^^^^^^^^^^^^^
-  |
-```
+This file is auto-generated by the lint-docs script.
diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md
index 55714f8f454..3c1452d6467 100644
--- a/src/doc/rustc/src/lints/listing/deny-by-default.md
+++ b/src/doc/rustc/src/lints/listing/deny-by-default.md
@@ -1,203 +1,3 @@
 # Deny-by-default lints
 
-These lints are all set to the 'deny' level by default.
-
-## exceeding-bitshifts
-
-This lint detects that a shift exceeds the type's number of bits. Some
-example code that triggers this lint:
-
-```rust,ignore
-1_i32 << 32;
-```
-
-This will produce:
-
-```text
-error: bitshift exceeds the type's number of bits
- --> src/main.rs:2:5
-  |
-2 |     1_i32 << 32;
-  |     ^^^^^^^^^^^
-  |
-```
-
-## invalid-type-param-default
-
-This lint detects type parameter default erroneously allowed in invalid location. Some
-example code that triggers this lint:
-
-```rust,ignore
-fn foo<T=i32>(t: T) {}
-```
-
-This will produce:
-
-```text
-error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions.
- --> src/main.rs:4:8
-  |
-4 | fn foo<T=i32>(t: T) {}
-  |        ^
-  |
-  = note: `#[deny(invalid_type_param_default)]` on by default
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-  = note: for more information, see issue #36887 <https://github.com/rust-lang/rust/issues/36887>
-```
-
-## mutable-transmutes
-
-This lint catches transmuting from `&T` to `&mut T` because it is undefined
-behavior. Some example code that triggers this lint:
-
-```rust,ignore
-unsafe {
-    let y = std::mem::transmute::<&i32, &mut i32>(&5);
-}
-```
-
-This will produce:
-
-```text
-error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell
- --> src/main.rs:3:17
-  |
-3 |         let y = std::mem::transmute::<&i32, &mut i32>(&5);
-  |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-```
-
-
-## no-mangle-const-items
-
-This lint detects any `const` items with the `#[no_mangle]` attribute.
-Constants do not have their symbols exported, and therefore, this probably
-means you meant to use a `static`, not a `const`. Some example code that
-triggers this lint:
-
-```rust,ignore
-#[no_mangle]
-const FOO: i32 = 5;
-```
-
-This will produce:
-
-```text
-error: const items should never be `#[no_mangle]`
- --> src/main.rs:3:1
-  |
-3 | const FOO: i32 = 5;
-  | -----^^^^^^^^^^^^^^
-  | |
-  | help: try a static value: `pub static`
-  |
-```
-
-## overflowing-literals
-
-This lint detects literal out of range for its type. Some
-example code that triggers this lint:
-
-```rust,compile_fail
-let x: u8 = 1000;
-```
-
-This will produce:
-
-```text
-error: literal out of range for u8
- --> src/main.rs:2:17
-  |
-2 |     let x: u8 = 1000;
-  |                 ^^^^
-  |
-```
-
-## patterns-in-fns-without-body
-
-This lint detects patterns in functions without body were that were
-previously erroneously allowed. Some example code that triggers this lint:
-
-```rust,compile_fail
-trait Trait {
-    fn foo(mut arg: u8);
-}
-```
-
-This will produce:
-
-```text
-warning: patterns aren't allowed in methods without bodies
- --> src/main.rs:2:12
-  |
-2 |     fn foo(mut arg: u8);
-  |            ^^^^^^^
-  |
-  = note: `#[warn(patterns_in_fns_without_body)]` on by default
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-  = note: for more information, see issue #35203 <https://github.com/rust-lang/rust/issues/35203>
-```
-
-To fix this, remove the pattern; it can be used in the implementation without
-being used in the definition. That is:
-
-```rust
-trait Trait {
-    fn foo(arg: u8);
-}
-
-impl Trait for i32 {
-    fn foo(mut arg: u8) {
-
-    }
-}
-```
-
-## pub-use-of-private-extern-crate
-
-This lint detects a specific situation of re-exporting a private `extern crate`;
-
-## unknown-crate-types
-
-This lint detects an unknown crate type found in a `#[crate_type]` directive. Some
-example code that triggers this lint:
-
-```rust,ignore
-#![crate_type="lol"]
-```
-
-This will produce:
-
-```text
-error: invalid `crate_type` value
- --> src/lib.rs:1:1
-  |
-1 | #![crate_type="lol"]
-  | ^^^^^^^^^^^^^^^^^^^^
-  |
-```
-
-## const-err
-
-This lint detects expressions that will always panic at runtime and would be an
-error in a `const` context.
-
-```rust,ignore
-let _ = [0; 4][4];
-```
-
-This will produce:
-
-```text
-error: index out of bounds: the len is 4 but the index is 4
- --> src/lib.rs:1:9
-  |
-1 | let _ = [0; 4][4];
-  |         ^^^^^^^^^
-  |
-```
-
-## order-dependent-trait-objects
-
-This lint detects a trait coherency violation that would allow creating two
-trait impls for the same dynamic trait object involving marker traits.
+This file is auto-generated by the lint-docs script.
diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md
index 386f6008d06..eebc022a82b 100644
--- a/src/doc/rustc/src/lints/listing/warn-by-default.md
+++ b/src/doc/rustc/src/lints/listing/warn-by-default.md
@@ -1,903 +1,3 @@
 # Warn-by-default lints
 
-These lints are all set to the 'warn' level by default.
-
-## const-err
-
-This lint detects an erroneous expression while doing constant evaluation. Some
-example code that triggers this lint:
-
-```rust,ignore
-let b = 200u8 + 200u8;
-```
-
-This will produce:
-
-```text
-warning: attempt to add with overflow
- --> src/main.rs:2:9
-  |
-2 | let b = 200u8 + 200u8;
-  |         ^^^^^^^^^^^^^
-  |
-```
-
-## dead-code
-
-This lint detects unused, unexported items. Some
-example code that triggers this lint:
-
-```rust
-fn foo() {}
-```
-
-This will produce:
-
-```text
-warning: function is never used: `foo`
- --> src/lib.rs:2:1
-  |
-2 | fn foo() {}
-  | ^^^^^^^^
-  |
-```
-
-## deprecated
-
-This lint detects use of deprecated items. Some
-example code that triggers this lint:
-
-```rust
-#[deprecated]
-fn foo() {}
-
-fn bar() {
-    foo();
-}
-```
-
-This will produce:
-
-```text
-warning: use of deprecated item 'foo'
- --> src/lib.rs:7:5
-  |
-7 |     foo();
-  |     ^^^
-  |
-```
-
-## illegal-floating-point-literal-pattern
-
-This lint detects floating-point literals used in patterns. Some example code
-that triggers this lint:
-
-```rust
-let x = 42.0;
-
-match x {
-    5.0 => {},
-    _ => {},
-}
-```
-
-This will produce:
-
-```text
-warning: floating-point literals cannot be used in patterns
- --> src/main.rs:4:9
-  |
-4 |         5.0 => {},
-  |         ^^^
-  |
-  = note: `#[warn(illegal_floating_point_literal_pattern)]` on by default
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-  = note: for more information, see issue #41620 <https://github.com/rust-lang/rust/issues/41620>
-```
-
-## improper-ctypes
-
-This lint detects proper use of libc types in foreign modules. Some
-example code that triggers this lint:
-
-```rust
-extern "C" {
-    static STATIC: String;
-}
-```
-
-This will produce:
-
-```text
-warning: found struct without foreign-function-safe representation annotation in foreign module, consider adding a `#[repr(C)]` attribute to the type
- --> src/main.rs:2:20
-  |
-2 |     static STATIC: String;
-  |                    ^^^^^^
-  |
-```
-
-## late-bound-lifetime-arguments
-
-This lint detects generic lifetime arguments in path segments with
-late bound lifetime parameters. Some example code that triggers this lint:
-
-```rust
-struct S;
-
-impl S {
-    fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
-}
-
-fn main() {
-    S.late::<'static>(&0, &0);
-}
-```
-
-This will produce:
-
-```text
-warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present
- --> src/main.rs:8:14
-  |
-4 |     fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {}
-  |             -- the late bound lifetime parameter is introduced here
-...
-8 |     S.late::<'static>(&0, &0);
-  |              ^^^^^^^
-  |
-  = note: `#[warn(late_bound_lifetime_arguments)]` on by default
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-  = note: for more information, see issue #42868 <https://github.com/rust-lang/rust/issues/42868>
-```
-
-## non-camel-case-types
-
-This lint detects types, variants, traits and type parameters that don't have
-camel case names. Some example code that triggers this lint:
-
-```rust
-struct s;
-```
-
-This will produce:
-
-```text
-warning: type `s` should have a camel case name such as `S`
- --> src/main.rs:1:1
-  |
-1 | struct s;
-  | ^^^^^^^^^
-  |
-```
-
-## non-shorthand-field-patterns
-
-This lint detects using `Struct { x: x }` instead of `Struct { x }` in a pattern. Some
-example code that triggers this lint:
-
-```rust
-struct Point {
-    x: i32,
-    y: i32,
-}
-
-
-fn main() {
-    let p = Point {
-        x: 5,
-        y: 5,
-    };
-
-    match p {
-        Point { x: x, y: y } => (),
-    }
-}
-```
-
-This will produce:
-
-```text
-warning: the `x:` in this pattern is redundant
-  --> src/main.rs:14:17
-   |
-14 |         Point { x: x, y: y } => (),
-   |                 --^^
-   |                 |
-   |                 help: remove this
-   |
-
-warning: the `y:` in this pattern is redundant
-  --> src/main.rs:14:23
-   |
-14 |         Point { x: x, y: y } => (),
-   |                       --^^
-   |                       |
-   |                       help: remove this
-
-```
-
-## non-snake-case
-
-This lint detects variables, methods, functions, lifetime parameters and
-modules that don't have snake case names. Some example code that triggers
-this lint:
-
-```rust
-let X = 5;
-```
-
-This will produce:
-
-```text
-warning: variable `X` should have a snake case name such as `x`
- --> src/main.rs:2:9
-  |
-2 |     let X = 5;
-  |         ^
-  |
-```
-
-## non-upper-case-globals
-
-This lint detects static constants that don't have uppercase identifiers.
-Some example code that triggers this lint:
-
-```rust
-static x: i32 = 5;
-```
-
-This will produce:
-
-```text
-warning: static variable `x` should have an upper case name such as `X`
- --> src/main.rs:1:1
-  |
-1 | static x: i32 = 5;
-  | ^^^^^^^^^^^^^^^^^^
-  |
-```
-
-## no-mangle-generic-items
-
-This lint detects generic items must be mangled. Some
-example code that triggers this lint:
-
-```rust
-#[no_mangle]
-fn foo<T>(t: T) {
-
-}
-```
-
-This will produce:
-
-```text
-warning: functions generic over types must be mangled
- --> src/main.rs:2:1
-  |
-1 |   #[no_mangle]
-  |   ------------ help: remove this attribute
-2 | / fn foo<T>(t: T) {
-3 | |
-4 | | }
-  | |_^
-  |
-```
-
-## path-statements
-
-This lint detects path statements with no effect. Some example code that
-triggers this lint:
-
-```rust
-let x = 42;
-
-x;
-```
-
-This will produce:
-
-```text
-warning: path statement with no effect
- --> src/main.rs:3:5
-  |
-3 |     x;
-  |     ^^
-  |
-```
-
-## private-in-public
-
-This lint detects private items in public interfaces not caught by the old implementation. Some
-example code that triggers this lint:
-
-```rust,ignore
-pub trait Trait {
-    type A;
-}
-
-pub struct S;
-
-mod foo {
-    struct Z;
-
-    impl ::Trait for ::S {
-        type A = Z;
-    }
-}
-# fn main() {}
-```
-
-This will produce:
-
-```text
-error[E0446]: private type `foo::Z` in public interface
-  --> src/main.rs:11:9
-   |
-11 |         type A = Z;
-   |         ^^^^^^^^^^^ can't leak private type
-```
-
-## private-no-mangle-fns
-
-This lint detects functions marked `#[no_mangle]` that are also private.
-Given that private functions aren't exposed publicly, and `#[no_mangle]`
-controls the public symbol, this combination is erroneous. Some example code
-that triggers this lint:
-
-```rust
-#[no_mangle]
-fn foo() {}
-```
-
-This will produce:
-
-```text
-warning: function is marked `#[no_mangle]`, but not exported
- --> src/main.rs:2:1
-  |
-2 | fn foo() {}
-  | -^^^^^^^^^^
-  | |
-  | help: try making it public: `pub`
-  |
-```
-
-To fix this, either make it public or remove the `#[no_mangle]`.
-
-## private-no-mangle-statics
-
-This lint detects any statics marked `#[no_mangle]` that are private.
-Given that private statics aren't exposed publicly, and `#[no_mangle]`
-controls the public symbol, this combination is erroneous. Some example code
-that triggers this lint:
-
-```rust
-#[no_mangle]
-static X: i32 = 4;
-```
-
-This will produce:
-
-```text
-warning: static is marked `#[no_mangle]`, but not exported
- --> src/main.rs:2:1
-  |
-2 | static X: i32 = 4;
-  | -^^^^^^^^^^^^^^^^^
-  | |
-  | help: try making it public: `pub`
-  |
-```
-
-To fix this, either make it public or remove the `#[no_mangle]`.
-
-## renamed-and-removed-lints
-
-This lint detects lints that have been renamed or removed. Some
-example code that triggers this lint:
-
-```rust
-#![deny(raw_pointer_derive)]
-```
-
-This will produce:
-
-```text
-warning: lint raw_pointer_derive has been removed: using derive with raw pointers is ok
- --> src/main.rs:1:9
-  |
-1 | #![deny(raw_pointer_derive)]
-  |         ^^^^^^^^^^^^^^^^^^
-  |
-```
-
-To fix this, either remove the lint or use the new name.
-
-## safe-packed-borrows
-
-This lint detects borrowing a field in the interior of a packed structure
-with alignment other than 1. Some example code that triggers this lint:
-
-```rust
-#[repr(packed)]
-pub struct Unaligned<T>(pub T);
-
-pub struct Foo {
-    start: u8,
-    data: Unaligned<u32>,
-}
-
-fn main() {
-    let x = Foo { start: 0, data: Unaligned(1) };
-    let y = &x.data.0;
-}
-```
-
-This will produce:
-
-```text
-warning: borrow of packed field requires unsafe function or block (error E0133)
-  --> src/main.rs:11:13
-   |
-11 |     let y = &x.data.0;
-   |             ^^^^^^^^^
-   |
-   = note: `#[warn(safe_packed_borrows)]` on by default
-   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
-```
-
-## stable-features
-
-This lint detects a `#[feature]` attribute that's since been made stable. Some
-example code that triggers this lint:
-
-```rust
-#![feature(test_accepted_feature)]
-```
-
-This will produce:
-
-```text
-warning: this feature has been stable since 1.0.0. Attribute no longer needed
- --> src/main.rs:1:12
-  |
-1 | #![feature(test_accepted_feature)]
-  |            ^^^^^^^^^^^^^^^^^^^^^
-  |
-```
-
-To fix, simply remove the `#![feature]` attribute, as it's no longer needed.
-
-## type-alias-bounds
-
-This lint detects bounds in type aliases. These are not currently enforced.
-Some example code that triggers this lint:
-
-```rust
-#[allow(dead_code)]
-type SendVec<T: Send> = Vec<T>;
-```
-
-This will produce:
-
-```text
-warning: bounds on generic parameters are not enforced in type aliases
- --> src/lib.rs:2:17
-  |
-2 | type SendVec<T: Send> = Vec<T>;
-  |                 ^^^^
-  |
-  = note: `#[warn(type_alias_bounds)]` on by default
-  = help: the bound will not be checked when the type alias is used, and should be removed
-```
-
-## tyvar-behind-raw-pointer
-
-This lint detects raw pointer to an inference variable. Some
-example code that triggers this lint:
-
-```rust
-let data = std::ptr::null();
-let _ = &data as *const *const ();
-
-if data.is_null() {}
-```
-
-This will produce:
-
-```text
-warning: type annotations needed
- --> src/main.rs:4:13
-  |
-4 |     if data.is_null() {}
-  |             ^^^^^^^
-  |
-  = note: `#[warn(tyvar_behind_raw_pointer)]` on by default
-  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition!
-  = note: for more information, see issue #46906 <https://github.com/rust-lang/rust/issues/46906>
-```
-
-## unconditional-recursion
-
-This lint detects functions that cannot return without calling themselves.
-Some example code that triggers this lint:
-
-```rust
-fn foo() {
-    foo();
-}
-```
-
-This will produce:
-
-```text
-warning: function cannot return without recursing
- --> src/main.rs:1:1
-  |
-1 | fn foo() {
-  | ^^^^^^^^ cannot return without recursing
-2 |     foo();
-  |     ----- recursive call site
-  |
-```
-
-## unknown-lints
-
-This lint detects unrecognized lint attribute. Some
-example code that triggers this lint:
-
-```rust,ignore
-#[allow(not_a_real_lint)]
-```
-
-This will produce:
-
-```text
-warning: unknown lint: `not_a_real_lint`
- --> src/main.rs:1:10
-  |
-1 | #![allow(not_a_real_lint)]
-  |          ^^^^^^^^^^^^^^^
-  |
-```
-
-## unreachable-code
-
-This lint detects unreachable code paths. Some example code that
-triggers this lint:
-
-```rust,no_run
-panic!("we never go past here!");
-
-let x = 5;
-```
-
-This will produce:
-
-```text
-warning: unreachable statement
- --> src/main.rs:4:5
-  |
-4 |     let x = 5;
-  |     ^^^^^^^^^^
-  |
-```
-
-## unreachable-patterns
-
-This lint detects unreachable patterns. Some
-example code that triggers this lint:
-
-```rust
-let x = 5;
-match x {
-    y => (),
-    5 => (),
-}
-```
-
-This will produce:
-
-```text
-warning: unreachable pattern
- --> src/main.rs:5:5
-  |
-5 |     5 => (),
-  |     ^
-  |
-```
-
-The `y` pattern will always match, so the five is impossible to reach.
-Remember, match arms match in order, you probably wanted to put the `5` case
-above the `y` case.
-
-## unstable-name-collision
-
-This lint detects that you've used a name that the standard library plans to
-add in the future, which means that your code may fail to compile without
-additional type annotations in the future. Either rename, or add those
-annotations now.
-
-## unused-allocation
-
-This lint detects unnecessary allocations that can be eliminated.
-
-## unused-assignments
-
-This lint detects assignments that will never be read. Some
-example code that triggers this lint:
-
-```rust
-let mut x = 5;
-x = 6;
-```
-
-This will produce:
-
-```text
-warning: value assigned to `x` is never read
- --> src/main.rs:4:5
-  |
-4 |     x = 6;
-  |     ^
-  |
-```
-
-## unused-attributes
-
-This lint detects attributes that were not used by the compiler. Some
-example code that triggers this lint:
-
-```rust
-#![macro_export]
-```
-
-This will produce:
-
-```text
-warning: unused attribute
- --> src/main.rs:1:1
-  |
-1 | #![macro_export]
-  | ^^^^^^^^^^^^^^^^
-  |
-```
-
-## unused-comparisons
-
-This lint detects comparisons made useless by limits of the types involved. Some
-example code that triggers this lint:
-
-```rust
-fn foo(x: u8) {
-    x >= 0;
-}
-```
-
-This will produce:
-
-```text
-warning: comparison is useless due to type limits
- --> src/main.rs:6:5
-  |
-6 |     x >= 0;
-  |     ^^^^^^
-  |
-```
-
-## unused-doc-comment
-
-This lint detects doc comments that aren't used by rustdoc. Some
-example code that triggers this lint:
-
-```rust
-/// docs for x
-let x = 12;
-```
-
-This will produce:
-
-```text
-warning: doc comment not used by rustdoc
- --> src/main.rs:2:5
-  |
-2 |     /// docs for x
-  |     ^^^^^^^^^^^^^^
-  |
-```
-
-## unused-features
-
-This lint detects unused or unknown features found in crate-level `#[feature]` directives.
-To fix this, simply remove the feature flag.
-
-## unused-imports
-
-This lint detects imports that are never used. Some
-example code that triggers this lint:
-
-```rust
-use std::collections::HashMap;
-```
-
-This will produce:
-
-```text
-warning: unused import: `std::collections::HashMap`
- --> src/main.rs:1:5
-  |
-1 | use std::collections::HashMap;
-  |     ^^^^^^^^^^^^^^^^^^^^^^^^^
-  |
-```
-
-## unused-macros
-
-This lint detects macros that were not used. Some example code that
-triggers this lint:
-
-```rust
-macro_rules! unused {
-    () => {};
-}
-
-fn main() {
-}
-```
-
-This will produce:
-
-```text
-warning: unused macro definition
- --> src/main.rs:1:1
-  |
-1 | / macro_rules! unused {
-2 | |     () => {};
-3 | | }
-  | |_^
-  |
-```
-
-## unused-must-use
-
-This lint detects unused result of a type flagged as `#[must_use]`. Some
-example code that triggers this lint:
-
-```rust
-fn returns_result() -> Result<(), ()> {
-    Ok(())
-}
-
-fn main() {
-    returns_result();
-}
-```
-
-This will produce:
-
-```text
-warning: unused `std::result::Result` that must be used
- --> src/main.rs:6:5
-  |
-6 |     returns_result();
-  |     ^^^^^^^^^^^^^^^^^
-  |
-```
-
-## unused-mut
-
-This lint detects mut variables which don't need to be mutable. Some
-example code that triggers this lint:
-
-```rust
-let mut x = 5;
-```
-
-This will produce:
-
-```text
-warning: variable does not need to be mutable
- --> src/main.rs:2:9
-  |
-2 |     let mut x = 5;
-  |         ----^
-  |         |
-  |         help: remove this `mut`
-  |
-```
-
-## unused-parens
-
-This lint detects `if`, `match`, `while` and `return` with parentheses; they
-do not need them. Some example code that triggers this lint:
-
-```rust
-if(true) {}
-```
-
-This will produce:
-
-```text
-warning: unnecessary parentheses around `if` condition
- --> src/main.rs:2:7
-  |
-2 |     if(true) {}
-  |       ^^^^^^ help: remove these parentheses
-  |
-```
-
-## unused-unsafe
-
-This lint detects unnecessary use of an `unsafe` block. Some
-example code that triggers this lint:
-
-```rust
-unsafe {}
-```
-
-This will produce:
-
-```text
-warning: unnecessary `unsafe` block
- --> src/main.rs:2:5
-  |
-2 |     unsafe {}
-  |     ^^^^^^ unnecessary `unsafe` block
-  |
-```
-
-## unused-variables
-
-This lint detects variables which are not used in any way. Some
-example code that triggers this lint:
-
-```rust
-let x = 5;
-```
-
-This will produce:
-
-```text
-warning: unused variable: `x`
- --> src/main.rs:2:9
-  |
-2 |     let x = 5;
-  |         ^ help: consider using `_x` instead
-  |
-```
-
-## warnings
-
-This lint is a bit special; by changing its level, you change every other warning
-that would produce a warning to whatever value you'd like:
-
-```rust
-#![deny(warnings)]
-```
-
-As such, you won't ever trigger this lint in your code directly.
-
-## while-true
-
-This lint detects `while true { }`. Some example code that triggers this
-lint:
-
-```rust,no_run
-while true {
-
-}
-```
-
-This will produce:
-
-```text
-warning: denote infinite loops with `loop { ... }`
- --> src/main.rs:2:5
-  |
-2 |     while true {
-  |     ^^^^^^^^^^ help: use `loop`
-  |
-```
+This file is auto-generated by the lint-docs script.
diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml
new file mode 100644
index 00000000000..657b115671e
--- /dev/null
+++ b/src/tools/lint-docs/Cargo.toml
@@ -0,0 +1,13 @@
+[package]
+name = "lint-docs"
+version = "0.1.0"
+authors = ["The Rust Project Developers"]
+edition = "2018"
+description = "A script to extract the lint documentation for the rustc book."
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+serde_json = "1.0.57"
+tempfile = "3.1.0"
+walkdir = "2.3.1"
diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs
new file mode 100644
index 00000000000..a212459bb4d
--- /dev/null
+++ b/src/tools/lint-docs/src/groups.rs
@@ -0,0 +1,114 @@
+use crate::Lint;
+use std::collections::{BTreeMap, BTreeSet};
+use std::error::Error;
+use std::fmt::Write;
+use std::fs;
+use std::path::Path;
+use std::process::Command;
+
+static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[
+    ("unused", "Lints that detect things being declared but not used, or excess syntax"),
+    ("rustdoc", "Rustdoc-specific lints"),
+    ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"),
+    ("nonstandard-style", "Violation of standard naming conventions"),
+    ("future-incompatible", "Lints that detect code that has future-compatibility problems"),
+    ("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_path: &Path,
+    out_path: &Path,
+) -> Result<(), Box<dyn Error>> {
+    let groups = collect_groups(rustc_path)?;
+    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: &Path) -> Result<LintGroups, Box<dyn Error>> {
+    let mut result = BTreeMap::new();
+    let mut cmd = Command::new(rustc);
+    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 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());
+    }
+    if result.is_empty() {
+        return Err(
+            format!("expected at least one group in -Whelp output, got:\n{}", stdout).into()
+        );
+    }
+    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();
+    }
+    Ok(result)
+}
diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs
new file mode 100644
index 00000000000..b1e14ea6c46
--- /dev/null
+++ b/src/tools/lint-docs/src/lib.rs
@@ -0,0 +1,463 @@
+use std::error::Error;
+use std::fmt::Write;
+use std::fs;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+use walkdir::WalkDir;
+
+mod groups;
+
+struct Lint {
+    name: String,
+    doc: Vec<String>,
+    level: Level,
+    path: PathBuf,
+    lineno: usize,
+}
+
+#[derive(Clone, Copy, PartialEq)]
+enum Level {
+    Allow,
+    Warn,
+    Deny,
+}
+
+impl Level {
+    fn doc_filename(&self) -> &str {
+        match self {
+            Level::Allow => "allowed-by-default.md",
+            Level::Warn => "warn-by-default.md",
+            Level::Deny => "deny-by-default.md",
+        }
+    }
+}
+
+/// Collects all lints, and writes the markdown documentation at the given directory.
+pub fn extract_lint_docs(
+    src_path: &Path,
+    out_path: &Path,
+    rustc_path: &Path,
+    rustdoc_path: &Path,
+    verbose: bool,
+) -> Result<(), Box<dyn Error>> {
+    let mut lints = gather_lints(src_path)?;
+    for lint in &mut lints {
+        generate_output_example(lint, rustc_path, rustdoc_path, verbose).map_err(|e| {
+            format!(
+                "failed to test example in lint docs for `{}` in {}:{}: {}",
+                lint.name,
+                lint.path.display(),
+                lint.lineno,
+                e
+            )
+        })?;
+    }
+    save_lints_markdown(&lints, &out_path.join("listing"))?;
+    groups::generate_group_docs(&lints, rustc_path, 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;
+        }
+        lints.extend(lints_from_file(entry.path())?);
+    }
+    if lints.is_empty() {
+        return Err("no lints were found!".into());
+    }
+    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;
+                    }
+                }
+                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 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() {
+                            return Err(format!(
+                                "did not find doc lines for lint `{}` in {}",
+                                name,
+                                path.display()
+                            )
+                            .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,
+                    _ => {
+                        return Err(format!(
+                            "unexpected lint level `{}` in {}:{}",
+                            line,
+                            path.display(),
+                            lineno
+                        )
+                        .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())
+        }
+        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_path: &Path,
+    rustdoc_path: &Path,
+    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"
+            | "unstable_features"
+            | "incomplete_include"
+            | "unused_crate_dependencies"
+            | "exported_private_dependencies"
+            | "proc_macro_derive_resolution_fallback"
+            | "macro_use_extern_crate"
+    ) {
+        return Ok(());
+    }
+    check_style(lint)?;
+    replace_produces(lint, rustc_path, rustdoc_path, 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 !lint.doc.iter().any(|line| line.contains(expected)) {
+            return Err(format!("lint docs should contain the line `{}`", expected).into());
+        }
+    }
+    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());
+        }
+    }
+    Ok(())
+}
+
+/// Mutates the lint docs to replace the `{{produces}}` marker with the actual
+/// output from the compiler.
+fn replace_produces(
+    lint: &mut Lint,
+    rustc_path: &Path,
+    rustdoc_path: &Path,
+    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<_>>();
+                }
+                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(()),
+            }
+        };
+        // 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_path,
+                        rustdoc_path,
+                        verbose,
+                    )?;
+                    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(()),
+            }
+        }
+    }
+}
+
+/// Runs the compiler against the example, and extracts the output.
+fn generate_lint_output(
+    name: &str,
+    example: &[&mut String],
+    options: &[&str],
+    rustc_path: &Path,
+    rustdoc_path: &Path,
+    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 is_rustdoc = options.contains(&"rustdoc");
+    let needs_main = !example.iter().any(|line| line.contains("fn main")) && !is_rustdoc;
+    // 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("#!") {
+            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')
+    }
+    if needs_main {
+        source.push_str("}\n");
+    }
+    fs::write(&tempfile, source)
+        .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?;
+    let program = if is_rustdoc { rustdoc_path } else { rustc_path };
+    let mut cmd = Command::new(program);
+    if options.contains(&"edition2015") {
+        cmd.arg("--edition=2015");
+    } else {
+        cmd.arg("--edition=2018");
+    }
+    cmd.arg("--error-format=json");
+    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();
+                    Err(format!(
+                        "did not find lint `{}` in output of example, got:\n{}",
+                        name,
+                        rendered.join("\n")
+                    )
+                    .into())
+                }
+            }
+        }
+    }
+}
+
+static ALLOWED_MD: &str = r#"# Allowed-by-default lints
+
+These lints are all set to the 'allow' level by default. As such, they won't show up
+unless you set them to a higher lint level with a flag or attribute.
+
+"#;
+
+static WARN_MD: &str = r#"# Warn-by-default lints
+
+These lints are all set to the 'warn' level by default.
+
+"#;
+
+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
new file mode 100644
index 00000000000..4b824596b46
--- /dev/null
+++ b/src/tools/lint-docs/src/main.rs
@@ -0,0 +1,67 @@
+use std::error::Error;
+use std::path::PathBuf;
+
+fn main() {
+    if let Err(e) = doit() {
+        println!("error: {}", e);
+        std::process::exit(1);
+    }
+}
+
+fn doit() -> Result<(), Box<dyn Error>> {
+    let mut args = std::env::args().skip(1);
+    let mut src_path = None;
+    let mut out_path = None;
+    let mut rustc_path = None;
+    let mut rustdoc_path = None;
+    let mut verbose = false;
+    while let Some(arg) = args.next() {
+        match arg.as_str() {
+            "--src" => {
+                src_path = match args.next() {
+                    Some(s) => Some(PathBuf::from(s)),
+                    None => return Err("--src requires a value".into()),
+                };
+            }
+            "--out" => {
+                out_path = match args.next() {
+                    Some(s) => Some(PathBuf::from(s)),
+                    None => return Err("--out requires a value".into()),
+                };
+            }
+            "--rustc" => {
+                rustc_path = match args.next() {
+                    Some(s) => Some(PathBuf::from(s)),
+                    None => return Err("--rustc requires a value".into()),
+                };
+            }
+            "--rustdoc" => {
+                rustdoc_path = match args.next() {
+                    Some(s) => Some(PathBuf::from(s)),
+                    None => return Err("--rustdoc requires a value".into()),
+                };
+            }
+            "-v" | "--verbose" => verbose = true,
+            s => return Err(format!("unexpected argument `{}`", s).into()),
+        }
+    }
+    if src_path.is_none() {
+        return Err("--src must be specified to the directory with the compiler source".into());
+    }
+    if out_path.is_none() {
+        return Err("--out must be specified to the directory with the lint listing docs".into());
+    }
+    if rustc_path.is_none() {
+        return Err("--rustc must be specified to the path of rustc".into());
+    }
+    if rustdoc_path.is_none() {
+        return Err("--rustdoc must be specified to the path of rustdoc".into());
+    }
+    lint_docs::extract_lint_docs(
+        &src_path.unwrap(),
+        &out_path.unwrap(),
+        &rustc_path.unwrap(),
+        &rustdoc_path.unwrap(),
+        verbose,
+    )
+}