about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-07-13 11:10:51 +0000
committerbors <bors@rust-lang.org>2022-07-13 11:10:51 +0000
commitca4e39400ef33198e2715973d1c67a1d3cee15e7 (patch)
treeef1ab0f047db44028413e3bdeb9ed024a8e4e491
parenta639f89d0414a34b7a72702849f3e9f95b46de5c (diff)
parentf290811aaf4a434d7bf25dda1ff16fa6bd930c8f (diff)
downloadrust-ca4e39400ef33198e2715973d1c67a1d3cee15e7.tar.gz
rust-ca4e39400ef33198e2715973d1c67a1d3cee15e7.zip
Auto merge of #99203 - GuillaumeGomez:rollup-b2re0dv, r=GuillaumeGomez
Rollup of 10 pull requests

Successful merges:

 - #98789 (rustdoc-json-types: Clean up derives.)
 - #98848 (Build the Clippy book as part of x.py doc)
 - #99020 (check non_exhaustive attr and private fields for transparent types)
 - #99132 (Add some autolabels for A-bootstrap and T-infra)
 - #99148 (Clarify that [iu]size bounds were only defined for the target arch)
 - #99152 (Use CSS variables to handle theming (part 2))
 - #99168 (Add regression test for #74713)
 - #99176 (:arrow_up: rust-analyzer)
 - #99183 (Mention rust-analyzer maintainers when `proc_macro` bridge is changed)
 - #99185 (llvm-wrapper: adapt for LLVM API change)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs55
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp6
-rw-r--r--compiler/rustc_typeck/src/check/check.rs71
-rw-r--r--library/core/src/num/int_macros.rs11
-rw-r--r--library/core/src/num/mod.rs38
-rw-r--r--library/core/src/num/uint_macros.rs7
-rw-r--r--src/bootstrap/builder.rs1
-rw-r--r--src/bootstrap/doc.rs1
-rw-r--r--src/doc/index.md4
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css29
-rw-r--r--src/librustdoc/html/static/css/themes/ayu.css58
-rw-r--r--src/librustdoc/html/static/css/themes/dark.css59
-rw-r--r--src/librustdoc/html/static/css/themes/light.css62
-rw-r--r--src/librustdoc/json/conversions.rs2
-rw-r--r--src/rustdoc-json-types/lib.rs88
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-74713.rs8
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/issue-74713.stderr22
-rw-r--r--src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs18
-rw-r--r--src/test/ui/repr/repr-transparent-non-exhaustive.rs96
-rw-r--r--src/test/ui/repr/repr-transparent-non-exhaustive.stderr127
-rw-r--r--src/tools/clippy/book/src/README.md2
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md33
-rw-r--r--src/tools/clippy/book/src/development/basics.md2
-rw-r--r--src/tools/clippy/book/src/development/common_tools_writing_lints.md2
-rw-r--r--src/tools/clippy/book/src/usage.md2
m---------src/tools/rust-analyzer14
-rw-r--r--triagebot.toml16
27 files changed, 571 insertions, 263 deletions
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 9fc2249b290..6d2cb63c1d7 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -3132,6 +3132,60 @@ declare_lint! {
     "detects unexpected names and values in `#[cfg]` conditions",
 }
 
+declare_lint! {
+    /// The `repr_transparent_external_private_fields` lint
+    /// detects types marked `#[repr(transparent)]` that (transitively)
+    /// contain an external ZST type marked `#[non_exhaustive]` or containing
+    /// private fields
+    ///
+    /// ### Example
+    ///
+    /// ```rust,ignore (needs external crate)
+    /// #![deny(repr_transparent_external_private_fields)]
+    /// use foo::NonExhaustiveZst;
+    ///
+    /// #[repr(transparent)]
+    /// struct Bar(u32, ([u32; 0], NonExhaustiveZst));
+    /// ```
+    ///
+    /// This will produce:
+    ///
+    /// ```text
+    /// error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+    ///  --> src/main.rs:5:28
+    ///   |
+    /// 5 | struct Bar(u32, ([u32; 0], NonExhaustiveZst));
+    ///   |                            ^^^^^^^^^^^^^^^^
+    ///   |
+    /// note: the lint level is defined here
+    ///  --> src/main.rs:1:9
+    ///   |
+    /// 1 | #![deny(repr_transparent_external_private_fields)]
+    ///   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+    ///   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+    ///   = note: this struct contains `NonExhaustiveZst`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+    /// ```
+    ///
+    /// ### Explanation
+    ///
+    /// Previous, Rust accepted fields that contain external private zero-sized types,
+    /// even though it should not be a breaking change to add a non-zero-sized field to
+    /// that private type.
+    ///
+    /// This is a [future-incompatible] lint to transition this
+    /// to a hard error in the future. See [issue #78586] for more details.
+    ///
+    /// [issue #78586]: https://github.com/rust-lang/rust/issues/78586
+    /// [future-incompatible]: ../index.md#future-incompatible-lints
+    pub REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
+    Warn,
+    "tranparent type contains an external ZST that is marked #[non_exhaustive] or contains private fields",
+    @future_incompatible = FutureIncompatibleInfo {
+        reference: "issue #78586 <https://github.com/rust-lang/rust/issues/78586>",
+    };
+}
+
 declare_lint_pass! {
     /// Does nothing as a lint pass, but registers some `Lint`s
     /// that are used by other parts of the compiler.
@@ -3237,6 +3291,7 @@ declare_lint_pass! {
         DEPRECATED_WHERE_CLAUSE_LOCATION,
         TEST_UNSTABLE_LINT,
         FFI_UNWIND_CALLS,
+        REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
     ]
 }
 
diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
index 8c5b4e2dc96..7ac3157e7a1 100644
--- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp
@@ -411,8 +411,14 @@ LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen,
 
 extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,
                                         size_t ConstraintsLen) {
+#if LLVM_VERSION_LT(15, 0)
   return InlineAsm::Verify(unwrap<FunctionType>(Ty),
                            StringRef(Constraints, ConstraintsLen));
+#else
+  // llvm::Error converts to true if it is an error.
+  return !llvm::errorToBool(InlineAsm::verify(
+      unwrap<FunctionType>(Ty), StringRef(Constraints, ConstraintsLen)));
+#endif
 }
 
 extern "C" void LLVMRustAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm,
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index e9709b64d93..79edbeab9c7 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -17,6 +17,7 @@ use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
+use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::subst::GenericArgKind;
@@ -1318,7 +1319,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
         }
     }
 
-    // For each field, figure out if it's known to be a ZST and align(1)
+    // For each field, figure out if it's known to be a ZST and align(1), with "known"
+    // respecting #[non_exhaustive] attributes.
     let field_infos = adt.all_fields().map(|field| {
         let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did));
         let param_env = tcx.param_env(field.did);
@@ -1327,16 +1329,56 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
         let span = tcx.hir().span_if_local(field.did).unwrap();
         let zst = layout.map_or(false, |layout| layout.is_zst());
         let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1);
-        (span, zst, align1)
+        if !zst {
+            return (span, zst, align1, None);
+        }
+
+        fn check_non_exhaustive<'tcx>(
+            tcx: TyCtxt<'tcx>,
+            t: Ty<'tcx>,
+        ) -> ControlFlow<(&'static str, DefId, SubstsRef<'tcx>, bool)> {
+            match t.kind() {
+                ty::Tuple(list) => list.iter().try_for_each(|t| check_non_exhaustive(tcx, t)),
+                ty::Array(ty, _) => check_non_exhaustive(tcx, *ty),
+                ty::Adt(def, subst) => {
+                    if !def.did().is_local() {
+                        let non_exhaustive = def.is_variant_list_non_exhaustive()
+                            || def
+                                .variants()
+                                .iter()
+                                .any(ty::VariantDef::is_field_list_non_exhaustive);
+                        let has_priv = def.all_fields().any(|f| !f.vis.is_public());
+                        if non_exhaustive || has_priv {
+                            return ControlFlow::Break((
+                                def.descr(),
+                                def.did(),
+                                subst,
+                                non_exhaustive,
+                            ));
+                        }
+                    }
+                    def.all_fields()
+                        .map(|field| field.ty(tcx, subst))
+                        .try_for_each(|t| check_non_exhaustive(tcx, t))
+                }
+                _ => ControlFlow::Continue(()),
+            }
+        }
+
+        (span, zst, align1, check_non_exhaustive(tcx, ty).break_value())
     });
 
-    let non_zst_fields =
-        field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None });
+    let non_zst_fields = field_infos
+        .clone()
+        .filter_map(|(span, zst, _align1, _non_exhaustive)| if !zst { Some(span) } else { None });
     let non_zst_count = non_zst_fields.clone().count();
     if non_zst_count >= 2 {
         bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp);
     }
-    for (span, zst, align1) in field_infos {
+    let incompatible_zst_fields =
+        field_infos.clone().filter(|(_, _, _, opt)| opt.is_some()).count();
+    let incompat = incompatible_zst_fields + non_zst_count >= 2 && non_zst_count < 2;
+    for (span, zst, align1, non_exhaustive) in field_infos {
         if zst && !align1 {
             struct_span_err!(
                 tcx.sess,
@@ -1348,6 +1390,25 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: ty::AdtD
             .span_label(span, "has alignment larger than 1")
             .emit();
         }
+        if incompat && let Some((descr, def_id, substs, non_exhaustive)) = non_exhaustive {
+            tcx.struct_span_lint_hir(
+                REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
+                tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()),
+                span,
+                |lint| {
+                    let note = if non_exhaustive {
+                        "is marked with `#[non_exhaustive]`"
+                    } else {
+                        "contains private fields"
+                    };
+                    let field_ty = tcx.def_path_str_with_substs(def_id, substs);
+                    lint.build("zero-sized fields in repr(transparent) cannot contain external non-exhaustive types")
+                        .note(format!("this {descr} contains `{field_ty}`, which {note}, \
+                            and makes it not a breaking change to become non-zero-sized in the future."))
+                        .emit();
+                },
+            )
+        }
     }
 }
 
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 1f435784be1..147f04a3f12 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -2,9 +2,10 @@ macro_rules! int_impl {
     ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $BITS_MINUS_ONE:expr, $Min:expr, $Max:expr,
      $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
      $reversed:expr, $le_bytes:expr, $be_bytes:expr,
-     $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
-        /// The smallest value that can be represented by this integer type,
-        #[doc = concat!("&minus;2<sup>", $BITS_MINUS_ONE, "</sup>.")]
+     $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr,
+     $bound_condition:expr) => {
+        /// The smallest value that can be represented by this integer type
+        #[doc = concat!("(&minus;2<sup>", $BITS_MINUS_ONE, "</sup>", $bound_condition, ")")]
         ///
         /// # Examples
         ///
@@ -16,8 +17,8 @@ macro_rules! int_impl {
         #[stable(feature = "assoc_int_consts", since = "1.43.0")]
         pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self;
 
-        /// The largest value that can be represented by this integer type,
-        #[doc = concat!("2<sup>", $BITS_MINUS_ONE, "</sup> &minus; 1.")]
+        /// The largest value that can be represented by this integer type
+        #[doc = concat!("(2<sup>", $BITS_MINUS_ONE, "</sup> &minus; 1", $bound_condition, ")")]
         ///
         /// # Examples
         ///
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 66193eaf5da..f481399fdcf 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -196,25 +196,25 @@ macro_rules! widening_impl {
 
 impl i8 {
     int_impl! { i8, i8, u8, 8, 7, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48",
-    "[0x12]", "[0x12]", "", "" }
+    "[0x12]", "[0x12]", "", "", "" }
 }
 
 impl i16 {
     int_impl! { i16, i16, u16, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412",
-    "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
+    "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "", "" }
 }
 
 impl i32 {
     int_impl! { i32, i32, u32, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
     "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
-    "[0x12, 0x34, 0x56, 0x78]", "", "" }
+    "[0x12, 0x34, 0x56, 0x78]", "", "", "" }
 }
 
 impl i64 {
     int_impl! { i64, i64, u64, 64, 63, -9223372036854775808, 9223372036854775807, 12,
     "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412",
     "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
-    "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" }
+    "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "", "" }
 }
 
 impl i128 {
@@ -225,14 +225,15 @@ impl i128 {
     "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
       0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \
-      0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "" }
+      0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]", "", "", "" }
 }
 
 #[cfg(target_pointer_width = "16")]
 impl isize {
     int_impl! { isize, i16, usize, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234",
     "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]",
-    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(),
+    " on 16-bit targets" }
 }
 
 #[cfg(target_pointer_width = "32")]
@@ -240,7 +241,8 @@ impl isize {
     int_impl! { isize, i32, usize, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301",
     "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78]",
-    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(),
+    " on 32-bit targets" }
 }
 
 #[cfg(target_pointer_width = "64")]
@@ -249,7 +251,8 @@ impl isize {
     12, "0xaa00000000006e1", "0x6e10aa",  "0x1234567890123456", "0x5634129078563412",
     "0x6a2c48091e6a2c48", "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
-    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(),
+    " on 64-bit targets" }
 }
 
 /// If 6th bit set ascii is upper case.
@@ -257,7 +260,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000;
 
 impl u8 {
     uint_impl! { u8, u8, i8, NonZeroU8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
-    "[0x12]", "", "" }
+    "[0x12]", "", "", "" }
     widening_impl! { u8, u16, 8, unsigned }
 
     /// Checks if the value is within the ASCII range.
@@ -810,7 +813,7 @@ impl u8 {
 
 impl u16 {
     uint_impl! { u16, u16, i16, NonZeroU16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
-    "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
+    "[0x34, 0x12]", "[0x12, 0x34]", "", "", "" }
     widening_impl! { u16, u32, 16, unsigned }
 
     /// Checks if the value is a Unicode surrogate code point, which are disallowed values for [`char`].
@@ -841,7 +844,7 @@ impl u16 {
 
 impl u32 {
     uint_impl! { u32, u32, i32, NonZeroU32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
-    "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
+    "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "", "" }
     widening_impl! { u32, u64, 32, unsigned }
 }
 
@@ -850,7 +853,7 @@ impl u64 {
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
-    "", ""}
+    "", "", ""}
     widening_impl! { u64, u128, 64, unsigned }
 }
 
@@ -862,21 +865,23 @@ impl u128 {
       0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56, \
       0x78, 0x90, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12]",
-     "", ""}
+     "", "", ""}
 }
 
 #[cfg(target_pointer_width = "16")]
 impl usize {
     uint_impl! { usize, u16, isize, NonZeroUsize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]",
-    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(),
+    " on 16-bit targets" }
     widening_impl! { usize, u32, 16, unsigned }
 }
 #[cfg(target_pointer_width = "32")]
 impl usize {
     uint_impl! { usize, u32, isize, NonZeroUsize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
     "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]",
-    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(),
+    " on 32-bit targets" }
     widening_impl! { usize, u64, 32, unsigned }
 }
 
@@ -886,7 +891,8 @@ impl usize {
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
-    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
+    usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!(),
+    " on 64-bit targets" }
     widening_impl! { usize, u128, 64, unsigned }
 }
 
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index cd4b0e18c4d..715e78350a4 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -3,7 +3,8 @@ macro_rules! uint_impl {
         $BITS:expr, $MaxV:expr,
         $rot:expr, $rot_op:expr, $rot_result:expr, $swap_op:expr, $swapped:expr,
         $reversed:expr, $le_bytes:expr, $be_bytes:expr,
-        $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr) => {
+        $to_xe_bytes_doc:expr, $from_xe_bytes_doc:expr,
+        $bound_condition:expr) => {
         /// The smallest value that can be represented by this integer type.
         ///
         /// # Examples
@@ -16,8 +17,8 @@ macro_rules! uint_impl {
         #[stable(feature = "assoc_int_consts", since = "1.43.0")]
         pub const MIN: Self = 0;
 
-        /// The largest value that can be represented by this integer type,
-        #[doc = concat!("2<sup>", $BITS, "</sup> &minus; 1.")]
+        /// The largest value that can be represented by this integer type
+        #[doc = concat!("(2<sup>", $BITS, "</sup> &minus; 1", $bound_condition, ")")]
         ///
         /// # Examples
         ///
diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs
index fa6a5ee1668..712454d5048 100644
--- a/src/bootstrap/builder.rs
+++ b/src/bootstrap/builder.rs
@@ -697,6 +697,7 @@ impl<'a> Builder<'a> {
                 doc::RustcBook,
                 doc::CargoBook,
                 doc::Clippy,
+                doc::ClippyBook,
                 doc::Miri,
                 doc::EmbeddedBook,
                 doc::EditionGuide,
diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs
index 5b961456076..2852442d0be 100644
--- a/src/bootstrap/doc.rs
+++ b/src/bootstrap/doc.rs
@@ -74,6 +74,7 @@ macro_rules! book {
 // and checking against it?).
 book!(
     CargoBook, "src/tools/cargo/src/doc", "cargo", submodule = "src/tools/cargo";
+    ClippyBook, "src/tools/clippy/book", "clippy";
     EditionGuide, "src/doc/edition-guide", "edition-guide", submodule;
     EmbeddedBook, "src/doc/embedded-book", "embedded-book", submodule;
     Nomicon, "src/doc/nomicon", "nomicon", submodule;
diff --git a/src/doc/index.md b/src/doc/index.md
index 2c92d5e2a18..b77790e33b7 100644
--- a/src/doc/index.md
+++ b/src/doc/index.md
@@ -93,6 +93,10 @@ accomplishing various tasks.
 
 [The Rustdoc Book](rustdoc/index.html) describes our documentation tool, `rustdoc`.
 
+## The Clippy Book
+
+[The Clippy Book](clippy/index.html) describes our static analyzer, Clippy.
+
 ## Extended Error Listing
 
 Many of Rust's errors come with error codes, and you can request extended
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 5c7b56ec140..e8f069cdbfe 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -141,6 +141,10 @@ h1, h2, h3, h4 {
 h1.fqn {
 	margin: 0;
 	padding: 0;
+	border-bottom-color: var(--headings-border-bottom-color);
+}
+h2, h3, h4 {
+	border-bottom-color: var(--headings-border-bottom-color);
 }
 .main-heading {
 	display: flex;
@@ -377,6 +381,10 @@ nav.sub {
 	object-fit: contain;
 }
 
+.sidebar, .mobile-topbar, .sidebar-menu-toggle {
+	background-color: var(--sidebar-background-color);
+}
+
 .sidebar {
 	font-size: 0.875rem;
 	width: 250px;
@@ -443,9 +451,11 @@ nav.sub {
 /* Improve the scrollbar display on firefox */
 * {
 	scrollbar-width: initial;
+	scrollbar-color: var(--scrollbar-color);
 }
 .sidebar {
 	scrollbar-width: thin;
+	scrollbar-color: var(--scrollbar-color);
 }
 
 /* Improve the scrollbar display on webkit-based browsers */
@@ -457,6 +467,13 @@ nav.sub {
 }
 ::-webkit-scrollbar-track {
 	-webkit-box-shadow: inset 0;
+	background-color: var(--scrollbar-track-background-color);
+}
+.sidebar::-webkit-scrollbar-track {
+	background-color: var(--scrollbar-track-background-color);
+}
+::-webkit-scrollbar-thumb, .sidebar::-webkit-scrollbar-thumb {
+	background-color: var(--scrollbar-thumb-background-color);
 }
 
 /* Everything else */
@@ -637,6 +654,9 @@ h2.location a {
 
 .docblock h5 { font-size: 1rem; }
 .docblock h6 { font-size: 0.875rem; }
+.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
+	border-bottom-color: var(--headings-border-bottom-color);
+}
 
 .docblock {
 	margin-left: 24px;
@@ -672,6 +692,11 @@ h2.location a {
 	display: inline-block;
 }
 
+.docblock code, .docblock-short code,
+pre, .rustdoc.source .example-wrap {
+	background-color: var(--code-block-background-color);
+}
+
 #main-content {
 	position: relative;
 }
@@ -1914,6 +1939,10 @@ in storage.js plus the media query with (min-width: 701px)
 		border: none;
 	}
 
+	.sidebar-elems {
+		background-color: var(--sidebar-background-color);
+	}
+
 	.source nav:not(.sidebar).sub {
 		margin-left: 32px;
 	}
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index b25f5e9fdb1..73d18df7656 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -9,6 +9,11 @@ Original by Dempfi (https://github.com/dempfi/ayu)
 	--settings-input-color: #ffb454;
 	--sidebar-background-color: #14191f;
 	--sidebar-background-color-hover: rgba(70, 70, 70, 0.33);
+	--code-block-background-color: #191f26;
+	--scrollbar-track-background-color: transparent;
+	--scrollbar-thumb-background-color: #5c6773;
+	--scrollbar-color: #5c6773 #24292f;
+	--headings-border-bottom-color: #5c6773;
 }
 
 .slider {
@@ -24,15 +29,9 @@ input:focus + .slider {
 h1, h2, h3, h4 {
 	color: white;
 }
-h1.fqn {
-	border-bottom-color: #5c6773;
-}
 h1.fqn  a {
 	color: #fff;
 }
-h2, h3, h4 {
-	border-bottom-color: #5c6773;
-}
 h4 {
 	border: none;
 }
@@ -56,16 +55,8 @@ span code {
 .docblock a > code {
 	color: #39AFD7 !important;
 }
-.docblock code, .docblock-short code {
-	background-color: #191f26;
-}
 pre, .rustdoc.source .example-wrap {
 	color: #e6e1cf;
-	background-color: #191f26;
-}
-
-.sidebar, .mobile-topbar, .sidebar-menu-toggle {
-	background-color: #14191f;
 }
 
 .rust-logo {
@@ -75,29 +66,6 @@ pre, .rustdoc.source .example-wrap {
 		drop-shadow(0 -1px 0 #fff);
 }
 
-/* Improve the scrollbar display on firefox */
-* {
-	scrollbar-color: #5c6773 #24292f;
-}
-
-.sidebar {
-	scrollbar-color: #5c6773 #24292f;
-}
-
-/* Improve the scrollbar display on webkit-based browsers */
-::-webkit-scrollbar-track {
-	background-color: transparent;
-}
-::-webkit-scrollbar-thumb {
-	background-color: #5c6773;
-}
-.sidebar::-webkit-scrollbar-track {
-	background-color: transparent;
-}
-.sidebar::-webkit-scrollbar-thumb {
-	background-color: #5c6773;
-}
-
 .sidebar .current,
 .sidebar a:hover {
 	background-color: transparent;
@@ -116,10 +84,6 @@ pre, .rustdoc.source .example-wrap {
 	border-right: 1px solid #ffb44c;
 }
 
-.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
-	border-bottom-color: #5c6773;
-}
-
 .docblock table td, .docblock table th {
 	border-color: #5c6773;
 }
@@ -496,21 +460,9 @@ a.result-keyword:focus {}
 .sidebar a.current.keyword {}
 
 @media (max-width: 700px) {
-	.sidebar-menu {
-		background-color: #14191f;
-		border-bottom-color: #5c6773;
-		border-right-color: #5c6773;
-	}
-
 	.sidebar-elems {
-		background-color: #14191f;
 		border-right-color: #5c6773;
 	}
-
-	#sidebar-filler {
-		background-color: #14191f;
-		border-bottom-color: #5c6773;
-	}
 }
 
 kbd {
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index 184d0e77a90..93dca51307f 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -2,8 +2,13 @@
 	--main-background-color: #353535;
 	--main-color: #ddd;
 	--settings-input-color: #2196f3;
-	--sidebar-background-color: #565656;
+	--sidebar-background-color: #505050;
 	--sidebar-background-color-hover: #676767;
+	--code-block-background-color: #2A2A2A;
+	--scrollbar-track-background-color: #717171;
+	--scrollbar-thumb-background-color: rgba(32, 34, 37, .6);
+	--scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
+	--headings-border-bottom-color: #d2d2d2;
 }
 
 .slider {
@@ -16,28 +21,10 @@ input:focus + .slider {
 	box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
 }
 
-h1.fqn {
-	border-bottom-color: #d2d2d2;
-}
-h2, h3, h4 {
-	border-bottom-color: #d2d2d2;
-}
-
 .in-band {
 	background-color: #353535;
 }
 
-.docblock code, .docblock-short code {
-	background-color: #2A2A2A;
-}
-pre, .rustdoc.source .example-wrap {
-	background-color: #2A2A2A;
-}
-
-.sidebar, .mobile-topbar, .sidebar-menu-toggle {
-	background-color: #505050;
-}
-
 .rust-logo {
 	filter: drop-shadow(1px 0 0px #fff)
 		drop-shadow(0 1px 0 #fff)
@@ -45,28 +32,6 @@ pre, .rustdoc.source .example-wrap {
 		drop-shadow(0 -1px 0 #fff)
 }
 
-/* Improve the scrollbar display on firefox */
-* {
-	scrollbar-color: rgb(64, 65, 67) #717171;
-}
-.sidebar {
-	scrollbar-color: rgba(32,34,37,.6) #5a5a5a;
-}
-
-/* Improve the scrollbar display on webkit-based browsers */
-::-webkit-scrollbar-track {
-	background-color: #717171;
-}
-::-webkit-scrollbar-thumb {
-	background-color: rgba(32, 34, 37, .6);
-}
-.sidebar::-webkit-scrollbar-track {
-	background-color: #717171;
-}
-.sidebar::-webkit-scrollbar-thumb {
-	background-color: rgba(32, 34, 37, .6);
-}
-
 .sidebar .current,
 .sidebar a:hover {
 	background: #444;
@@ -356,21 +321,9 @@ pre.ignore:hover, .information:hover + pre.ignore {
 }
 
 @media (max-width: 700px) {
-	.sidebar-menu {
-		background-color: #505050;
-		border-bottom-color: #e0e0e0;
-		border-right-color: #e0e0e0;
-	}
-
 	.sidebar-elems {
-		background-color: #505050;
 		border-right-color: #000;
 	}
-
-	#sidebar-filler {
-		background-color: #505050;
-		border-bottom-color: #e0e0e0;
-	}
 }
 
 kbd {
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index c6ba13fe1d6..73731bc8f9f 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -4,6 +4,11 @@
 	--settings-input-color: #2196f3;
 	--sidebar-background-color: #F5F5F5;
 	--sidebar-background-color-hover: #E0E0E0;
+	--code-block-background-color: #F5F5F5;
+	--scrollbar-track-background-color: #dcdcdc;
+	--scrollbar-thumb-background-color: rgba(36, 37, 39, 0.6);
+	--scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
+	--headings-border-bottom-color: #ddd;
 }
 
 .slider {
@@ -16,57 +21,16 @@ input:focus + .slider {
 	box-shadow: 0 0 0 2px #0a84ff, 0 0 0 6px rgba(10, 132, 255, 0.3);
 }
 
-h1.fqn {
-	border-bottom-color: #DDDDDD;
-}
-h2, h3, h4 {
-	border-bottom-color: #DDDDDD;
-}
-
 .in-band {
 	background-color: white;
 }
 
-.docblock code, .docblock-short code {
-	background-color: #F5F5F5;
-}
-pre, .rustdoc.source .example-wrap {
-	background-color: #F5F5F5;
-}
-
-.sidebar, .mobile-topbar, .sidebar-menu-toggle {
-	background-color: #F5F5F5;
-}
-
-/* Improve the scrollbar display on firefox */
-* {
-	scrollbar-color: rgba(36, 37, 39, 0.6) #e6e6e6;
-}
-
-.sidebar {
-	scrollbar-color: rgba(36, 37, 39, 0.6) #d9d9d9;
-}
-
 .rust-logo {
 	/* This rule exists to force other themes to explicitly style the logo.
 	 * Rustdoc has a custom linter for this purpose.
 	 */
 }
 
-/* Improve the scrollbar display on webkit-based browsers */
-::-webkit-scrollbar-track {
-	background-color: #ecebeb;
-}
-::-webkit-scrollbar-thumb {
-	background-color: rgba(36, 37, 39, 0.6);
-}
-.sidebar::-webkit-scrollbar-track {
-	background-color: #dcdcdc;
-}
-.sidebar::-webkit-scrollbar-thumb {
-	background-color: rgba(36, 37, 39, 0.6);
-}
-
 .sidebar .current,
 .sidebar a:hover {
 	background-color: #fff;
@@ -77,10 +41,6 @@ pre, .rustdoc.source .example-wrap {
 	background-color: #FDFFD3 !important;
 }
 
-.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
-	border-bottom-color: #ddd;
-}
-
 .docblock table td, .docblock table th {
 	border-color: #ddd;
 }
@@ -339,21 +299,9 @@ pre.ignore:hover, .information:hover + pre.ignore {
 }
 
 @media (max-width: 700px) {
-	.sidebar-menu {
-		background-color: #F5F5F5;
-		border-bottom-color: #e0e0e0;
-		border-right-color: #e0e0e0;
-	}
-
 	.sidebar-elems {
-		background-color: #F5F5F5;
 		border-right-color: #000;
 	}
-
-	#sidebar-filler {
-		background-color: #F5F5F5;
-		border-bottom-color: #e0e0e0;
-	}
 }
 
 kbd {
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 316554808c2..db2ad953f6a 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -624,7 +624,7 @@ impl FromWithTcx<clean::VariantStruct> for Struct {
         let clean::VariantStruct { struct_type, fields } = struct_;
         Struct {
             struct_type: from_ctor_kind(struct_type),
-            generics: Default::default(),
+            generics: Generics { params: vec![], where_predicates: vec![] },
             fields_stripped,
             fields: ids(fields, tcx),
             impls: Vec::new(),
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index eb2c8e5bae1..1168a89a8b2 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -14,7 +14,7 @@ pub const FORMAT_VERSION: u32 = 15;
 /// A `Crate` is the root of the emitted JSON blob. It contains all type/documentation information
 /// about the language items in the local crate, as well as info about external items to allow
 /// tools to find or link to them.
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 pub struct Crate {
     /// The id of the root [`Module`] item of the local crate.
     pub root: Id,
@@ -34,7 +34,7 @@ pub struct Crate {
     pub format_version: u32,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct ExternalCrate {
     pub name: String,
     pub html_root_url: Option<String>,
@@ -44,7 +44,7 @@ pub struct ExternalCrate {
 /// information. This struct should contain enough to generate a link/reference to the item in
 /// question, or can be used by a tool that takes the json output of multiple crates to find
 /// the actual item definition with all the relevant info.
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct ItemSummary {
     /// Can be used to look up the name and html_root_url of the crate this item came from in the
     /// `external_crates` map.
@@ -56,7 +56,7 @@ pub struct ItemSummary {
     pub kind: ItemKind,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
 pub struct Item {
     /// The unique identifier of this item. Can be used to find this item in various mappings.
     pub id: Id,
@@ -83,7 +83,7 @@ pub struct Item {
     pub inner: ItemEnum,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Span {
     /// The path to the source file for this span relative to the path `rustdoc` was invoked with.
     pub filename: PathBuf,
@@ -93,13 +93,13 @@ pub struct Span {
     pub end: (usize, usize),
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Deprecation {
     pub since: Option<String>,
     pub note: Option<String>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum Visibility {
     Public,
@@ -115,7 +115,7 @@ pub enum Visibility {
     },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericArgs {
     /// <'a, 32, B: Copy, C = u32>
@@ -124,7 +124,7 @@ pub enum GenericArgs {
     Parenthesized { inputs: Vec<Type>, output: Option<Type> },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericArg {
     Lifetime(String),
@@ -133,7 +133,7 @@ pub enum GenericArg {
     Infer,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Constant {
     #[serde(rename = "type")]
     pub type_: Type,
@@ -142,14 +142,14 @@ pub struct Constant {
     pub is_literal: bool,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct TypeBinding {
     pub name: String,
     pub args: GenericArgs,
     pub binding: TypeBindingKind,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum TypeBindingKind {
     Equality(Term),
@@ -159,7 +159,7 @@ pub enum TypeBindingKind {
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Id(pub String);
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum ItemKind {
     Module,
@@ -189,7 +189,7 @@ pub enum ItemKind {
     Keyword,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(tag = "kind", content = "inner", rename_all = "snake_case")]
 pub enum ItemEnum {
     Module(Module),
@@ -241,13 +241,13 @@ pub enum ItemEnum {
     },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Module {
     pub is_crate: bool,
     pub items: Vec<Id>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Union {
     pub generics: Generics,
     pub fields_stripped: bool,
@@ -255,7 +255,7 @@ pub struct Union {
     pub impls: Vec<Id>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Struct {
     pub struct_type: StructType,
     pub generics: Generics,
@@ -264,7 +264,7 @@ pub struct Struct {
     pub impls: Vec<Id>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Enum {
     pub generics: Generics,
     pub variants_stripped: bool,
@@ -272,7 +272,7 @@ pub struct Enum {
     pub impls: Vec<Id>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 #[serde(tag = "variant_kind", content = "variant_inner")]
 pub enum Variant {
@@ -281,7 +281,7 @@ pub enum Variant {
     Struct(Vec<Id>),
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum StructType {
     Plain,
@@ -289,7 +289,7 @@ pub enum StructType {
     Unit,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Header {
     #[serde(rename = "const")]
     pub const_: bool,
@@ -300,7 +300,7 @@ pub struct Header {
     pub abi: Abi,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub enum Abi {
     // We only have a concrete listing here for stable ABI's because their are so many
     // See rustc_ast_passes::feature_gate::PostExpansionVisitor::check_abi for the list
@@ -316,14 +316,14 @@ pub enum Abi {
     Other(String),
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Function {
     pub decl: FnDecl,
     pub generics: Generics,
     pub header: Header,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Method {
     pub decl: FnDecl,
     pub generics: Generics,
@@ -331,19 +331,19 @@ pub struct Method {
     pub has_body: bool,
 }
 
-#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Generics {
     pub params: Vec<GenericParamDef>,
     pub where_predicates: Vec<WherePredicate>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct GenericParamDef {
     pub name: String,
     pub kind: GenericParamDefKind,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericParamDefKind {
     Lifetime {
@@ -384,7 +384,7 @@ pub enum GenericParamDefKind {
     },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum WherePredicate {
     BoundPredicate {
@@ -410,7 +410,7 @@ pub enum WherePredicate {
     },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum GenericBound {
     TraitBound {
@@ -429,7 +429,7 @@ pub enum GenericBound {
     Outlives(String),
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum TraitBoundModifier {
     None,
@@ -437,14 +437,14 @@ pub enum TraitBoundModifier {
     MaybeConst,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum Term {
     Type(Type),
     Constant(Constant),
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 #[serde(tag = "kind", content = "inner")]
 pub enum Type {
@@ -498,7 +498,7 @@ pub enum Type {
     },
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct FunctionPointer {
     pub decl: FnDecl,
     /// Used for Higher-Rank Trait Bounds (HRTBs)
@@ -512,14 +512,14 @@ pub struct FunctionPointer {
     pub header: Header,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct FnDecl {
     pub inputs: Vec<(String, Type)>,
     pub output: Option<Type>,
     pub c_variadic: bool,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Trait {
     pub is_auto: bool,
     pub is_unsafe: bool,
@@ -529,13 +529,13 @@ pub struct Trait {
     pub implementations: Vec<Id>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct TraitAlias {
     pub generics: Generics,
     pub params: Vec<GenericBound>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Impl {
     pub is_unsafe: bool,
     pub generics: Generics,
@@ -550,7 +550,7 @@ pub struct Impl {
     pub blanket_impl: Option<Type>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub struct Import {
     /// The full path being imported.
@@ -564,37 +564,37 @@ pub struct Import {
     pub glob: bool,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct ProcMacro {
     pub kind: MacroKind,
     pub helpers: Vec<String>,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 #[serde(rename_all = "snake_case")]
 pub enum MacroKind {
     /// A bang macro `foo!()`.
     Bang,
     /// An attribute macro `#[foo]`.
     Attr,
-    /// A derive macro `#[derive(Foo)]`
+    /// A derive macro `#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]`
     Derive,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Typedef {
     #[serde(rename = "type")]
     pub type_: Type,
     pub generics: Generics,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct OpaqueTy {
     pub bounds: Vec<GenericBound>,
     pub generics: Generics,
 }
 
-#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
 pub struct Static {
     #[serde(rename = "type")]
     pub type_: Type,
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-74713.rs b/src/test/ui/const-generics/generic_const_exprs/issue-74713.rs
new file mode 100644
index 00000000000..0bcb997d96c
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-74713.rs
@@ -0,0 +1,8 @@
+fn bug<'a>()
+where
+    [(); { //~ ERROR mismatched types
+        let _: &'a (); //~ ERROR a non-static lifetime is not allowed in a `const`
+    }]:
+{}
+
+fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-74713.stderr b/src/test/ui/const-generics/generic_const_exprs/issue-74713.stderr
new file mode 100644
index 00000000000..e7673df0a02
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/issue-74713.stderr
@@ -0,0 +1,22 @@
+error[E0658]: a non-static lifetime is not allowed in a `const`
+  --> $DIR/issue-74713.rs:4:17
+   |
+LL |         let _: &'a ();
+   |                 ^^
+   |
+   = note: see issue #76560 <https://github.com/rust-lang/rust/issues/76560> for more information
+   = help: add `#![feature(generic_const_exprs)]` to the crate attributes to enable
+
+error[E0308]: mismatched types
+  --> $DIR/issue-74713.rs:3:10
+   |
+LL |       [(); {
+   |  __________^
+LL | |         let _: &'a ();
+LL | |     }]:
+   | |_____^ expected `usize`, found `()`
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0308, E0658.
+For more information about an error, try `rustc --explain E0308`.
diff --git a/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs
new file mode 100644
index 00000000000..4bf6b54fe07
--- /dev/null
+++ b/src/test/ui/repr/auxiliary/repr-transparent-non-exhaustive.rs
@@ -0,0 +1,18 @@
+#![crate_type = "lib"]
+
+pub struct Private { _priv: () }
+
+#[non_exhaustive]
+pub struct NonExhaustive {}
+
+#[non_exhaustive]
+pub enum NonExhaustiveEnum {}
+
+pub enum NonExhaustiveVariant {
+    #[non_exhaustive]
+    A,
+}
+
+pub struct ExternalIndirection<T> {
+    pub x: T,
+}
diff --git a/src/test/ui/repr/repr-transparent-non-exhaustive.rs b/src/test/ui/repr/repr-transparent-non-exhaustive.rs
new file mode 100644
index 00000000000..9ccd8610dad
--- /dev/null
+++ b/src/test/ui/repr/repr-transparent-non-exhaustive.rs
@@ -0,0 +1,96 @@
+#![deny(repr_transparent_external_private_fields)]
+
+// aux-build: repr-transparent-non-exhaustive.rs
+extern crate repr_transparent_non_exhaustive;
+
+use repr_transparent_non_exhaustive::{
+    Private,
+    NonExhaustive,
+    NonExhaustiveEnum,
+    NonExhaustiveVariant,
+    ExternalIndirection,
+};
+
+pub struct InternalPrivate {
+    _priv: (),
+}
+
+#[non_exhaustive]
+pub struct InternalNonExhaustive;
+
+pub struct InternalIndirection<T> {
+    x: T,
+}
+
+pub type Sized = i32;
+
+#[repr(transparent)]
+pub struct T1(Sized, InternalPrivate);
+#[repr(transparent)]
+pub struct T2(Sized, InternalNonExhaustive);
+#[repr(transparent)]
+pub struct T3(Sized, InternalIndirection<(InternalPrivate, InternalNonExhaustive)>);
+#[repr(transparent)]
+pub struct T4(Sized, ExternalIndirection<(InternalPrivate, InternalNonExhaustive)>);
+
+#[repr(transparent)]
+pub struct T5(Sized, Private);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T6(Sized, NonExhaustive);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T7(Sized, NonExhaustiveEnum);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T8(Sized, NonExhaustiveVariant);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T9(Sized, InternalIndirection<Private>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T10(Sized, InternalIndirection<NonExhaustive>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T11(Sized, InternalIndirection<NonExhaustiveEnum>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T12(Sized, InternalIndirection<NonExhaustiveVariant>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T13(Sized, ExternalIndirection<Private>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T14(Sized, ExternalIndirection<NonExhaustive>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T15(Sized, ExternalIndirection<NonExhaustiveEnum>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+#[repr(transparent)]
+pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>);
+//~^ ERROR zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+//~| WARN this was previously accepted by the compiler
+
+fn main() {}
diff --git a/src/test/ui/repr/repr-transparent-non-exhaustive.stderr b/src/test/ui/repr/repr-transparent-non-exhaustive.stderr
new file mode 100644
index 00000000000..3b1e334a0cb
--- /dev/null
+++ b/src/test/ui/repr/repr-transparent-non-exhaustive.stderr
@@ -0,0 +1,127 @@
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:37:22
+   |
+LL | pub struct T5(Sized, Private);
+   |                      ^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/repr-transparent-non-exhaustive.rs:1:9
+   |
+LL | #![deny(repr_transparent_external_private_fields)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:42:22
+   |
+LL | pub struct T6(Sized, NonExhaustive);
+   |                      ^^^^^^^^^^^^^
+   |
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:47:22
+   |
+LL | pub struct T7(Sized, NonExhaustiveEnum);
+   |                      ^^^^^^^^^^^^^^^^^
+   |
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:52:22
+   |
+LL | pub struct T8(Sized, NonExhaustiveVariant);
+   |                      ^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:57:22
+   |
+LL | pub struct T9(Sized, InternalIndirection<Private>);
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:62:23
+   |
+LL | pub struct T10(Sized, InternalIndirection<NonExhaustive>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:67:23
+   |
+LL | pub struct T11(Sized, InternalIndirection<NonExhaustiveEnum>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:72:23
+   |
+LL | pub struct T12(Sized, InternalIndirection<NonExhaustiveVariant>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:77:23
+   |
+LL | pub struct T13(Sized, ExternalIndirection<Private>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `Private`, which contains private fields, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:82:23
+   |
+LL | pub struct T14(Sized, ExternalIndirection<NonExhaustive>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this struct contains `NonExhaustive`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:87:23
+   |
+LL | pub struct T15(Sized, ExternalIndirection<NonExhaustiveEnum>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveEnum`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: zero-sized fields in repr(transparent) cannot contain external non-exhaustive types
+  --> $DIR/repr-transparent-non-exhaustive.rs:92:23
+   |
+LL | pub struct T16(Sized, ExternalIndirection<NonExhaustiveVariant>);
+   |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = 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 #78586 <https://github.com/rust-lang/rust/issues/78586>
+   = note: this enum contains `NonExhaustiveVariant`, which is marked with `#[non_exhaustive]`, and makes it not a breaking change to become non-zero-sized in the future.
+
+error: aborting due to 12 previous errors
+
diff --git a/src/tools/clippy/book/src/README.md b/src/tools/clippy/book/src/README.md
index d941f8b65e8..6248d588a89 100644
--- a/src/tools/clippy/book/src/README.md
+++ b/src/tools/clippy/book/src/README.md
@@ -1,7 +1,7 @@
 # Clippy
 
 [![Clippy Test](https://github.com/rust-lang/rust-clippy/workflows/Clippy%20Test/badge.svg?branch=auto&event=push)](https://github.com/rust-lang/rust-clippy/actions?query=workflow%3A%22Clippy+Test%22+event%3Apush+branch%3Aauto)
-[![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](#license)
+[![License: MIT OR Apache-2.0](https://img.shields.io/crates/l/clippy.svg)](https://github.com/rust-lang/rust-clippy#license)
 
 A collection of lints to catch common mistakes and improve your
 [Rust](https://github.com/rust-lang/rust) code.
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index 3da07fcb968..d06297f2e07 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -13,7 +13,6 @@ because that's clearly a non-descriptive name.
   - [Testing](#testing)
     - [Cargo lints](#cargo-lints)
   - [Rustfix tests](#rustfix-tests)
-  - [Edition 2018 tests](#edition-2018-tests)
   - [Testing manually](#testing-manually)
   - [Lint declaration](#lint-declaration)
   - [Lint registration](#lint-registration)
@@ -402,9 +401,8 @@ need to ensure that the MSRV configured for the project is >= the MSRV of the
 required Rust feature. If multiple features are required, just use the one with
 a lower MSRV.
 
-First, add an MSRV alias for the required feature in
-[`clippy_utils::msrvs`](/clippy_utils/src/msrvs.rs). This can be accessed later
-as `msrvs::STR_STRIP_PREFIX`, for example.
+First, add an MSRV alias for the required feature in [`clippy_utils::msrvs`].
+This can be accessed later as `msrvs::STR_STRIP_PREFIX`, for example.
 
 ```rust
 msrv_aliases! {
@@ -468,6 +466,8 @@ define_Conf! {
 }
 ```
 
+[`clippy_utils::msrvs`]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/msrvs/index.html
+
 ## Author lint
 
 If you have trouble implementing your lint, there is also the internal `author`
@@ -583,8 +583,7 @@ the workspace directory. Adding a configuration to a lint can be useful for
 thresholds or to constrain some behavior that can be seen as a false positive
 for some users. Adding a configuration is done in the following steps:
 
-1. Adding a new configuration entry to
-   [clippy_lints::utils::conf](/clippy_lints/src/utils/conf.rs) like this:
+1. Adding a new configuration entry to [`clippy_lints::utils::conf`] like this:
 
    ```rust
    /// Lint: LINT_NAME.
@@ -635,9 +634,9 @@ for some users. Adding a configuration is done in the following steps:
        ```
 3. Passing the configuration value to the lint impl struct:
 
-   First find the struct construction in the [clippy_lints lib
-   file](/clippy_lints/src/lib.rs). The configuration value is now cloned or
-   copied into a local value that is then passed to the impl struct like this:
+   First find the struct construction in the [`clippy_lints` lib file]. The
+   configuration value is now cloned or copied into a local value that is then
+   passed to the impl struct like this:
 
    ```rust
    // Default generated registration:
@@ -653,12 +652,16 @@ for some users. Adding a configuration is done in the following steps:
 
 4. Adding tests:
     1. The default configured value can be tested like any normal lint in
-       [`tests/ui`](/tests/ui).
-    2. The configuration itself will be tested separately in
-       [`tests/ui-toml`](/tests/ui-toml). Simply add a new subfolder with a
-       fitting name. This folder contains a `clippy.toml` file with the
-       configuration value and a rust file that should be linted by Clippy. The
-       test can otherwise be written as usual.
+       [`tests/ui`].
+    2. The configuration itself will be tested separately in [`tests/ui-toml`].
+       Simply add a new subfolder with a fitting name. This folder contains a
+       `clippy.toml` file with the configuration value and a rust file that
+       should be linted by Clippy. The test can otherwise be written as usual.
+
+[`clippy_lints::utils::conf`]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/utils/conf.rs
+[`clippy_lints` lib file]: https://github.com/rust-lang/rust-clippy/blob/master/clippy_lints/src/lib.rs
+[`tests/ui`]: https://github.com/rust-lang/rust-clippy/blob/master/tests/ui
+[`tests/ui-toml`]: https://github.com/rust-lang/rust-clippy/blob/master/tests/ui-toml
 
 ## Cheat Sheet
 
diff --git a/src/tools/clippy/book/src/development/basics.md b/src/tools/clippy/book/src/development/basics.md
index 78c429ea013..605897ff49c 100644
--- a/src/tools/clippy/book/src/development/basics.md
+++ b/src/tools/clippy/book/src/development/basics.md
@@ -98,7 +98,7 @@ cargo dev setup intellij
 ```
 
 More about intellij command usage and reasons
-[here](../CONTRIBUTING.md#intellij-rust)
+[here](https://github.com/rust-lang/rust-clippy/blob/master/CONTRIBUTING.md#intellij-rust)
 
 ## lintcheck
 
diff --git a/src/tools/clippy/book/src/development/common_tools_writing_lints.md b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
index e1ed89262f6..15e00c7d7ce 100644
--- a/src/tools/clippy/book/src/development/common_tools_writing_lints.md
+++ b/src/tools/clippy/book/src/development/common_tools_writing_lints.md
@@ -276,4 +276,4 @@ functions to deal with macros:
 [LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html
 [TyCtxt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TyCtxt.html
 [pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty
-[paths]: ../clippy_utils/src/paths.rs
+[paths]: https://doc.rust-lang.org/nightly/nightly-rustc/clippy_utils/paths/index.html
diff --git a/src/tools/clippy/book/src/usage.md b/src/tools/clippy/book/src/usage.md
index 337680aa313..5d858e0da46 100644
--- a/src/tools/clippy/book/src/usage.md
+++ b/src/tools/clippy/book/src/usage.md
@@ -148,4 +148,4 @@ clippy-driver --edition 2018 -Cpanic=abort foo.rs
 > that are not optimized as expected, for example.
 
 [Installation]: installation.md
-[CI]: continuous_integration
+[CI]: continuous_integration/index.md
diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer
-Subproject 75b22326dad1914c22484ab6672de5cae94f745
+Subproject 5342f47f4276641ddb5f0a5e08fb307742d6cdc
diff --git a/triagebot.toml b/triagebot.toml
index ba9ed20cc64..3842da566a9 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -165,6 +165,19 @@ exclude_labels = [
     "T-*",
 ]
 
+[autolabel."A-bootstrap"]
+trigger_files = [
+    "x.py",
+    "src/bootstrap",
+    "src/tools/rust-installer",
+]
+
+[autolabel."T-infra"]
+trigger_files = [
+    "src/ci",
+    "src/tools/bump-stage0",
+]
+
 [notify-zulip."I-prioritize"]
 zulip_stream = 245100 # #t-compiler/wg-prioritization/alerts
 topic = "#{number} {title}"
@@ -279,6 +292,9 @@ Examples of `T-libs-api` changes:
 * Changing observable runtime behavior of library APIs
 """
 
+[mentions."library/proc_macro/src/bridge"]
+cc = ["@rust-lang/wg-rls-2"]
+
 [mentions."src/librustdoc/clean/types.rs"]
 cc = ["@camelid"]