diff --git a/Cargo.lock b/Cargo.lock
index 890c5ce3ac478..197b2c8f3f06a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1879,9 +1879,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.99"
+version = "0.2.103"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7f823d141fe0a24df1e23b4af4e3c7ba9e5966ec514ea068c93024aa7deb765"
+checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
 dependencies = [
  "rustc-std-workspace-core",
 ]
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index d05cfebc5f02e..11cdbe84accb7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -498,6 +498,27 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
             diag.span_label(*span, format!("`{}` escapes the {} body here", fr_name, escapes_from));
         }
 
+        // Only show an extra note if we can find an 'error region' for both of the region
+        // variables. This avoids showing a noisy note that just mentions 'synthetic' regions
+        // that don't help the user understand the error.
+        if self.to_error_region(errci.fr).is_some()
+            && self.to_error_region(errci.outlived_fr).is_some()
+        {
+            let fr_region_name = self.give_region_a_name(errci.fr).unwrap();
+            fr_region_name.highlight_region_name(&mut diag);
+            let outlived_fr_region_name = self.give_region_a_name(errci.outlived_fr).unwrap();
+            outlived_fr_region_name.highlight_region_name(&mut diag);
+
+            diag.span_label(
+                *span,
+                format!(
+                    "{}requires that `{}` must outlive `{}`",
+                    category.description(),
+                    fr_region_name,
+                    outlived_fr_region_name,
+                ),
+            );
+        }
         diag
     }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index f13531814d6eb..fee13fd2e2eaf 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1826,8 +1826,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
 
         match layout.variants {
             Variants::Single { index } => {
-                debug!("print-type-size `{:#?}` variant {}", layout, adt_def.variants[index].ident);
-                if !adt_def.variants.is_empty() {
+                if !adt_def.variants.is_empty() && layout.fields != FieldsShape::Primitive {
+                    debug!(
+                        "print-type-size `{:#?}` variant {}",
+                        layout, adt_def.variants[index].ident
+                    );
                     let variant_def = &adt_def.variants[index];
                     let fields: Vec<_> = variant_def.fields.iter().map(|f| f.ident.name).collect();
                     record(
diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs
index 9736a7b2e28e3..51c766fe57c10 100644
--- a/compiler/rustc_typeck/src/check/cast.rs
+++ b/compiler/rustc_typeck/src/check/cast.rs
@@ -351,7 +351,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                 );
                 let mut sugg = None;
                 let mut sugg_mutref = false;
-                if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() {
+                if let ty::Ref(reg, cast_ty, mutbl) = *self.cast_ty.kind() {
                     if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() {
                         if fcx
                             .try_coerce(
@@ -366,7 +366,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                             )
                             .is_ok()
                         {
-                            sugg = Some(format!("&{}*", mutbl.prefix_str()));
+                            sugg = Some((format!("&{}*", mutbl.prefix_str()), cast_ty == expr_ty));
                         }
                     } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() {
                         if expr_mutbl == Mutability::Not
@@ -400,7 +400,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                             )
                             .is_ok()
                     {
-                        sugg = Some(format!("&{}", mutbl.prefix_str()));
+                        sugg = Some((format!("&{}", mutbl.prefix_str()), false));
                     }
                 } else if let ty::RawPtr(TypeAndMut { mutbl, .. }) = *self.cast_ty.kind() {
                     if fcx
@@ -416,19 +416,47 @@ impl<'a, 'tcx> CastCheck<'tcx> {
                         )
                         .is_ok()
                     {
-                        sugg = Some(format!("&{}", mutbl.prefix_str()));
+                        sugg = Some((format!("&{}", mutbl.prefix_str()), false));
                     }
                 }
                 if sugg_mutref {
                     err.span_label(self.span, "invalid cast");
                     err.span_note(self.expr.span, "this reference is immutable");
                     err.span_note(self.cast_span, "trying to cast to a mutable reference type");
-                } else if let Some(sugg) = sugg {
+                } else if let Some((sugg, remove_cast)) = sugg {
                     err.span_label(self.span, "invalid cast");
-                    err.span_suggestion_verbose(
-                        self.expr.span.shrink_to_lo(),
+
+                    let has_parens = fcx
+                        .tcx
+                        .sess
+                        .source_map()
+                        .span_to_snippet(self.expr.span)
+                        .map_or(false, |snip| snip.starts_with("("));
+
+                    // Very crude check to see whether the expression must be wrapped
+                    // in parentheses for the suggestion to work (issue #89497).
+                    // Can/should be extended in the future.
+                    let needs_parens = !has_parens
+                        && match self.expr.kind {
+                            hir::ExprKind::Cast(..) => true,
+                            _ => false,
+                        };
+
+                    let mut suggestion = vec![(self.expr.span.shrink_to_lo(), sugg)];
+                    if needs_parens {
+                        suggestion[0].1 += "(";
+                        suggestion.push((self.expr.span.shrink_to_hi(), ")".to_string()));
+                    }
+                    if remove_cast {
+                        suggestion.push((
+                            self.expr.span.shrink_to_hi().to(self.cast_span),
+                            String::new(),
+                        ));
+                    }
+
+                    err.multipart_suggestion_verbose(
                         "consider borrowing the value",
-                        sugg,
+                        suggestion,
                         Applicability::MachineApplicable,
                     );
                 } else if !matches!(
diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs
index dfa0227dea3b8..05f94da6de70d 100644
--- a/library/alloc/src/collections/vec_deque/drain.rs
+++ b/library/alloc/src/collections/vec_deque/drain.rs
@@ -18,10 +18,21 @@ pub struct Drain<
     T: 'a,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
 > {
-    pub(crate) after_tail: usize,
-    pub(crate) after_head: usize,
-    pub(crate) iter: Iter<'a, T>,
-    pub(crate) deque: NonNull<VecDeque<T, A>>,
+    after_tail: usize,
+    after_head: usize,
+    iter: Iter<'a, T>,
+    deque: NonNull<VecDeque<T, A>>,
+}
+
+impl<'a, T, A: Allocator> Drain<'a, T, A> {
+    pub(super) unsafe fn new(
+        after_tail: usize,
+        after_head: usize,
+        iter: Iter<'a, T>,
+        deque: NonNull<VecDeque<T, A>>,
+    ) -> Self {
+        Drain { after_tail, after_head, iter, deque }
+    }
 }
 
 #[stable(feature = "collection_debug", since = "1.17.0")]
diff --git a/library/alloc/src/collections/vec_deque/iter_mut.rs b/library/alloc/src/collections/vec_deque/iter_mut.rs
index 7700b31cf5b46..31e6e3b06af5f 100644
--- a/library/alloc/src/collections/vec_deque/iter_mut.rs
+++ b/library/alloc/src/collections/vec_deque/iter_mut.rs
@@ -13,10 +13,21 @@ use super::{count, wrap_index, RingSlices};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IterMut<'a, T: 'a> {
     // Internal safety invariant: the entire slice is dereferencable.
-    pub(crate) ring: *mut [T],
-    pub(crate) tail: usize,
-    pub(crate) head: usize,
-    pub(crate) phantom: PhantomData<&'a mut [T]>,
+    ring: *mut [T],
+    tail: usize,
+    head: usize,
+    phantom: PhantomData<&'a mut [T]>,
+}
+
+impl<'a, T> IterMut<'a, T> {
+    pub(super) unsafe fn new(
+        ring: *mut [T],
+        tail: usize,
+        head: usize,
+        phantom: PhantomData<&'a mut [T]>,
+    ) -> Self {
+        IterMut { ring, tail, head, phantom }
+    }
 }
 
 // SAFETY: we do nothing thread-local and there is no interior mutability,
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index f4de2b2ebe5dc..e996784bbad28 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -1000,12 +1000,9 @@ impl<T, A: Allocator> VecDeque<T, A> {
     pub fn iter_mut(&mut self) -> IterMut<'_, T> {
         // SAFETY: The internal `IterMut` safety invariant is established because the
         // `ring` we create is a dereferencable slice for lifetime '_.
-        IterMut {
-            tail: self.tail,
-            head: self.head,
-            ring: ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()),
-            phantom: PhantomData,
-        }
+        let ring = ptr::slice_from_raw_parts_mut(self.ptr(), self.cap());
+
+        unsafe { IterMut::new(ring, self.tail, self.head, PhantomData) }
     }
 
     /// Returns a pair of slices which contain, in order, the contents of the
@@ -1192,12 +1189,9 @@ impl<T, A: Allocator> VecDeque<T, A> {
 
         // SAFETY: The internal `IterMut` safety invariant is established because the
         // `ring` we create is a dereferencable slice for lifetime '_.
-        IterMut {
-            tail,
-            head,
-            ring: ptr::slice_from_raw_parts_mut(self.ptr(), self.cap()),
-            phantom: PhantomData,
-        }
+        let ring = ptr::slice_from_raw_parts_mut(self.ptr(), self.cap());
+
+        unsafe { IterMut::new(ring, tail, head, PhantomData) }
     }
 
     /// Creates a draining iterator that removes the specified range in the
@@ -1269,19 +1263,17 @@ impl<T, A: Allocator> VecDeque<T, A> {
         // the drain is complete and the Drain destructor is run.
         self.head = drain_tail;
 
-        Drain {
-            deque: NonNull::from(&mut *self),
-            after_tail: drain_head,
-            after_head: head,
-            iter: Iter {
-                tail: drain_tail,
-                head: drain_head,
-                // Crucially, we only create shared references from `self` here and read from
-                // it.  We do not write to `self` nor reborrow to a mutable reference.
-                // Hence the raw pointer we created above, for `deque`, remains valid.
-                ring: unsafe { self.buffer_as_slice() },
-            },
-        }
+        let deque = NonNull::from(&mut *self);
+        let iter = Iter {
+            tail: drain_tail,
+            head: drain_head,
+            // Crucially, we only create shared references from `self` here and read from
+            // it.  We do not write to `self` nor reborrow to a mutable reference.
+            // Hence the raw pointer we created above, for `deque`, remains valid.
+            ring: unsafe { self.buffer_as_slice() },
+        };
+
+        unsafe { Drain::new(drain_head, head, iter, deque) }
     }
 
     /// Clears the `VecDeque`, removing all values.
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 4742970f9542b..f9d517ce8c0eb 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -142,6 +142,7 @@
 #![feature(link_llvm_intrinsics)]
 #![feature(llvm_asm)]
 #![feature(min_specialization)]
+#![feature(mixed_integer_ops)]
 #![cfg_attr(not(bootstrap), feature(must_not_suspend))]
 #![feature(negative_impls)]
 #![feature(never_type)]
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 9d46948ce02af..12dda61400f2a 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -433,6 +433,28 @@ macro_rules! int_impl {
             unsafe { intrinsics::unchecked_add(self, rhs) }
         }
 
+        /// Checked addition with an unsigned integer. Computes `self + rhs`,
+        /// returning `None` if overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_unsigned(2), Some(3));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_unsigned(3), None);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_add_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
+            let (a, b) = self.overflowing_add_unsigned(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
         /// Checked integer subtraction. Computes `self - rhs`, returning `None` if
         /// overflow occurred.
         ///
@@ -479,6 +501,28 @@ macro_rules! int_impl {
             unsafe { intrinsics::unchecked_sub(self, rhs) }
         }
 
+        /// Checked subtraction with an unsigned integer. Computes `self - rhs`,
+        /// returning `None` if overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_sub_unsigned(2), Some(-1));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub_unsigned(3), None);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_sub_unsigned(self, rhs: $UnsignedT) -> Option<Self> {
+            let (a, b) = self.overflowing_sub_unsigned(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
         /// Checked integer multiplication. Computes `self * rhs`, returning `None` if
         /// overflow occurred.
         ///
@@ -826,6 +870,32 @@ macro_rules! int_impl {
             intrinsics::saturating_add(self, rhs)
         }
 
+        /// Saturating addition with an unsigned integer. Computes `self + rhs`,
+        /// saturating at the numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_unsigned(2), 3);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.saturating_add_unsigned(100), ", stringify!($SelfT), "::MAX);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn saturating_add_unsigned(self, rhs: $UnsignedT) -> Self {
+            // Overflow can only happen at the upper bound
+            // We cannot use `unwrap_or` here because it is not `const`
+            match self.checked_add_unsigned(rhs) {
+                Some(x) => x,
+                None => Self::MAX,
+            }
+        }
+
         /// Saturating integer subtraction. Computes `self - rhs`, saturating at the
         /// numeric bounds instead of overflowing.
         ///
@@ -847,6 +917,32 @@ macro_rules! int_impl {
             intrinsics::saturating_sub(self, rhs)
         }
 
+        /// Saturating subtraction with an unsigned integer. Computes `self - rhs`,
+        /// saturating at the numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".saturating_sub_unsigned(127), -27);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub_unsigned(100), ", stringify!($SelfT), "::MIN);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn saturating_sub_unsigned(self, rhs: $UnsignedT) -> Self {
+            // Overflow can only happen at the lower bound
+            // We cannot use `unwrap_or` here because it is not `const`
+            match self.checked_sub_unsigned(rhs) {
+                Some(x) => x,
+                None => Self::MIN,
+            }
+        }
+
         /// Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN`
         /// instead of overflowing.
         ///
@@ -1002,6 +1098,27 @@ macro_rules! int_impl {
             intrinsics::wrapping_add(self, rhs)
         }
 
+        /// Wrapping (modular) addition with an unsigned integer. Computes
+        /// `self + rhs`, wrapping around at the boundary of the type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(100", stringify!($SelfT), ".wrapping_add_unsigned(27), 127);")]
+        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add_unsigned(2), ", stringify!($SelfT), "::MIN + 1);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline(always)]
+        pub const fn wrapping_add_unsigned(self, rhs: $UnsignedT) -> Self {
+            self.wrapping_add(rhs as Self)
+        }
+
         /// Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the
         /// boundary of the type.
         ///
@@ -1022,6 +1139,27 @@ macro_rules! int_impl {
             intrinsics::wrapping_sub(self, rhs)
         }
 
+        /// Wrapping (modular) subtraction with an unsigned integer. Computes
+        /// `self - rhs`, wrapping around at the boundary of the type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".wrapping_sub_unsigned(127), -127);")]
+        #[doc = concat!("assert_eq!((-2", stringify!($SelfT), ").wrapping_sub_unsigned(", stringify!($UnsignedT), "::MAX), -1);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline(always)]
+        pub const fn wrapping_sub_unsigned(self, rhs: $UnsignedT) -> Self {
+            self.wrapping_sub(rhs as Self)
+        }
+
         /// Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at
         /// the boundary of the type.
         ///
@@ -1372,6 +1510,33 @@ macro_rules! int_impl {
             (sum as $SelfT, carry)
         }
 
+        /// Calculates `self` + `rhs` with an unsigned `rhs`
+        ///
+        /// Returns a tuple of the addition along with a boolean indicating
+        /// whether an arithmetic overflow would occur. If an overflow would
+        /// have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_unsigned(2), (3, false));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN).overflowing_add_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MAX, false));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_unsigned(3), (", stringify!($SelfT), "::MIN, true));")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_add_unsigned(self, rhs: $UnsignedT) -> (Self, bool) {
+            let rhs = rhs as Self;
+            let (res, overflowed) = self.overflowing_add(rhs);
+            (res, overflowed ^ (rhs < 0))
+        }
+
         /// Calculates `self` - `rhs`
         ///
         /// Returns a tuple of the subtraction along with a boolean indicating whether an arithmetic overflow
@@ -1423,6 +1588,33 @@ macro_rules! int_impl {
             (sum as $SelfT, borrow)
         }
 
+        /// Calculates `self` - `rhs` with an unsigned `rhs`
+        ///
+        /// Returns a tuple of the subtraction along with a boolean indicating
+        /// whether an arithmetic overflow would occur. If an overflow would
+        /// have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_sub_unsigned(2), (-1, false));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX).overflowing_sub_unsigned(", stringify!($UnsignedT), "::MAX), (", stringify!($SelfT), "::MIN, false));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MIN + 2).overflowing_sub_unsigned(3), (", stringify!($SelfT), "::MAX, true));")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_sub_unsigned(self, rhs: $UnsignedT) -> (Self, bool) {
+            let rhs = rhs as Self;
+            let (res, overflowed) = self.overflowing_sub(rhs);
+            (res, overflowed ^ (rhs < 0))
+        }
+
         /// Calculates the multiplication of `self` and `rhs`.
         ///
         /// Returns a tuple of the multiplication along with a boolean indicating whether an arithmetic overflow
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index 59b68cbe9c0ce..d5fb98eff575d 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -245,7 +245,7 @@ const ASCII_CASE_MASK: u8 = 0b0010_0000;
 #[lang = "u8"]
 impl u8 {
     widening_impl! { u8, u16, 8 }
-    uint_impl! { u8, u8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
+    uint_impl! { u8, u8, i8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]",
     "[0x12]", "", "" }
 
     /// Checks if the value is within the ASCII range.
@@ -779,21 +779,21 @@ impl u8 {
 #[lang = "u16"]
 impl u16 {
     widening_impl! { u16, u32, 16 }
-    uint_impl! { u16, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+    uint_impl! { u16, u16, i16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]", "", "" }
 }
 
 #[lang = "u32"]
 impl u32 {
     widening_impl! { u32, u64, 32 }
-    uint_impl! { u32, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
+    uint_impl! { u32, u32, i32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
     "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" }
 }
 
 #[lang = "u64"]
 impl u64 {
     widening_impl! { u64, u128, 64 }
-    uint_impl! { u64, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
+    uint_impl! { u64, u64, i64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
     "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
@@ -802,7 +802,7 @@ impl u64 {
 
 #[lang = "u128"]
 impl u128 {
-    uint_impl! { u128, u128, 128, 340282366920938463463374607431768211455, 16,
+    uint_impl! { u128, u128, i128, 128, 340282366920938463463374607431768211455, 16,
     "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012",
     "0x12907856341290785634129078563412", "0x48091e6a2c48091e6a2c48091e6a2c48",
     "[0x12, 0x90, 0x78, 0x56, 0x34, 0x12, 0x90, 0x78, \
@@ -816,7 +816,7 @@ impl u128 {
 #[lang = "usize"]
 impl usize {
     widening_impl! { usize, u32, 16 }
-    uint_impl! { usize, u16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
+    uint_impl! { usize, u16, isize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48",
     "[0x34, 0x12]", "[0x12, 0x34]",
     usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() }
 }
@@ -824,7 +824,7 @@ impl usize {
 #[lang = "usize"]
 impl usize {
     widening_impl! { usize, u64, 32 }
-    uint_impl! { usize, u32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678",
+    uint_impl! { usize, u32, isize, 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!() }
 }
@@ -833,7 +833,7 @@ impl usize {
 #[lang = "usize"]
 impl usize {
     widening_impl! { usize, u128, 64 }
-    uint_impl! { usize, u64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
+    uint_impl! { usize, u64, isize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa",
     "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48",
     "[0x56, 0x34, 0x12, 0x90, 0x78, 0x56, 0x34, 0x12]",
      "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]",
@@ -865,23 +865,41 @@ impl usize {
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub enum FpCategory {
-    /// "Not a Number", often obtained by dividing by zero.
+    /// NaN (not a number): this value results from calculations like `(-1.0).sqrt()`.
+    ///
+    /// See [the documentation for `f32`](f32) for more information on the unusual properties
+    /// of NaN.
     #[stable(feature = "rust1", since = "1.0.0")]
     Nan,
 
-    /// Positive or negative infinity.
+    /// Positive or negative infinity, which often results from dividing a nonzero number
+    /// by zero.
     #[stable(feature = "rust1", since = "1.0.0")]
     Infinite,
 
     /// Positive or negative zero.
+    ///
+    /// See [the documentation for `f32`](f32) for more information on the signedness of zeroes.
     #[stable(feature = "rust1", since = "1.0.0")]
     Zero,
 
-    /// De-normalized floating point representation (less precise than `Normal`).
+    /// “Subnormal” or “denormal” floating point representation (less precise, relative to
+    /// their magnitude, than [`Normal`]).
+    ///
+    /// Subnormal numbers are larger in magnitude than [`Zero`] but smaller in magnitude than all
+    /// [`Normal`] numbers.
+    ///
+    /// [`Normal`]: Self::Normal
+    /// [`Zero`]: Self::Zero
     #[stable(feature = "rust1", since = "1.0.0")]
     Subnormal,
 
-    /// A regular floating point number.
+    /// A regular floating point number, not any of the exceptional categories.
+    ///
+    /// The smallest positive normal numbers are [`f32::MIN_POSITIVE`] and [`f64::MIN_POSITIVE`],
+    /// and the largest positive normal numbers are [`f32::MAX`] and [`f64::MAX`]. (Unlike signed
+    /// integers, floating point numbers are symmetric in their range, so negating any of these
+    /// constants will produce their negative counterpart.)
     #[stable(feature = "rust1", since = "1.0.0")]
     Normal,
 }
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 7ef8ea23b5028..25cd582bb67d7 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -1,5 +1,5 @@
 macro_rules! uint_impl {
-    ($SelfT:ty, $ActualT:ident, $BITS:expr, $MaxV:expr,
+    ($SelfT:ty, $ActualT:ident, $SignedT:ident, $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) => {
@@ -442,6 +442,29 @@ macro_rules! uint_impl {
             unsafe { intrinsics::unchecked_add(self, rhs) }
         }
 
+        /// Checked addition with a signed integer. Computes `self + rhs`,
+        /// returning `None` if overflow occurred.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(2), Some(3));")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".checked_add_signed(-2), None);")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add_signed(3), None);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn checked_add_signed(self, rhs: $SignedT) -> Option<Self> {
+            let (a, b) = self.overflowing_add_signed(rhs);
+            if unlikely!(b) {None} else {Some(a)}
+        }
+
         /// Checked integer subtraction. Computes `self - rhs`, returning
         /// `None` if overflow occurred.
         ///
@@ -995,6 +1018,35 @@ macro_rules! uint_impl {
             intrinsics::saturating_add(self, rhs)
         }
 
+        /// Saturating addition with a signed integer. Computes `self + rhs`,
+        /// saturating at the numeric bounds instead of overflowing.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(2), 3);")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".saturating_add_signed(-2), 0);")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).saturating_add_signed(4), ", stringify!($SelfT), "::MAX);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn saturating_add_signed(self, rhs: $SignedT) -> Self {
+            let (res, overflow) = self.overflowing_add(rhs as Self);
+            if overflow == (rhs < 0) {
+                res
+            } else if overflow {
+                Self::MAX
+            } else {
+                0
+            }
+        }
+
         /// Saturating integer subtraction. Computes `self - rhs`, saturating
         /// at the numeric bounds instead of overflowing.
         ///
@@ -1111,6 +1163,28 @@ macro_rules! uint_impl {
             intrinsics::wrapping_add(self, rhs)
         }
 
+        /// Wrapping (modular) addition with a signed integer. Computes
+        /// `self + rhs`, wrapping around at the boundary of the type.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(2), 3);")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".wrapping_add_signed(-2), ", stringify!($SelfT), "::MAX);")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).wrapping_add_signed(4), 1);")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn wrapping_add_signed(self, rhs: $SignedT) -> Self {
+            self.wrapping_add(rhs as Self)
+        }
+
         /// Wrapping (modular) subtraction. Computes `self - rhs`,
         /// wrapping around at the boundary of the type.
         ///
@@ -1435,6 +1509,32 @@ macro_rules! uint_impl {
             (c, b | d)
         }
 
+        /// Calculates `self` + `rhs` with a signed `rhs`
+        ///
+        /// Returns a tuple of the addition along with a boolean indicating
+        /// whether an arithmetic overflow would occur. If an overflow would
+        /// have occurred then the wrapped value is returned.
+        ///
+        /// # Examples
+        ///
+        /// Basic usage:
+        ///
+        /// ```
+        /// # #![feature(mixed_integer_ops)]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(2), (3, false));")]
+        #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".overflowing_add_signed(-2), (", stringify!($SelfT), "::MAX, true));")]
+        #[doc = concat!("assert_eq!((", stringify!($SelfT), "::MAX - 2).overflowing_add_signed(4), (1, true));")]
+        /// ```
+        #[unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[rustc_const_unstable(feature = "mixed_integer_ops", issue = "87840")]
+        #[must_use = "this returns the result of the operation, \
+                      without modifying the original"]
+        #[inline]
+        pub const fn overflowing_add_signed(self, rhs: $SignedT) -> (Self, bool) {
+            let (res, overflowed) = self.overflowing_add(rhs as Self);
+            (res, overflowed ^ (rhs < 0))
+        }
+
         /// Calculates `self` - `rhs`
         ///
         /// Returns a tuple of the subtraction along with a boolean indicating
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 2b77dc54ab35c..6bc445c6f2b07 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -15,7 +15,7 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] }
 panic_unwind = { path = "../panic_unwind", optional = true }
 panic_abort = { path = "../panic_abort" }
 core = { path = "../core" }
-libc = { version = "0.2.99", default-features = false, features = ['rustc-dep-of-std'] }
+libc = { version = "0.2.103", default-features = false, features = ['rustc-dep-of-std'] }
 compiler_builtins = { version = "0.1.44" }
 profiler_builtins = { path = "../profiler_builtins", optional = true }
 unwind = { path = "../unwind" }
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 25cc5e67ad14e..980b2531192e8 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -292,12 +292,7 @@ where
             SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n),
             SeekFrom::Current(n) => (self.pos, n),
         };
-        let new_pos = if offset >= 0 {
-            base_pos.checked_add(offset as u64)
-        } else {
-            base_pos.checked_sub((offset.wrapping_neg()) as u64)
-        };
-        match new_pos {
+        match base_pos.checked_add_signed(offset) {
             Some(n) => {
                 self.pos = n;
                 Ok(self.pos)
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 0ba4e85886caa..a7516bf4ffd37 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -297,6 +297,7 @@
 #![feature(maybe_uninit_slice)]
 #![feature(maybe_uninit_uninit_array)]
 #![feature(min_specialization)]
+#![feature(mixed_integer_ops)]
 #![cfg_attr(not(bootstrap), feature(must_not_suspend))]
 #![feature(needs_panic_runtime)]
 #![feature(negative_impls)]
diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs
index 8be25f84999d2..81b21fbbb1656 100644
--- a/library/std/src/sys/hermit/thread.rs
+++ b/library/std/src/sys/hermit/thread.rs
@@ -97,7 +97,7 @@ impl Thread {
     }
 }
 
-pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
     unsupported()
 }
 
diff --git a/library/std/src/sys/sgx/thread.rs b/library/std/src/sys/sgx/thread.rs
index cbb8ba964018a..d745a61961404 100644
--- a/library/std/src/sys/sgx/thread.rs
+++ b/library/std/src/sys/sgx/thread.rs
@@ -137,7 +137,7 @@ impl Thread {
     }
 }
 
-pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
     unsupported()
 }
 
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 5631834eca6fe..891f3413e9138 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -263,7 +263,7 @@ impl Drop for Thread {
     }
 }
 
-pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
     cfg_if::cfg_if! {
         if #[cfg(any(
             target_os = "android",
diff --git a/library/std/src/sys/unsupported/thread.rs b/library/std/src/sys/unsupported/thread.rs
index dc75d4ee6725c..a8db251de2017 100644
--- a/library/std/src/sys/unsupported/thread.rs
+++ b/library/std/src/sys/unsupported/thread.rs
@@ -31,7 +31,7 @@ impl Thread {
     }
 }
 
-pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
     unsupported()
 }
 
diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs
index 9ec02bbec2644..2e4e474c4492c 100644
--- a/library/std/src/sys/wasi/thread.rs
+++ b/library/std/src/sys/wasi/thread.rs
@@ -64,7 +64,7 @@ impl Thread {
     }
 }
 
-pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
     unsupported()
 }
 
diff --git a/library/std/src/sys/wasm/atomics/thread.rs b/library/std/src/sys/wasm/atomics/thread.rs
index a66ab0837570d..16418a06226e4 100644
--- a/library/std/src/sys/wasm/atomics/thread.rs
+++ b/library/std/src/sys/wasm/atomics/thread.rs
@@ -40,7 +40,7 @@ impl Thread {
     pub fn join(self) {}
 }
 
-pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
     unsupported()
 }
 
diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs
index a5293133b3ab0..75f70c2076ee1 100644
--- a/library/std/src/sys/windows/thread.rs
+++ b/library/std/src/sys/windows/thread.rs
@@ -100,7 +100,7 @@ impl Thread {
     }
 }
 
-pub fn available_concurrency() -> io::Result<NonZeroUsize> {
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
     let res = unsafe {
         let mut sysinfo: c::SYSTEM_INFO = crate::mem::zeroed();
         c::GetSystemInfo(&mut sysinfo);
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 9d659102b0320..707a55b625814 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -1453,12 +1453,14 @@ fn _assert_sync_and_send() {
 ///
 /// ```
 /// # #![allow(dead_code)]
-/// #![feature(available_concurrency)]
+/// #![feature(available_parallelism)]
 /// use std::thread;
 ///
-/// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1);
+/// let count = thread::available_parallelism().map(|n| n.get()).unwrap_or(1);
 /// ```
-#[unstable(feature = "available_concurrency", issue = "74479")]
-pub fn available_concurrency() -> io::Result<NonZeroUsize> {
-    imp::available_concurrency()
+#[doc(alias = "hardware_concurrency")] // Alias for C++ `std::thread::hardware_concurrency`.
+#[doc(alias = "available_concurrency")] // Alias for a name we gave this API on unstable.
+#[unstable(feature = "available_parallelism", issue = "74479")]
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+    imp::available_parallelism()
 }
diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs
index c39a9b0ec0233..e25f524ec0566 100644
--- a/library/test/src/helpers/concurrency.rs
+++ b/library/test/src/helpers/concurrency.rs
@@ -9,6 +9,6 @@ pub fn get_concurrency() -> usize {
             _ => panic!("RUST_TEST_THREADS is `{}`, should be a positive integer.", value),
         }
     } else {
-        thread::available_concurrency().map(|n| n.get()).unwrap_or(1)
+        thread::available_parallelism().map(|n| n.get()).unwrap_or(1)
     }
 }
diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs
index 251f099f28af4..6732c6c61c204 100644
--- a/library/test/src/lib.rs
+++ b/library/test/src/lib.rs
@@ -23,7 +23,7 @@
 #![feature(libc)]
 #![feature(rustc_private)]
 #![feature(nll)]
-#![feature(available_concurrency)]
+#![feature(available_parallelism)]
 #![feature(bench_black_box)]
 #![feature(internal_output_capture)]
 #![feature(panic_unwind)]
diff --git a/src/doc/rustc/src/tests/index.md b/src/doc/rustc/src/tests/index.md
index ec23d4fe0dbd3..04e20fdd41c0f 100644
--- a/src/doc/rustc/src/tests/index.md
+++ b/src/doc/rustc/src/tests/index.md
@@ -161,7 +161,7 @@ The following options affect how tests are executed.
 
 Sets the number of threads to use for running tests in parallel. By default,
 uses the amount of concurrency available on the hardware as indicated by
-[`available_concurrency`].
+[`available_parallelism`].
 
 This can also be specified with the `RUST_TEST_THREADS` environment variable.
 
@@ -265,7 +265,7 @@ Experimental support for using custom test harnesses is available on the
 
 [`--test` option]: ../command-line-arguments.md#option-test
 [`-Z panic-abort-tests`]: https://github.com/rust-lang/rust/issues/67650
-[`available_concurrency`]: ../../std/thread/fn.available_concurrency.html
+[`available_parallelism`]: ../../std/thread/fn.available_parallelism.html
 [`cargo test`]: ../../cargo/commands/cargo-test.html
 [`libtest`]: ../../test/index.html
 [`main` function]: ../../reference/crates-and-source-files.html#main-functions
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index 56d2ca57218c5..302fc5a677771 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -1,4 +1,4 @@
-use crate::html::markdown::{ErrorCodes, IdMap, Markdown, Playground};
+use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
 use crate::rustc_span::edition::Edition;
 use std::fs;
 use std::path::Path;
@@ -39,14 +39,32 @@ impl ExternalHtml {
         let bc = format!(
             "{}{}",
             bc,
-            Markdown(&m_bc, &[], id_map, codes, edition, playground).into_string()
+            Markdown {
+                content: &m_bc,
+                links: &[],
+                ids: id_map,
+                error_codes: codes,
+                edition,
+                playground,
+                heading_offset: HeadingOffset::H2,
+            }
+            .into_string()
         );
         let ac = load_external_files(after_content, diag)?;
         let m_ac = load_external_files(md_after_content, diag)?;
         let ac = format!(
             "{}{}",
             ac,
-            Markdown(&m_ac, &[], id_map, codes, edition, playground).into_string()
+            Markdown {
+                content: &m_ac,
+                links: &[],
+                ids: id_map,
+                error_codes: codes,
+                edition,
+                playground,
+                heading_offset: HeadingOffset::H2,
+            }
+            .into_string()
         );
         Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac })
     }
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index fda2512a05036..9f2e282fce1c3 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -8,11 +8,19 @@
 //! extern crate rustc_span;
 //!
 //! use rustc_span::edition::Edition;
-//! use rustdoc::html::markdown::{IdMap, Markdown, ErrorCodes};
+//! use rustdoc::html::markdown::{HeadingOffset, IdMap, Markdown, ErrorCodes};
 //!
 //! let s = "My *markdown* _text_";
 //! let mut id_map = IdMap::new();
-//! let md = Markdown(s, &[], &mut id_map, ErrorCodes::Yes, Edition::Edition2015, &None);
+//! let md = Markdown {
+//!     content: s,
+//!     links: &[],
+//!     ids: &mut id_map,
+//!     error_codes: ErrorCodes::Yes,
+//!     edition: Edition::Edition2015,
+//!     playground: &None,
+//!     heading_offset: HeadingOffset::H2,
+//! };
 //! let html = md.into_string();
 //! // ... something using html
 //! ```
@@ -47,6 +55,8 @@ use pulldown_cmark::{
 #[cfg(test)]
 mod tests;
 
+const MAX_HEADER_LEVEL: u32 = 6;
+
 /// Options for rendering Markdown in the main body of documentation.
 pub(crate) fn main_body_opts() -> Options {
     Options::ENABLE_TABLES
@@ -65,20 +75,33 @@ pub(crate) fn summary_opts() -> Options {
         | Options::ENABLE_SMART_PUNCTUATION
 }
 
+#[derive(Debug, Clone, Copy)]
+pub enum HeadingOffset {
+    H1 = 0,
+    H2,
+    H3,
+    H4,
+    H5,
+    H6,
+}
+
 /// When `to_string` is called, this struct will emit the HTML corresponding to
 /// the rendered version of the contained markdown string.
-pub struct Markdown<'a>(
-    pub &'a str,
+pub struct Markdown<'a> {
+    pub content: &'a str,
     /// A list of link replacements.
-    pub &'a [RenderedLink],
+    pub links: &'a [RenderedLink],
     /// The current list of used header IDs.
-    pub &'a mut IdMap,
+    pub ids: &'a mut IdMap,
     /// Whether to allow the use of explicit error codes in doctest lang strings.
-    pub ErrorCodes,
+    pub error_codes: ErrorCodes,
     /// Default edition to use when parsing doctests (to add a `fn main`).
-    pub Edition,
-    pub &'a Option<Playground>,
-);
+    pub edition: Edition,
+    pub playground: &'a Option<Playground>,
+    /// Offset at which we render headings.
+    /// E.g. if `heading_offset: HeadingOffset::H2`, then `# something` renders an `<h2>`.
+    pub heading_offset: HeadingOffset,
+}
 /// A tuple struct like `Markdown` that renders the markdown with a table of contents.
 crate struct MarkdownWithToc<'a>(
     crate &'a str,
@@ -489,11 +512,17 @@ struct HeadingLinks<'a, 'b, 'ids, I> {
     toc: Option<&'b mut TocBuilder>,
     buf: VecDeque<SpannedEvent<'a>>,
     id_map: &'ids mut IdMap,
+    heading_offset: HeadingOffset,
 }
 
 impl<'a, 'b, 'ids, I> HeadingLinks<'a, 'b, 'ids, I> {
-    fn new(iter: I, toc: Option<&'b mut TocBuilder>, ids: &'ids mut IdMap) -> Self {
-        HeadingLinks { inner: iter, toc, buf: VecDeque::new(), id_map: ids }
+    fn new(
+        iter: I,
+        toc: Option<&'b mut TocBuilder>,
+        ids: &'ids mut IdMap,
+        heading_offset: HeadingOffset,
+    ) -> Self {
+        HeadingLinks { inner: iter, toc, buf: VecDeque::new(), id_map: ids, heading_offset }
     }
 }
 
@@ -530,6 +559,7 @@ impl<'a, 'b, 'ids, I: Iterator<Item = SpannedEvent<'a>>> Iterator
                 self.buf.push_front((Event::Html(format!("{} ", sec).into()), 0..0));
             }
 
+            let level = std::cmp::min(level + (self.heading_offset as u32), MAX_HEADER_LEVEL);
             self.buf.push_back((Event::Html(format!("</a></h{}>", level).into()), 0..0));
 
             let start_tags = format!(
@@ -1005,7 +1035,15 @@ impl LangString {
 
 impl Markdown<'_> {
     pub fn into_string(self) -> String {
-        let Markdown(md, links, mut ids, codes, edition, playground) = self;
+        let Markdown {
+            content: md,
+            links,
+            mut ids,
+            error_codes: codes,
+            edition,
+            playground,
+            heading_offset,
+        } = self;
 
         // This is actually common enough to special-case
         if md.is_empty() {
@@ -1026,7 +1064,7 @@ impl Markdown<'_> {
 
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        let p = HeadingLinks::new(p, None, &mut ids);
+        let p = HeadingLinks::new(p, None, &mut ids, heading_offset);
         let p = Footnotes::new(p);
         let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
         let p = TableWrapper::new(p);
@@ -1048,7 +1086,7 @@ impl MarkdownWithToc<'_> {
         let mut toc = TocBuilder::new();
 
         {
-            let p = HeadingLinks::new(p, Some(&mut toc), &mut ids);
+            let p = HeadingLinks::new(p, Some(&mut toc), &mut ids, HeadingOffset::H1);
             let p = Footnotes::new(p);
             let p = TableWrapper::new(p.map(|(ev, _)| ev));
             let p = CodeBlocks::new(p, codes, edition, playground);
@@ -1077,7 +1115,7 @@ impl MarkdownHtml<'_> {
 
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        let p = HeadingLinks::new(p, None, &mut ids);
+        let p = HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1);
         let p = Footnotes::new(p);
         let p = TableWrapper::new(p.map(|(ev, _)| ev));
         let p = CodeBlocks::new(p, codes, edition, playground);
@@ -1295,7 +1333,7 @@ crate fn markdown_links(md: &str) -> Vec<MarkdownLink> {
     // There's no need to thread an IdMap through to here because
     // the IDs generated aren't going to be emitted anywhere.
     let mut ids = IdMap::new();
-    let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids));
+    let iter = Footnotes::new(HeadingLinks::new(p, None, &mut ids, HeadingOffset::H1));
 
     for ev in iter {
         if let Event::Start(Tag::Link(kind, dest, _)) = ev.0 {
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index 1e4cf3381f6a3..68ab002f13867 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -1,5 +1,5 @@
 use super::{find_testable_code, plain_text_summary, short_markdown_summary};
-use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml};
+use super::{ErrorCodes, HeadingOffset, IdMap, Ignore, LangString, Markdown, MarkdownHtml};
 use rustc_span::edition::{Edition, DEFAULT_EDITION};
 
 #[test]
@@ -147,33 +147,41 @@ fn test_lang_string_tokenizer() {
 fn test_header() {
     fn t(input: &str, expect: &str) {
         let mut map = IdMap::new();
-        let output =
-            Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
+        let output = Markdown {
+            content: input,
+            links: &[],
+            ids: &mut map,
+            error_codes: ErrorCodes::Yes,
+            edition: DEFAULT_EDITION,
+            playground: &None,
+            heading_offset: HeadingOffset::H2,
+        }
+        .into_string();
         assert_eq!(output, expect, "original: {}", input);
     }
 
     t(
         "# Foo bar",
-        "<h1 id=\"foo-bar\" class=\"section-header\"><a href=\"#foo-bar\">Foo bar</a></h1>",
+        "<h2 id=\"foo-bar\" class=\"section-header\"><a href=\"#foo-bar\">Foo bar</a></h2>",
     );
     t(
         "## Foo-bar_baz qux",
-        "<h2 id=\"foo-bar_baz-qux\" class=\"section-header\">\
-         <a href=\"#foo-bar_baz-qux\">Foo-bar_baz qux</a></h2>",
+        "<h3 id=\"foo-bar_baz-qux\" class=\"section-header\">\
+         <a href=\"#foo-bar_baz-qux\">Foo-bar_baz qux</a></h3>",
     );
     t(
         "### **Foo** *bar* baz!?!& -_qux_-%",
-        "<h3 id=\"foo-bar-baz--qux-\" class=\"section-header\">\
+        "<h4 id=\"foo-bar-baz--qux-\" class=\"section-header\">\
             <a href=\"#foo-bar-baz--qux-\"><strong>Foo</strong> \
             <em>bar</em> baz!?!&amp; -<em>qux</em>-%</a>\
-         </h3>",
+         </h4>",
     );
     t(
         "#### **Foo?** & \\*bar?!*  _`baz`_ ❤ #qux",
-        "<h4 id=\"foo--bar--baz--qux\" class=\"section-header\">\
+        "<h5 id=\"foo--bar--baz--qux\" class=\"section-header\">\
              <a href=\"#foo--bar--baz--qux\"><strong>Foo?</strong> &amp; *bar?!*  \
              <em><code>baz</code></em> ❤ #qux</a>\
-         </h4>",
+         </h5>",
     );
 }
 
@@ -181,40 +189,48 @@ fn test_header() {
 fn test_header_ids_multiple_blocks() {
     let mut map = IdMap::new();
     fn t(map: &mut IdMap, input: &str, expect: &str) {
-        let output =
-            Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
+        let output = Markdown {
+            content: input,
+            links: &[],
+            ids: map,
+            error_codes: ErrorCodes::Yes,
+            edition: DEFAULT_EDITION,
+            playground: &None,
+            heading_offset: HeadingOffset::H2,
+        }
+        .into_string();
         assert_eq!(output, expect, "original: {}", input);
     }
 
     t(
         &mut map,
         "# Example",
-        "<h1 id=\"example\" class=\"section-header\"><a href=\"#example\">Example</a></h1>",
+        "<h2 id=\"example\" class=\"section-header\"><a href=\"#example\">Example</a></h2>",
     );
     t(
         &mut map,
         "# Panics",
-        "<h1 id=\"panics\" class=\"section-header\"><a href=\"#panics\">Panics</a></h1>",
+        "<h2 id=\"panics\" class=\"section-header\"><a href=\"#panics\">Panics</a></h2>",
     );
     t(
         &mut map,
         "# Example",
-        "<h1 id=\"example-1\" class=\"section-header\"><a href=\"#example-1\">Example</a></h1>",
+        "<h2 id=\"example-1\" class=\"section-header\"><a href=\"#example-1\">Example</a></h2>",
     );
     t(
         &mut map,
         "# Main",
-        "<h1 id=\"main-1\" class=\"section-header\"><a href=\"#main-1\">Main</a></h1>",
+        "<h2 id=\"main-1\" class=\"section-header\"><a href=\"#main-1\">Main</a></h2>",
     );
     t(
         &mut map,
         "# Example",
-        "<h1 id=\"example-2\" class=\"section-header\"><a href=\"#example-2\">Example</a></h1>",
+        "<h2 id=\"example-2\" class=\"section-header\"><a href=\"#example-2\">Example</a></h2>",
     );
     t(
         &mut map,
         "# Panics",
-        "<h1 id=\"panics-1\" class=\"section-header\"><a href=\"#panics-1\">Panics</a></h1>",
+        "<h2 id=\"panics-1\" class=\"section-header\"><a href=\"#panics-1\">Panics</a></h2>",
     );
 }
 
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 5045a99800ab1..11682afdf899b 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -67,7 +67,7 @@ use crate::html::format::{
     href, print_abi_with_space, print_constness_with_space, print_default_space,
     print_generic_bounds, print_where_clause, Buffer, HrefError, PrintWithSpace,
 };
-use crate::html::markdown::{Markdown, MarkdownHtml, MarkdownSummaryLine};
+use crate::html::markdown::{HeadingOffset, Markdown, MarkdownHtml, MarkdownSummaryLine};
 
 /// A pair of name and its optional document.
 crate type NameDoc = (String, Option<String>);
@@ -470,32 +470,45 @@ fn settings(root_path: &str, suffix: &str, themes: &[StylePath]) -> Result<Strin
     ))
 }
 
-fn document(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, parent: Option<&clean::Item>) {
+fn document(
+    w: &mut Buffer,
+    cx: &Context<'_>,
+    item: &clean::Item,
+    parent: Option<&clean::Item>,
+    heading_offset: HeadingOffset,
+) {
     if let Some(ref name) = item.name {
         info!("Documenting {}", name);
     }
     document_item_info(w, cx, item, parent);
     if parent.is_none() {
-        document_full_collapsible(w, item, cx);
+        document_full_collapsible(w, item, cx, heading_offset);
     } else {
-        document_full(w, item, cx);
+        document_full(w, item, cx, heading_offset);
     }
 }
 
 /// Render md_text as markdown.
-fn render_markdown(w: &mut Buffer, cx: &Context<'_>, md_text: &str, links: Vec<RenderedLink>) {
+fn render_markdown(
+    w: &mut Buffer,
+    cx: &Context<'_>,
+    md_text: &str,
+    links: Vec<RenderedLink>,
+    heading_offset: HeadingOffset,
+) {
     let mut ids = cx.id_map.borrow_mut();
     write!(
         w,
         "<div class=\"docblock\">{}</div>",
-        Markdown(
-            md_text,
-            &links,
-            &mut ids,
-            cx.shared.codes,
-            cx.shared.edition(),
-            &cx.shared.playground
-        )
+        Markdown {
+            content: md_text,
+            links: &links,
+            ids: &mut ids,
+            error_codes: cx.shared.codes,
+            edition: cx.shared.edition(),
+            playground: &cx.shared.playground,
+            heading_offset,
+        }
         .into_string()
     )
 }
@@ -531,15 +544,31 @@ fn document_short(
     }
 }
 
-fn document_full_collapsible(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) {
-    document_full_inner(w, item, cx, true);
+fn document_full_collapsible(
+    w: &mut Buffer,
+    item: &clean::Item,
+    cx: &Context<'_>,
+    heading_offset: HeadingOffset,
+) {
+    document_full_inner(w, item, cx, true, heading_offset);
 }
 
-fn document_full(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>) {
-    document_full_inner(w, item, cx, false);
+fn document_full(
+    w: &mut Buffer,
+    item: &clean::Item,
+    cx: &Context<'_>,
+    heading_offset: HeadingOffset,
+) {
+    document_full_inner(w, item, cx, false, heading_offset);
 }
 
-fn document_full_inner(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_collapsible: bool) {
+fn document_full_inner(
+    w: &mut Buffer,
+    item: &clean::Item,
+    cx: &Context<'_>,
+    is_collapsible: bool,
+    heading_offset: HeadingOffset,
+) {
     if let Some(s) = cx.shared.maybe_collapsed_doc_value(item) {
         debug!("Doc block: =====\n{}\n=====", s);
         if is_collapsible {
@@ -549,10 +578,10 @@ fn document_full_inner(w: &mut Buffer, item: &clean::Item, cx: &Context<'_>, is_
                      <span>Expand description</span>\
                 </summary>",
             );
-            render_markdown(w, cx, &s, item.links(cx));
+            render_markdown(w, cx, &s, item.links(cx), heading_offset);
             w.write_str("</details>");
         } else {
-            render_markdown(w, cx, &s, item.links(cx));
+            render_markdown(w, cx, &s, item.links(cx), heading_offset);
         }
     }
 }
@@ -1321,7 +1350,7 @@ fn render_impl(
                         // because impls can't have a stability.
                         if item.doc_value().is_some() {
                             document_item_info(&mut info_buffer, cx, it, Some(parent));
-                            document_full(&mut doc_buffer, item, cx);
+                            document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
                             short_documented = false;
                         } else {
                             // In case the item isn't documented,
@@ -1339,7 +1368,7 @@ fn render_impl(
                 } else {
                     document_item_info(&mut info_buffer, cx, item, Some(parent));
                     if rendering_params.show_def_docs {
-                        document_full(&mut doc_buffer, item, cx);
+                        document_full(&mut doc_buffer, item, cx, HeadingOffset::H5);
                         short_documented = false;
                     }
                 }
@@ -1573,14 +1602,15 @@ fn render_impl(
             write!(
                 w,
                 "<div class=\"docblock\">{}</div>",
-                Markdown(
-                    &*dox,
-                    &i.impl_item.links(cx),
-                    &mut ids,
-                    cx.shared.codes,
-                    cx.shared.edition(),
-                    &cx.shared.playground
-                )
+                Markdown {
+                    content: &*dox,
+                    links: &i.impl_item.links(cx),
+                    ids: &mut ids,
+                    error_codes: cx.shared.codes,
+                    edition: cx.shared.edition(),
+                    playground: &cx.shared.playground,
+                    heading_offset: HeadingOffset::H2
+                }
                 .into_string()
             );
         }
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 28b2eded7cc3e..1275fa4e15617 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -30,7 +30,7 @@ use crate::html::format::{
 };
 use crate::html::highlight;
 use crate::html::layout::Page;
-use crate::html::markdown::MarkdownSummaryLine;
+use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
 
 const ITEM_TABLE_OPEN: &'static str = "<div class=\"item-table\">";
 const ITEM_TABLE_CLOSE: &'static str = "</div>";
@@ -175,7 +175,7 @@ fn toggle_close(w: &mut Buffer) {
 }
 
 fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[clean::Item]) {
-    document(w, cx, item, None);
+    document(w, cx, item, None, HeadingOffset::H2);
 
     let mut indices = (0..items.len()).filter(|i| !items[*i].is_stripped()).collect::<Vec<usize>>();
 
@@ -482,7 +482,7 @@ fn item_function(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, f: &clean::
             notable_traits = notable_traits_decl(&f.decl, cx),
         );
     });
-    document(w, cx, it, None)
+    document(w, cx, it, None, HeadingOffset::H2)
 }
 
 fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Trait) {
@@ -605,7 +605,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
     });
 
     // Trait documentation
-    document(w, cx, it, None);
+    document(w, cx, it, None, HeadingOffset::H2);
 
     fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) {
         write!(
@@ -623,7 +623,7 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra
         let item_type = m.type_();
         let id = cx.derive_id(format!("{}.{}", item_type, name));
         let mut content = Buffer::empty_from(w);
-        document(&mut content, cx, m, Some(t));
+        document(&mut content, cx, m, Some(t), HeadingOffset::H5);
         let toggled = !content.is_empty();
         if toggled {
             write!(w, "<details class=\"rustdoc-toggle\" open><summary>");
@@ -837,7 +837,7 @@ fn item_trait_alias(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clea
         );
     });
 
-    document(w, cx, it, None);
+    document(w, cx, it, None, HeadingOffset::H2);
 
     // Render any items associated directly to this alias, as otherwise they
     // won't be visible anywhere in the docs. It would be nice to also show
@@ -859,7 +859,7 @@ fn item_opaque_ty(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean:
         );
     });
 
-    document(w, cx, it, None);
+    document(w, cx, it, None, HeadingOffset::H2);
 
     // Render any items associated directly to this alias, as otherwise they
     // won't be visible anywhere in the docs. It would be nice to also show
@@ -890,7 +890,7 @@ fn item_typedef(
         );
     });
 
-    document(w, cx, it, None);
+    document(w, cx, it, None, HeadingOffset::H2);
 
     let def_id = it.def_id.expect_def_id();
     // Render any items associated directly to this alias, as otherwise they
@@ -908,7 +908,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
         });
     });
 
-    document(w, cx, it, None);
+    document(w, cx, it, None, HeadingOffset::H2);
 
     let mut fields = s
         .fields
@@ -941,7 +941,7 @@ fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Uni
             if let Some(stability_class) = field.stability_class(cx.tcx()) {
                 write!(w, "<span class=\"stab {stab}\"></span>", stab = stability_class);
             }
-            document(w, cx, field, Some(it));
+            document(w, cx, field, Some(it), HeadingOffset::H2);
         }
     }
     let def_id = it.def_id.expect_def_id();
@@ -1023,7 +1023,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
         });
     });
 
-    document(w, cx, it, None);
+    document(w, cx, it, None, HeadingOffset::H2);
 
     if !e.variants.is_empty() {
         write!(
@@ -1052,7 +1052,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
             w.write_str("</code>");
             render_stability_since(w, variant, it, cx.tcx());
             w.write_str("</div>");
-            document(w, cx, variant, Some(it));
+            document(w, cx, variant, Some(it), HeadingOffset::H2);
             document_non_exhaustive(w, variant);
 
             use crate::clean::Variant;
@@ -1092,7 +1092,7 @@ fn item_enum(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, e: &clean::Enum
                                 f = field.name.as_ref().unwrap(),
                                 t = ty.print(cx)
                             );
-                            document(w, cx, field, Some(variant));
+                            document(w, cx, field, Some(variant), HeadingOffset::H2);
                         }
                         _ => unreachable!(),
                     }
@@ -1119,7 +1119,7 @@ fn item_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Mac
             None,
         );
     });
-    document(w, cx, it, None)
+    document(w, cx, it, None, HeadingOffset::H2)
 }
 
 fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean::ProcMacro) {
@@ -1149,11 +1149,11 @@ fn item_proc_macro(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, m: &clean
             });
         }
     }
-    document(w, cx, it, None)
+    document(w, cx, it, None, HeadingOffset::H2)
 }
 
 fn item_primitive(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
-    document(w, cx, it, None);
+    document(w, cx, it, None, HeadingOffset::H2);
     render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All)
 }
 
@@ -1192,7 +1192,7 @@ fn item_constant(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, c: &clean::
         }
     });
 
-    document(w, cx, it, None)
+    document(w, cx, it, None, HeadingOffset::H2)
 }
 
 fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Struct) {
@@ -1203,7 +1203,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
         });
     });
 
-    document(w, cx, it, None);
+    document(w, cx, it, None, HeadingOffset::H2);
 
     let mut fields = s
         .fields
@@ -1239,7 +1239,7 @@ fn item_struct(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
                     name = field_name,
                     ty = ty.print(cx)
                 );
-                document(w, cx, field, Some(it));
+                document(w, cx, field, Some(it), HeadingOffset::H2);
             }
         }
     }
@@ -1260,7 +1260,7 @@ fn item_static(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::St
             typ = s.type_.print(cx)
         );
     });
-    document(w, cx, it, None)
+    document(w, cx, it, None, HeadingOffset::H2)
 }
 
 fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
@@ -1275,13 +1275,13 @@ fn item_foreign_type(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
         );
     });
 
-    document(w, cx, it, None);
+    document(w, cx, it, None, HeadingOffset::H2);
 
     render_assoc_items(w, cx, it, it.def_id.expect_def_id(), AssocItemRender::All)
 }
 
 fn item_keyword(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item) {
-    document(w, cx, it, None)
+    document(w, cx, it, None, HeadingOffset::H2)
 }
 
 /// Compare two strings treating multi-digit numbers as single units (i.e. natural sort order).
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 341d9b80fd82d..5d33681847a41 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -126,7 +126,7 @@ h2 {
 h3 {
 	font-size: 1.3em;
 }
-h1, h2, h3, h4 {
+h1, h2, h3, h4, h5, h6 {
 	font-weight: 500;
 	margin: 20px 0 15px 0;
 	padding-bottom: 6px;
@@ -179,7 +179,7 @@ div.impl-items > div {
 	padding-left: 0;
 }
 
-h1, h2, h3, h4,
+h1, h2, h3, h4, h5, h6,
 .sidebar, a.source, .search-input, .search-results .result-name,
 .content table td:first-child > a,
 .item-left > a,
@@ -501,21 +501,20 @@ nav.sub {
 	white-space: pre-wrap;
 }
 
-.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
+.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
 	border-bottom: 1px solid;
 }
 
-.top-doc .docblock h1 { font-size: 1.3em; }
-.top-doc .docblock h2 { font-size: 1.15em; }
-.top-doc .docblock h3,
+.top-doc .docblock h2 { font-size: 1.3em; }
+.top-doc .docblock h3 { font-size: 1.15em; }
 .top-doc .docblock h4,
-.top-doc .docblock h5 {
+.top-doc .docblock h5,
+.top-doc .docblock h6 {
 	font-size: 1em;
 }
 
-.docblock h1 { font-size: 1em; }
-.docblock h2 { font-size: 0.95em; }
-.docblock h3, .docblock h4, .docblock h5 { font-size: 0.9em; }
+.docblock h5 { font-size: 1em; }
+.docblock h6 { font-size: 0.95em; }
 
 .docblock {
 	margin-left: 24px;
diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css
index c79801e830876..0fd6462a8f5dd 100644
--- a/src/librustdoc/html/static/css/themes/ayu.css
+++ b/src/librustdoc/html/static/css/themes/ayu.css
@@ -136,7 +136,7 @@ pre, .rustdoc.source .example-wrap {
 	border-right: 1px solid #ffb44c;
 }
 
-.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
+.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
 	border-bottom-color: #5c6773;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css
index d2e54070acd68..d863701dd73c7 100644
--- a/src/librustdoc/html/static/css/themes/dark.css
+++ b/src/librustdoc/html/static/css/themes/dark.css
@@ -93,7 +93,7 @@ pre, .rustdoc.source .example-wrap {
 	background-color: #0a042f !important;
 }
 
-.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
+.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
 	border-bottom-color: #DDD;
 }
 
diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css
index 25d810560c146..28d2e99a3d073 100644
--- a/src/librustdoc/html/static/css/themes/light.css
+++ b/src/librustdoc/html/static/css/themes/light.css
@@ -93,7 +93,7 @@ pre, .rustdoc.source .example-wrap {
 	background-color: #f6fdb0 !important;
 }
 
-.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5 {
+.docblock h1, .docblock h2, .docblock h3, .docblock h4, .docblock h5, .docblock h6 {
 	border-bottom-color: #ddd;
 }
 
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index 2ae4897dc3496..47b24d40edc27 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -10,7 +10,9 @@ use crate::config::{Options, RenderOptions};
 use crate::doctest::{Collector, TestOptions};
 use crate::html::escape::Escape;
 use crate::html::markdown;
-use crate::html::markdown::{find_testable_code, ErrorCodes, IdMap, Markdown, MarkdownWithToc};
+use crate::html::markdown::{
+    find_testable_code, ErrorCodes, HeadingOffset, IdMap, Markdown, MarkdownWithToc,
+};
 
 /// Separate any lines at the start of the file that begin with `# ` or `%`.
 fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) {
@@ -70,7 +72,16 @@ crate fn render<P: AsRef<Path>>(
     let text = if !options.markdown_no_toc {
         MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string()
     } else {
-        Markdown(text, &[], &mut ids, error_codes, edition, &playground).into_string()
+        Markdown {
+            content: text,
+            links: &[],
+            ids: &mut ids,
+            error_codes,
+            edition,
+            playground: &playground,
+            heading_offset: HeadingOffset::H1,
+        }
+        .into_string()
     };
 
     let err = write!(
diff --git a/src/test/codegen/alloc-optimisation.rs b/src/test/codegen/alloc-optimisation.rs
index 5b27f3f45457d..aee93b93e3737 100644
--- a/src/test/codegen/alloc-optimisation.rs
+++ b/src/test/codegen/alloc-optimisation.rs
@@ -1,4 +1,5 @@
 //
+// no-system-llvm
 // min-llvm-version: 10.0.1
 // compile-flags: -O
 #![crate_type="lib"]
diff --git a/src/test/rustdoc/external-cross.rs b/src/test/rustdoc/external-cross.rs
index 056ed3534624b..3f8e16882911a 100644
--- a/src/test/rustdoc/external-cross.rs
+++ b/src/test/rustdoc/external-cross.rs
@@ -6,5 +6,5 @@
 extern crate external_cross;
 
 // @has host/struct.NeedMoreDocs.html
-// @has - '//h1' 'Cross-crate imported docs'
+// @has - '//h2' 'Cross-crate imported docs'
 pub use external_cross::NeedMoreDocs;
diff --git a/src/test/rustdoc/external-doc.rs b/src/test/rustdoc/external-doc.rs
index fc29cb252e26c..bd322d67a370d 100644
--- a/src/test/rustdoc/external-doc.rs
+++ b/src/test/rustdoc/external-doc.rs
@@ -1,6 +1,6 @@
 // @has external_doc/struct.IncludeStrDocs.html
-// @has - '//h1' 'External Docs'
-// @has - '//h2' 'Inline Docs'
+// @has - '//h2' 'External Docs'
+// @has - '//h3' 'Inline Docs'
 #[doc = include_str!("auxiliary/external-doc.md")]
 /// ## Inline Docs
 pub struct IncludeStrDocs;
@@ -8,7 +8,7 @@ pub struct IncludeStrDocs;
 macro_rules! dir { () => { "auxiliary" } }
 
 // @has external_doc/struct.EagerExpansion.html
-// @has - '//h1' 'External Docs'
+// @has - '//h2' 'External Docs'
 #[doc = include_str!(concat!(dir!(), "/external-doc.md"))]
 /// ## Inline Docs
 pub struct EagerExpansion;
diff --git a/src/test/rustdoc/issue-42760.rs b/src/test/rustdoc/issue-42760.rs
index b07dc3f6e967b..4944f8157014e 100644
--- a/src/test/rustdoc/issue-42760.rs
+++ b/src/test/rustdoc/issue-42760.rs
@@ -1,5 +1,5 @@
 // @has issue_42760/struct.NonGen.html
-// @has - '//h1' 'Example'
+// @has - '//h2' 'Example'
 
 /// Item docs.
 ///
diff --git a/src/test/rustdoc/issue-89309-heading-levels.rs b/src/test/rustdoc/issue-89309-heading-levels.rs
new file mode 100644
index 0000000000000..bb706c28ffa51
--- /dev/null
+++ b/src/test/rustdoc/issue-89309-heading-levels.rs
@@ -0,0 +1,29 @@
+#![crate_name = "foo"]
+
+// @has foo/trait.Read.html
+// @has - '//h2' 'Trait examples'
+/// # Trait examples
+pub trait Read {
+    // @has - '//h5' 'Function examples'
+    /// # Function examples
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()>;
+}
+
+pub struct Foo;
+
+// @has foo/struct.Foo.html
+impl Foo {
+    // @has - '//h5' 'Implementation header'
+    /// # Implementation header
+    pub fn bar(&self) -> usize {
+        1
+    }
+}
+
+impl Read for Foo {
+    // @has - '//h5' 'Trait implementation header'
+    /// # Trait implementation header
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize, ()> {
+        Ok(1)
+    }
+}
diff --git a/src/test/rustdoc/short-docblock.rs b/src/test/rustdoc/short-docblock.rs
index 74fa783174da8..17c44eab091a6 100644
--- a/src/test/rustdoc/short-docblock.rs
+++ b/src/test/rustdoc/short-docblock.rs
@@ -2,7 +2,7 @@
 
 // @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'fooo'
 // @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h1' 'fooo'
-// @has foo/fn.foo.html '//h1[@id="fooo"]/a[@href="#fooo"]' 'fooo'
+// @has foo/fn.foo.html '//h2[@id="fooo"]/a[@href="#fooo"]' 'fooo'
 
 /// # fooo
 ///
@@ -11,7 +11,7 @@ pub fn foo() {}
 
 // @has foo/index.html '//*[@class="item-right docblock-short"]/p' 'mooood'
 // @!has foo/index.html '//*[@class="item-right docblock-short"]/p/h2' 'mooood'
-// @has foo/foo/index.html '//h2[@id="mooood"]/a[@href="#mooood"]' 'mooood'
+// @has foo/foo/index.html '//h3[@id="mooood"]/a[@href="#mooood"]' 'mooood'
 
 /// ## mooood
 ///
diff --git a/src/test/rustdoc/smart-punct.rs b/src/test/rustdoc/smart-punct.rs
index 5319892c99c23..7ae5bd6994579 100644
--- a/src/test/rustdoc/smart-punct.rs
+++ b/src/test/rustdoc/smart-punct.rs
@@ -21,7 +21,7 @@
 //! ```
 
 // @has "foo/index.html" "//p" "This is the “start” of the ‘document’! How’d you know that “it’s” the start?"
-// @has "foo/index.html" "//h1" "Header with “smart punct’”"
+// @has "foo/index.html" "//h2" "Header with “smart punct’”"
 // @has "foo/index.html" '//a[@href="https://www.rust-lang.org"]' "link with “smart punct’” – yessiree!"
 // @has "foo/index.html" '//code' "this inline code -- it shouldn't have \"smart punct\""
 // @has "foo/index.html" '//pre' "let x = \"don't smart-punct me -- please!\";"
diff --git a/src/test/ui/async-await/issues/issue-62097.nll.stderr b/src/test/ui/async-await/issues/issue-62097.nll.stderr
index e71bcf5822808..786f621326049 100644
--- a/src/test/ui/async-await/issues/issue-62097.nll.stderr
+++ b/src/test/ui/async-await/issues/issue-62097.nll.stderr
@@ -20,9 +20,15 @@ error[E0521]: borrowed data escapes outside of associated function
   --> $DIR/issue-62097.rs:13:9
    |
 LL |     pub async fn run_dummy_fn(&self) {
-   |                               ----- `self` is a reference that is only valid in the associated function body
+   |                               -----
+   |                               |
+   |                               `self` is a reference that is only valid in the associated function body
+   |                               let's call the lifetime of this reference `'1`
 LL |         foo(|| self.bar()).await;
-   |         ^^^^^^^^^^^^^^^^^^ `self` escapes the associated function body here
+   |         ^^^^^^^^^^^^^^^^^^
+   |         |
+   |         `self` escapes the associated function body here
+   |         argument requires that `'1` must outlive `'static`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/cast/issue-89497.fixed b/src/test/ui/cast/issue-89497.fixed
new file mode 100644
index 0000000000000..04c10a5f79ed4
--- /dev/null
+++ b/src/test/ui/cast/issue-89497.fixed
@@ -0,0 +1,10 @@
+// Regression test for issue #89497.
+
+// run-rustfix
+
+fn main() {
+    let pointer: usize = &1_i32 as *const i32 as usize;
+    let _reference: &'static i32 = unsafe { &*(pointer as *const i32) };
+    //~^ ERROR: non-primitive cast
+    //~| HELP: consider borrowing the value
+}
diff --git a/src/test/ui/cast/issue-89497.rs b/src/test/ui/cast/issue-89497.rs
new file mode 100644
index 0000000000000..76301b704c81c
--- /dev/null
+++ b/src/test/ui/cast/issue-89497.rs
@@ -0,0 +1,10 @@
+// Regression test for issue #89497.
+
+// run-rustfix
+
+fn main() {
+    let pointer: usize = &1_i32 as *const i32 as usize;
+    let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 };
+    //~^ ERROR: non-primitive cast
+    //~| HELP: consider borrowing the value
+}
diff --git a/src/test/ui/cast/issue-89497.stderr b/src/test/ui/cast/issue-89497.stderr
new file mode 100644
index 0000000000000..3726f8a41015e
--- /dev/null
+++ b/src/test/ui/cast/issue-89497.stderr
@@ -0,0 +1,15 @@
+error[E0605]: non-primitive cast: `*const i32` as `&'static i32`
+  --> $DIR/issue-89497.rs:7:45
+   |
+LL |     let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 };
+   |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast
+   |
+help: consider borrowing the value
+   |
+LL -     let _reference: &'static i32 = unsafe { pointer as *const i32 as &'static i32 };
+LL +     let _reference: &'static i32 = unsafe { &*(pointer as *const i32) };
+   | 
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0605`.
diff --git a/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs
new file mode 100644
index 0000000000000..b79bc262d2bac
--- /dev/null
+++ b/src/test/ui/const-generics/generic_const_exprs/const_eval_resolve_canonical.rs
@@ -0,0 +1,29 @@
+// run-pass
+#![feature(generic_const_exprs)]
+#![allow(incomplete_features)]
+
+trait Foo<const N: usize> {
+    type Assoc: Default;
+}
+
+impl Foo<0> for () {
+    type Assoc = u32;
+}
+
+impl Foo<3> for () {
+    type Assoc = i64;
+}
+
+fn foo<T, const N: usize>(_: T) -> <() as Foo<{ N + 1 }>>::Assoc
+where
+    (): Foo<{ N + 1 }>,
+{
+    Default::default()
+}
+
+fn main() {
+    // Test that we can correctly infer `T` which requires evaluating
+    // `{ N + 1 }` which has substs containing an inference var
+    let mut _q = Default::default();
+    _q = foo::<_, 2>(_q);
+}
diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr
index e5647ee6d0968..d082b6c10cc2a 100644
--- a/src/test/ui/error-codes/E0605.stderr
+++ b/src/test/ui/error-codes/E0605.stderr
@@ -12,8 +12,9 @@ LL |     v as &u8;
    |
 help: consider borrowing the value
    |
-LL |     &*v as &u8;
-   |     ++
+LL -     v as &u8;
+LL +     &*v;
+   | 
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr
index e49bd9da754d6..88c260b18cbb0 100644
--- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr
+++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.nll.stderr
@@ -2,9 +2,14 @@ error[E0521]: borrowed data escapes outside of function
   --> $DIR/dyn-trait.rs:20:5
    |
 LL | fn with_dyn_debug_static<'a>(x: Box<dyn Debug + 'a>) {
-   |                              - `x` is a reference that is only valid in the function body
+   |                          --  - `x` is a reference that is only valid in the function body
+   |                          |
+   |                          lifetime `'a` defined here
 LL |     static_val(x);
-   |     ^^^^^^^^^^^^^ `x` escapes the function body here
+   |     ^^^^^^^^^^^^^
+   |     |
+   |     `x` escapes the function body here
+   |     argument requires that `'a` must outlive `'static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-16683.nll.stderr b/src/test/ui/issues/issue-16683.nll.stderr
index 51d86eaf9e60c..0e8f520353fba 100644
--- a/src/test/ui/issues/issue-16683.nll.stderr
+++ b/src/test/ui/issues/issue-16683.nll.stderr
@@ -1,10 +1,19 @@
 error[E0521]: borrowed data escapes outside of associated function
   --> $DIR/issue-16683.rs:4:9
    |
+LL | trait T<'a> {
+   |         -- lifetime `'a` defined here
+LL |     fn a(&'a self) -> &'a bool;
 LL |     fn b(&self) {
-   |          ----- `self` is a reference that is only valid in the associated function body
+   |          -----
+   |          |
+   |          `self` is a reference that is only valid in the associated function body
+   |          let's call the lifetime of this reference `'1`
 LL |         self.a();
-   |         ^^^^^^^^ `self` escapes the associated function body here
+   |         ^^^^^^^^
+   |         |
+   |         `self` escapes the associated function body here
+   |         argument requires that `'1` must outlive `'a`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17758.nll.stderr b/src/test/ui/issues/issue-17758.nll.stderr
index 075c141ed7af6..b929fdbf3687a 100644
--- a/src/test/ui/issues/issue-17758.nll.stderr
+++ b/src/test/ui/issues/issue-17758.nll.stderr
@@ -1,10 +1,19 @@
 error[E0521]: borrowed data escapes outside of associated function
   --> $DIR/issue-17758.rs:7:9
    |
+LL | trait Foo<'a> {
+   |           -- lifetime `'a` defined here
+LL |     fn foo(&'a self);
 LL |     fn bar(&self) {
-   |            ----- `self` is a reference that is only valid in the associated function body
+   |            -----
+   |            |
+   |            `self` is a reference that is only valid in the associated function body
+   |            let's call the lifetime of this reference `'1`
 LL |         self.foo();
-   |         ^^^^^^^^^^ `self` escapes the associated function body here
+   |         ^^^^^^^^^^
+   |         |
+   |         `self` escapes the associated function body here
+   |         argument requires that `'1` must outlive `'a`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr
index 455d32e233ab9..7616f987d7312 100644
--- a/src/test/ui/issues/issue-2995.stderr
+++ b/src/test/ui/issues/issue-2995.stderr
@@ -6,8 +6,9 @@ LL |     let _q: &isize = p as &isize;
    |
 help: consider borrowing the value
    |
-LL |     let _q: &isize = &*p as &isize;
-   |                      ++
+LL -     let _q: &isize = p as &isize;
+LL +     let _q: &isize = &*p;
+   | 
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr
index 050d5fcf05ef4..6f3f84096e400 100644
--- a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr
+++ b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.nll.stderr
@@ -2,19 +2,29 @@ error[E0521]: borrowed data escapes outside of function
   --> $DIR/lifetime-bound-will-change-warning.rs:34:5
    |
 LL | fn test2<'a>(x: &'a Box<dyn Fn() + 'a>) {
-   |              - `x` is a reference that is only valid in the function body
+   |          --  - `x` is a reference that is only valid in the function body
+   |          |
+   |          lifetime `'a` defined here
 LL |     // but ref_obj will not, so warn.
 LL |     ref_obj(x)
-   |     ^^^^^^^^^^ `x` escapes the function body here
+   |     ^^^^^^^^^^
+   |     |
+   |     `x` escapes the function body here
+   |     argument requires that `'a` must outlive `'static`
 
 error[E0521]: borrowed data escapes outside of function
   --> $DIR/lifetime-bound-will-change-warning.rs:39:5
    |
 LL | fn test2cc<'a>(x: &'a Box<dyn Fn() + 'a>) {
-   |                - `x` is a reference that is only valid in the function body
+   |            --  - `x` is a reference that is only valid in the function body
+   |            |
+   |            lifetime `'a` defined here
 LL |     // same as test2, but cross crate
 LL |     lib::ref_obj(x)
-   |     ^^^^^^^^^^^^^^^ `x` escapes the function body here
+   |     ^^^^^^^^^^^^^^^
+   |     |
+   |     `x` escapes the function body here
+   |     argument requires that `'a` must outlive `'static`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr
index a47eb87cff06c..7f91d5ed42ce4 100644
--- a/src/test/ui/mismatched_types/cast-rfc0401.stderr
+++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr
@@ -28,8 +28,9 @@ LL |     let _ = v as &u8;
    |
 help: consider borrowing the value
    |
-LL |     let _ = &*v as &u8;
-   |             ++
+LL -     let _ = v as &u8;
+LL +     let _ = &*v;
+   | 
 
 error[E0605]: non-primitive cast: `*const u8` as `E`
   --> $DIR/cast-rfc0401.rs:30:13
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
index d17a40a95c1b8..d77793291c5c5 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr
@@ -38,14 +38,19 @@ error[E0521]: borrowed data escapes outside of function
   --> $DIR/propagate-approximated-shorter-to-static-no-bound.rs:32:5
    |
 LL |   fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
-   |                     ------ `cell_a` is a reference that is only valid in the function body
+   |             --      ------ `cell_a` is a reference that is only valid in the function body
+   |             |
+   |             lifetime `'a` defined here
 LL | /     establish_relationships(&cell_a, &cell_b, |_outlives, x, y| {
 LL | |
 LL | |
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |     });
-   | |______^ `cell_a` escapes the function body here
+   | |      ^
+   | |      |
+   | |______`cell_a` escapes the function body here
+   |        argument requires that `'a` must outlive `'static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
index 06c46ec8259a0..cc67270ad20c1 100644
--- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
+++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr
@@ -38,14 +38,19 @@ error[E0521]: borrowed data escapes outside of function
   --> $DIR/propagate-approximated-shorter-to-static-wrong-bound.rs:35:5
    |
 LL |   fn supply<'a, 'b>(cell_a: Cell<&'a u32>, cell_b: Cell<&'b u32>) {
-   |                     ------ `cell_a` is a reference that is only valid in the function body
+   |             --      ------ `cell_a` is a reference that is only valid in the function body
+   |             |
+   |             lifetime `'a` defined here
 LL | /     establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| {
 LL | |
 LL | |
 LL | |         // Only works if 'x: 'y:
 LL | |         demand_y(x, y, x.get())
 LL | |     });
-   | |______^ `cell_a` escapes the function body here
+   | |      ^
+   | |      |
+   | |______`cell_a` escapes the function body here
+   |        argument requires that `'a` must outlive `'static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-67007-escaping-data.rs b/src/test/ui/nll/issue-67007-escaping-data.rs
new file mode 100644
index 0000000000000..8c21737e05fe8
--- /dev/null
+++ b/src/test/ui/nll/issue-67007-escaping-data.rs
@@ -0,0 +1,26 @@
+// Regression test for issue #67007
+// Ensures that we show information about the specific regions involved
+
+#![feature(nll)]
+
+// Covariant over 'a, invariant over 'tcx
+struct FnCtxt<'a, 'tcx: 'a>(&'a (), *mut &'tcx ());
+
+impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
+    fn use_it(&self, _: &'tcx ()) {}
+}
+
+struct Consumer<'tcx>(&'tcx ());
+
+impl<'tcx> Consumer<'tcx> {
+    fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
+        let other = self.use_fcx(fcx); //~ ERROR borrowed data
+        fcx.use_it(other);
+    }
+
+    fn use_fcx<'a>(&self, _: &FnCtxt<'a, 'tcx>) -> &'a () {
+        &()
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/nll/issue-67007-escaping-data.stderr b/src/test/ui/nll/issue-67007-escaping-data.stderr
new file mode 100644
index 0000000000000..2834d6fb0d214
--- /dev/null
+++ b/src/test/ui/nll/issue-67007-escaping-data.stderr
@@ -0,0 +1,21 @@
+error[E0521]: borrowed data escapes outside of associated function
+  --> $DIR/issue-67007-escaping-data.rs:17:21
+   |
+LL | impl<'tcx> Consumer<'tcx> {
+   |      ---- lifetime `'tcx` defined here
+LL |     fn bad_method<'a>(&self, fcx: &FnCtxt<'a, 'tcx>) {
+   |                   --  -----  --- `fcx` is a reference that is only valid in the associated function body
+   |                   |   |
+   |                   |   `self` declared here, outside of the associated function body
+   |                   lifetime `'a` defined here
+LL |         let other = self.use_fcx(fcx);
+   |                     ^^^^^^^^^^^^^^^^^
+   |                     |
+   |                     `fcx` escapes the associated function body here
+   |                     argument requires that `'a` must outlive `'tcx`
+   |
+   = help: consider adding the following bound: `'a: 'tcx`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0521`.
diff --git a/src/test/ui/nll/outlives-suggestion-simple.stderr b/src/test/ui/nll/outlives-suggestion-simple.stderr
index fa85ce2799083..3b2017d2d03a1 100644
--- a/src/test/ui/nll/outlives-suggestion-simple.stderr
+++ b/src/test/ui/nll/outlives-suggestion-simple.stderr
@@ -92,13 +92,20 @@ LL |         self.x
 error[E0521]: borrowed data escapes outside of associated function
   --> $DIR/outlives-suggestion-simple.rs:73:9
    |
+LL | impl<'a> Foo2<'a> {
+   |      -- lifetime `'a` defined here
+LL |     // should not produce outlives suggestions to name 'self
 LL |     fn get_bar(&self) -> Bar2 {
    |                -----
    |                |
    |                `self` declared here, outside of the associated function body
    |                `self` is a reference that is only valid in the associated function body
+   |                let's call the lifetime of this reference `'1`
 LL |         Bar2::new(&self)
-   |         ^^^^^^^^^^^^^^^^ `self` escapes the associated function body here
+   |         ^^^^^^^^^^^^^^^^
+   |         |
+   |         `self` escapes the associated function body here
+   |         argument requires that `'1` must outlive `'a`
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/nll/user-annotations/closure-substs.stderr b/src/test/ui/nll/user-annotations/closure-substs.stderr
index 55bb3a6090c01..20002e4591d1a 100644
--- a/src/test/ui/nll/user-annotations/closure-substs.stderr
+++ b/src/test/ui/nll/user-annotations/closure-substs.stderr
@@ -28,9 +28,14 @@ error[E0521]: borrowed data escapes outside of closure
   --> $DIR/closure-substs.rs:29:9
    |
 LL |     |x: &i32, b: fn(&'static i32)| {
-   |      - `x` is a reference that is only valid in the closure body
+   |      -  - let's call the lifetime of this reference `'1`
+   |      |
+   |      `x` is a reference that is only valid in the closure body
 LL |         b(x);
-   |         ^^^^ `x` escapes the closure body here
+   |         ^^^^
+   |         |
+   |         `x` escapes the closure body here
+   |         argument requires that `'1` must outlive `'static`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr
index 6ce1b2eed85d2..af20c5e5fc0da 100644
--- a/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr
+++ b/src/test/ui/object-lifetime/object-lifetime-default-mybox.nll.stderr
@@ -15,9 +15,14 @@ error[E0521]: borrowed data escapes outside of function
   --> $DIR/object-lifetime-default-mybox.rs:31:5
    |
 LL | fn load2<'a>(ss: &MyBox<dyn SomeTrait + 'a>) -> MyBox<dyn SomeTrait + 'a> {
-   |              -- `ss` is a reference that is only valid in the function body
+   |          --  -- `ss` is a reference that is only valid in the function body
+   |          |
+   |          lifetime `'a` defined here
 LL |     load0(ss)
-   |     ^^^^^^^^^ `ss` escapes the function body here
+   |     ^^^^^^^^^
+   |     |
+   |     `ss` escapes the function body here
+   |     argument requires that `'a` must outlive `'static`
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/print_type_sizes/uninhabited.rs b/src/test/ui/print_type_sizes/uninhabited.rs
index c234547bd14b1..06a62db4ebb0f 100644
--- a/src/test/ui/print_type_sizes/uninhabited.rs
+++ b/src/test/ui/print_type_sizes/uninhabited.rs
@@ -11,5 +11,5 @@
 fn start(_: isize, _: *const *const u8) -> isize {
     let _x: Option<!> = None;
     let _y: Result<u32, !> = Ok(42);
-    0
+    let _z: Result<!, !> = loop {};
 }
diff --git a/src/test/ui/print_type_sizes/uninhabited.stdout b/src/test/ui/print_type_sizes/uninhabited.stdout
index 2a8706f7ac551..5eb5384bce340 100644
--- a/src/test/ui/print_type_sizes/uninhabited.stdout
+++ b/src/test/ui/print_type_sizes/uninhabited.stdout
@@ -3,3 +3,4 @@ print-type-size     variant `Ok`: 4 bytes
 print-type-size         field `.0`: 4 bytes
 print-type-size type: `std::option::Option<!>`: 0 bytes, alignment: 1 bytes
 print-type-size     variant `None`: 0 bytes
+print-type-size type: `std::result::Result<!, !>`: 0 bytes, alignment: 1 bytes
diff --git a/src/test/ui/regions/issue-78262.nll.stderr b/src/test/ui/regions/issue-78262.nll.stderr
index a35d6fd9bf885..721dafac0be76 100644
--- a/src/test/ui/regions/issue-78262.nll.stderr
+++ b/src/test/ui/regions/issue-78262.nll.stderr
@@ -2,8 +2,11 @@ error[E0521]: borrowed data escapes outside of closure
   --> $DIR/issue-78262.rs:14:26
    |
 LL |     let f = |x: &dyn TT| x.func();
-   |              -           ^^^^^^^^ `x` escapes the closure body here
-   |              |
+   |              -  -        ^^^^^^^^
+   |              |  |        |
+   |              |  |        `x` escapes the closure body here
+   |              |  |        argument requires that `'1` must outlive `'static`
+   |              |  let's call the lifetime of this reference `'1`
    |              `x` is a reference that is only valid in the closure body
 
 error: aborting due to previous error
diff --git a/src/test/ui/regions/issue-78262.polonius.stderr b/src/test/ui/regions/issue-78262.polonius.stderr
index a35d6fd9bf885..721dafac0be76 100644
--- a/src/test/ui/regions/issue-78262.polonius.stderr
+++ b/src/test/ui/regions/issue-78262.polonius.stderr
@@ -2,8 +2,11 @@ error[E0521]: borrowed data escapes outside of closure
   --> $DIR/issue-78262.rs:14:26
    |
 LL |     let f = |x: &dyn TT| x.func();
-   |              -           ^^^^^^^^ `x` escapes the closure body here
-   |              |
+   |              -  -        ^^^^^^^^
+   |              |  |        |
+   |              |  |        `x` escapes the closure body here
+   |              |  |        argument requires that `'1` must outlive `'static`
+   |              |  let's call the lifetime of this reference `'1`
    |              `x` is a reference that is only valid in the closure body
 
 error: aborting due to previous error
diff --git a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr
index 7221759dbd450..e220cbf555956 100644
--- a/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr
+++ b/src/test/ui/regions/region-invariant-static-error-reporting.nll.stderr
@@ -2,10 +2,15 @@ error[E0521]: borrowed data escapes outside of function
   --> $DIR/region-invariant-static-error-reporting.rs:15:9
    |
 LL | fn unify<'a>(x: Option<Invariant<'a>>, f: fn(Invariant<'a>)) {
-   |              - `x` is a reference that is only valid in the function body
+   |          --  - `x` is a reference that is only valid in the function body
+   |          |
+   |          lifetime `'a` defined here
 LL |     let bad = if x.is_some() {
 LL |         x.unwrap()
-   |         ^^^^^^^^^^ `x` escapes the function body here
+   |         ^^^^^^^^^^
+   |         |
+   |         `x` escapes the function body here
+   |         argument requires that `'a` must outlive `'static`
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
index ed7b17c207c30..83d6e13dc0a68 100644
--- a/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
+++ b/src/test/ui/regions/regions-bounded-method-type-parameters-trait-bound.nll.stderr
@@ -2,12 +2,17 @@ error[E0521]: borrowed data escapes outside of function
   --> $DIR/regions-bounded-method-type-parameters-trait-bound.rs:20:5
    |
 LL | fn caller2<'a,'b,F:Foo<'a>>(a: Inv<'a>, b: Inv<'b>, f: F) {
-   |                             -           - `b` is a reference that is only valid in the function body
-   |                             |
-   |                             `a` declared here, outside of the function body
+   |            -- --            -           - `b` is a reference that is only valid in the function body
+   |            |  |             |
+   |            |  |             `a` declared here, outside of the function body
+   |            |  lifetime `'b` defined here
+   |            lifetime `'a` defined here
 LL |     // Here the value provided for 'y is 'b, and hence 'b:'a does not hold.
 LL |     f.method(b);
-   |     ^^^^^^^^^^^ `b` escapes the function body here
+   |     ^^^^^^^^^^^
+   |     |
+   |     `b` escapes the function body here
+   |     argument requires that `'b` must outlive `'a`
    |
    = help: consider adding the following bound: `'b: 'a`
 
diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr
index 32a2de1e84d8f..a1ef32c5445b5 100644
--- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr
+++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.nll.stderr
@@ -2,33 +2,53 @@ error[E0521]: borrowed data escapes outside of function
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:20:9
    |
 LL |     fn use_it<'a, T>(val: &'a dyn ObjectTrait<T>) -> impl OtherTrait<'a> + 'a {
-   |                      --- `val` is a reference that is only valid in the function body
+   |               --     --- `val` is a reference that is only valid in the function body
+   |               |
+   |               lifetime `'a` defined here
 LL |         val.use_self::<T>()
-   |         ^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here
+   |         ^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         `val` escapes the function body here
+   |         argument requires that `'a` must outlive `'static`
 
 error[E0521]: borrowed data escapes outside of function
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:69:9
    |
 LL |     fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
-   |                   --- `val` is a reference that is only valid in the function body
+   |               --  --- `val` is a reference that is only valid in the function body
+   |               |
+   |               lifetime `'a` defined here
 LL |         val.use_self()
-   |         ^^^^^^^^^^^^^^ `val` escapes the function body here
+   |         ^^^^^^^^^^^^^^
+   |         |
+   |         `val` escapes the function body here
+   |         argument requires that `'a` must outlive `'static`
 
 error[E0521]: borrowed data escapes outside of function
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:88:9
    |
 LL |     fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> {
-   |                   --- `val` is a reference that is only valid in the function body
+   |               --  --- `val` is a reference that is only valid in the function body
+   |               |
+   |               lifetime `'a` defined here
 LL |         val.use_self()
-   |         ^^^^^^^^^^^^^^ `val` escapes the function body here
+   |         ^^^^^^^^^^^^^^
+   |         |
+   |         `val` escapes the function body here
+   |         argument requires that `'a` must outlive `'static`
 
 error[E0521]: borrowed data escapes outside of function
   --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9
    |
 LL |     fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a {
-   |                   --- `val` is a reference that is only valid in the function body
+   |               --  --- `val` is a reference that is only valid in the function body
+   |               |
+   |               lifetime `'a` defined here
 LL |         MyTrait::use_self(val)
-   |         ^^^^^^^^^^^^^^^^^^^^^^ `val` escapes the function body here
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |         |
+   |         `val` escapes the function body here
+   |         argument requires that `'a` must outlive `'static`
 
 error: aborting due to 4 previous errors
 
diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs
index 0386d8be167ee..39498c99e64d6 100644
--- a/src/tools/error_index_generator/main.rs
+++ b/src/tools/error_index_generator/main.rs
@@ -14,7 +14,7 @@ use std::path::PathBuf;
 
 use rustc_span::edition::DEFAULT_EDITION;
 
-use rustdoc::html::markdown::{ErrorCodes, IdMap, Markdown, Playground};
+use rustdoc::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
 
 pub struct ErrorMetadata {
     pub description: Option<String>,
@@ -119,14 +119,15 @@ impl Formatter for HTMLFormatter {
                 write!(
                     output,
                     "{}",
-                    Markdown(
-                        desc,
-                        &[],
-                        &mut id_map,
-                        ErrorCodes::Yes,
-                        DEFAULT_EDITION,
-                        &Some(playground)
-                    )
+                    Markdown {
+                        content: desc,
+                        links: &[],
+                        ids: &mut id_map,
+                        error_codes: ErrorCodes::Yes,
+                        edition: DEFAULT_EDITION,
+                        playground: &Some(playground),
+                        heading_offset: HeadingOffset::H1,
+                    }
                     .into_string()
                 )?
             }