diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index aca3fbbca13..24da75114a6 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -1035,14 +1035,14 @@ pub fn find_transparency(
 pub fn allow_internal_unstable<'a>(
     sess: &'a Session,
     attrs: &'a [Attribute],
-) -> Option<impl Iterator<Item = Symbol> + 'a> {
+) -> impl Iterator<Item = Symbol> + 'a {
     allow_unstable(sess, attrs, sym::allow_internal_unstable)
 }
 
 pub fn rustc_allow_const_fn_unstable<'a>(
     sess: &'a Session,
     attrs: &'a [Attribute],
-) -> Option<impl Iterator<Item = Symbol> + 'a> {
+) -> impl Iterator<Item = Symbol> + 'a {
     allow_unstable(sess, attrs, sym::rustc_allow_const_fn_unstable)
 }
 
@@ -1050,7 +1050,7 @@ fn allow_unstable<'a>(
     sess: &'a Session,
     attrs: &'a [Attribute],
     symbol: Symbol,
-) -> Option<impl Iterator<Item = Symbol> + 'a> {
+) -> impl Iterator<Item = Symbol> + 'a {
     let attrs = sess.filter_by_name(attrs, symbol);
     let list = attrs
         .filter_map(move |attr| {
@@ -1064,7 +1064,7 @@ fn allow_unstable<'a>(
         })
         .flatten();
 
-    Some(list.into_iter().filter_map(move |it| {
+    list.into_iter().filter_map(move |it| {
         let name = it.ident().map(|ident| ident.name);
         if name.is_none() {
             sess.diagnostic().span_err(
@@ -1073,5 +1073,5 @@ fn allow_unstable<'a>(
             );
         }
         name
-    }))
+    })
 }
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index b0aed812460..f5ae406faec 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -735,7 +735,7 @@ fn execute_work_item<B: ExtraBackendMethods>(
     match work_item {
         WorkItem::Optimize(module) => execute_optimize_work_item(cgcx, module, module_config),
         WorkItem::CopyPostLtoArtifacts(module) => {
-            execute_copy_from_cache_work_item(cgcx, module, module_config)
+            Ok(execute_copy_from_cache_work_item(cgcx, module, module_config))
         }
         WorkItem::LTO(module) => execute_lto_work_item(cgcx, module, module_config),
     }
@@ -844,7 +844,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
     cgcx: &CodegenContext<B>,
     module: CachedModuleCodegen,
     module_config: &ModuleConfig,
-) -> Result<WorkItemResult<B>, FatalError> {
+) -> WorkItemResult<B> {
     let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
     let mut object = None;
     if let Some(saved_file) = module.source.saved_file {
@@ -870,13 +870,13 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
 
     assert_eq!(object.is_some(), module_config.emit_obj != EmitObj::None);
 
-    Ok(WorkItemResult::Compiled(CompiledModule {
+    WorkItemResult::Compiled(CompiledModule {
         name: module.name,
         kind: ModuleKind::Regular,
         object,
         dwarf_object: None,
         bytecode: None,
-    }))
+    })
 }
 
 fn execute_lto_work_item<B: ExtraBackendMethods>(
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index e3dc793a7fa..ca304c05cdc 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -756,8 +756,8 @@ impl SyntaxExtension {
         name: Symbol,
         attrs: &[ast::Attribute],
     ) -> SyntaxExtension {
-        let allow_internal_unstable = attr::allow_internal_unstable(sess, &attrs)
-            .map(|features| features.collect::<Vec<Symbol>>().into());
+        let allow_internal_unstable =
+            Some(attr::allow_internal_unstable(sess, &attrs).collect::<Vec<Symbol>>().into());
 
         let mut local_inner_macros = false;
         if let Some(macro_export) = sess.find_by_name(attrs, sym::macro_export) {
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 5ebe38b2d7e..449b3a82dcb 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -266,7 +266,7 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> {
         let range = self.check_bounds(ptr.offset, size);
 
         self.mark_init(ptr, size, true);
-        self.clear_relocations(cx, ptr, size)?;
+        self.clear_relocations(cx, ptr, size);
 
         AllocationExtra::memory_written(self, ptr, size)?;
 
@@ -484,18 +484,13 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
     /// uninitialized. This is a somewhat odd "spooky action at a distance",
     /// but it allows strictly more code to run than if we would just error
     /// immediately in that case.
-    fn clear_relocations(
-        &mut self,
-        cx: &impl HasDataLayout,
-        ptr: Pointer<Tag>,
-        size: Size,
-    ) -> InterpResult<'tcx> {
+    fn clear_relocations(&mut self, cx: &impl HasDataLayout, ptr: Pointer<Tag>, size: Size) {
         // Find the start and end of the given range and its outermost relocations.
         let (first, last) = {
             // Find all relocations overlapping the given range.
             let relocations = self.get_relocations(cx, ptr, size);
             if relocations.is_empty() {
-                return Ok(());
+                return;
             }
 
             (
@@ -517,8 +512,6 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
 
         // Forget all the relocations.
         self.relocations.remove_range(first..last);
-
-        Ok(())
     }
 
     /// Errors if there are relocations overlapping with the edges of the
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 0b592ca4710..12dcb95187c 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -130,6 +130,7 @@ impl IntegerExt for Integer {
 
         if repr.c() {
             match &tcx.sess.target.arch[..] {
+                "hexagon" => min_from_extern = Some(I8),
                 // WARNING: the ARM EABI has two variants; the one corresponding
                 // to `at_least == I32` appears to be used on Linux and NetBSD,
                 // but some systems may use the variant corresponding to no
diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs
index c4039f2f15e..d36b3a7d9b5 100644
--- a/compiler/rustc_mir/src/interpret/intrinsics.rs
+++ b/compiler/rustc_mir/src/interpret/intrinsics.rs
@@ -23,11 +23,7 @@ use super::{
 mod caller_location;
 mod type_name;
 
-fn numeric_intrinsic<'tcx, Tag>(
-    name: Symbol,
-    bits: u128,
-    kind: Primitive,
-) -> InterpResult<'tcx, Scalar<Tag>> {
+fn numeric_intrinsic<Tag>(name: Symbol, bits: u128, kind: Primitive) -> Scalar<Tag> {
     let size = match kind {
         Primitive::Int(integer, _) => integer.size(),
         _ => bug!("invalid `{}` argument: {:?}", name, bits),
@@ -41,7 +37,7 @@ fn numeric_intrinsic<'tcx, Tag>(
         sym::bitreverse => (bits << extra).reverse_bits(),
         _ => bug!("not a numeric intrinsic: {}", name),
     };
-    Ok(Scalar::from_uint(bits_out, size))
+    Scalar::from_uint(bits_out, size)
 }
 
 /// The logic for all nullary intrinsics is implemented here. These intrinsics don't get evaluated
@@ -208,7 +204,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 if nonzero && bits == 0 {
                     throw_ub_format!("`{}_nonzero` called on 0", intrinsic_name);
                 }
-                let out_val = numeric_intrinsic(intrinsic_name, bits, kind)?;
+                let out_val = numeric_intrinsic(intrinsic_name, bits, kind);
                 self.write_scalar(out_val, dest)?;
             }
             sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
diff --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs
index ba7bea4ac54..19aee033a69 100644
--- a/compiler/rustc_mir/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs
@@ -85,8 +85,7 @@ pub fn rustc_allow_const_fn_unstable(
     feature_gate: Symbol,
 ) -> bool {
     let attrs = tcx.get_attrs(def_id);
-    attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs)
-        .map_or(false, |mut features| features.any(|name| name == feature_gate))
+    attr::rustc_allow_const_fn_unstable(&tcx.sess, attrs).any(|name| name == feature_gate)
 }
 
 // Returns `true` if the given `const fn` is "const-stable".
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index fa05df6805f..28bfaea4555 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -426,7 +426,7 @@ impl<'a> Parser<'a> {
         let span = self.mk_expr_sp(&lhs, lhs.span, rhs_span);
         let limits =
             if op == AssocOp::DotDot { RangeLimits::HalfOpen } else { RangeLimits::Closed };
-        Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits)?, AttrVec::new()))
+        Ok(self.mk_expr(span, self.mk_range(Some(lhs), rhs, limits), AttrVec::new()))
     }
 
     fn is_at_start_of_range_notation_rhs(&self) -> bool {
@@ -474,7 +474,7 @@ impl<'a> Parser<'a> {
             } else {
                 (lo, None)
             };
-            Ok(this.mk_expr(span, this.mk_range(None, opt_end, limits)?, attrs.into()))
+            Ok(this.mk_expr(span, this.mk_range(None, opt_end, limits), attrs.into()))
         })
     }
 
@@ -1041,7 +1041,7 @@ impl<'a> Parser<'a> {
     /// Assuming we have just parsed `.`, continue parsing into an expression.
     fn parse_dot_suffix(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
         if self.token.uninterpolated_span().rust_2018() && self.eat_keyword(kw::Await) {
-            return self.mk_await_expr(self_arg, lo);
+            return Ok(self.mk_await_expr(self_arg, lo));
         }
 
         let fn_span_lo = self.token.span;
@@ -2396,12 +2396,12 @@ impl<'a> Parser<'a> {
         start: Option<P<Expr>>,
         end: Option<P<Expr>>,
         limits: RangeLimits,
-    ) -> PResult<'a, ExprKind> {
+    ) -> ExprKind {
         if end.is_none() && limits == RangeLimits::Closed {
             self.error_inclusive_range_with_no_end(self.prev_token.span);
-            Ok(ExprKind::Err)
+            ExprKind::Err
         } else {
-            Ok(ExprKind::Range(start, end, limits))
+            ExprKind::Range(start, end, limits)
         }
     }
 
@@ -2421,11 +2421,11 @@ impl<'a> Parser<'a> {
         ExprKind::Call(f, args)
     }
 
-    fn mk_await_expr(&mut self, self_arg: P<Expr>, lo: Span) -> PResult<'a, P<Expr>> {
+    fn mk_await_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> {
         let span = lo.to(self.prev_token.span);
         let await_expr = self.mk_expr(span, ExprKind::Await(self_arg), AttrVec::new());
         self.recover_from_await_method_call();
-        Ok(await_expr)
+        await_expr
     }
 
     crate fn mk_expr(&self, span: Span, kind: ExprKind, attrs: AttrVec) -> P<Expr> {
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 0f907859a19..f3f5fc9af64 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1679,7 +1679,7 @@ impl<'a> Parser<'a> {
         let constness = self.parse_constness();
         let asyncness = self.parse_asyncness();
         let unsafety = self.parse_unsafety();
-        let ext = self.parse_extern()?;
+        let ext = self.parse_extern();
 
         if let Async::Yes { span, .. } = asyncness {
             self.ban_async_in_2015(span);
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index ace4134b1f6..1292286bc18 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -1202,12 +1202,8 @@ impl<'a> Parser<'a> {
     }
 
     /// Parses `extern string_literal?`.
-    fn parse_extern(&mut self) -> PResult<'a, Extern> {
-        Ok(if self.eat_keyword(kw::Extern) {
-            Extern::from_abi(self.parse_abi())
-        } else {
-            Extern::None
-        })
+    fn parse_extern(&mut self) -> Extern {
+        if self.eat_keyword(kw::Extern) { Extern::from_abi(self.parse_abi()) } else { Extern::None }
     }
 
     /// Parses a string literal as an ABI spec.
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 9328f7cd9ec..da713566c31 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -106,7 +106,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
             // However, we cannot allow stable `const fn`s to use unstable features without an explicit
             // opt-in via `rustc_allow_const_fn_unstable`.
             attr::rustc_allow_const_fn_unstable(&tcx.sess, &tcx.get_attrs(def_id))
-                .map_or(false, |mut features| features.any(|name| name == feature_gate))
+                .any(|name| name == feature_gate)
         };
 
         match required_gates {
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 32bf0ab7e85..2faf128c491 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1348,7 +1348,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         span: Span,
         remaining_fields: FxHashMap<Ident, (usize, &ty::FieldDef)>,
     ) {
-        let tcx = self.tcx;
         let len = remaining_fields.len();
 
         let mut displayable_field_names =
@@ -1356,25 +1355,29 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         displayable_field_names.sort();
 
-        let truncated_fields_error = if len <= 3 {
-            String::new()
-        } else {
-            format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" })
+        let mut truncated_fields_error = String::new();
+        let remaining_fields_names = match &displayable_field_names[..] {
+            [field1] => format!("`{}`", field1),
+            [field1, field2] => format!("`{}` and `{}`", field1, field2),
+            [field1, field2, field3] => format!("`{}`, `{}` and `{}`", field1, field2, field3),
+            _ => {
+                truncated_fields_error =
+                    format!(" and {} other field{}", len - 3, pluralize!(len - 3));
+                displayable_field_names
+                    .iter()
+                    .take(3)
+                    .map(|n| format!("`{}`", n))
+                    .collect::<Vec<_>>()
+                    .join(", ")
+            }
         };
 
-        let remaining_fields_names = displayable_field_names
-            .iter()
-            .take(3)
-            .map(|n| format!("`{}`", n))
-            .collect::<Vec<_>>()
-            .join(", ");
-
         struct_span_err!(
-            tcx.sess,
+            self.tcx.sess,
             span,
             E0063,
             "missing field{} {}{} in initializer of `{}`",
-            pluralize!(remaining_fields.len()),
+            pluralize!(len),
             remaining_fields_names,
             truncated_fields_error,
             adt_ty
diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs
index d13061d2203..d4fd7545d9b 100644
--- a/library/core/src/array/mod.rs
+++ b/library/core/src/array/mod.rs
@@ -11,8 +11,9 @@ use crate::cmp::Ordering;
 use crate::convert::{Infallible, TryFrom};
 use crate::fmt;
 use crate::hash::{self, Hash};
+use crate::iter::TrustedLen;
 use crate::marker::Unsize;
-use crate::mem::MaybeUninit;
+use crate::mem::{self, MaybeUninit};
 use crate::ops::{Index, IndexMut};
 use crate::slice::{Iter, IterMut};
 
@@ -426,41 +427,13 @@ impl<T, const N: usize> [T; N] {
     /// assert_eq!(y, [6, 9, 3, 3]);
     /// ```
     #[unstable(feature = "array_map", issue = "75243")]
-    pub fn map<F, U>(self, mut f: F) -> [U; N]
+    pub fn map<F, U>(self, f: F) -> [U; N]
     where
         F: FnMut(T) -> U,
     {
-        struct Guard<T, const N: usize> {
-            dst: *mut T,
-            initialized: usize,
-        }
-
-        impl<T, const N: usize> Drop for Guard<T, N> {
-            fn drop(&mut self) {
-                debug_assert!(self.initialized <= N);
-
-                let initialized_part =
-                    crate::ptr::slice_from_raw_parts_mut(self.dst, self.initialized);
-                // SAFETY: this raw slice will contain only initialized objects
-                // that's why, it is allowed to drop it.
-                unsafe {
-                    crate::ptr::drop_in_place(initialized_part);
-                }
-            }
-        }
-        let mut dst = MaybeUninit::uninit_array::<N>();
-        let mut guard: Guard<U, N> =
-            Guard { dst: MaybeUninit::slice_as_mut_ptr(&mut dst), initialized: 0 };
-        for (src, dst) in IntoIter::new(self).zip(&mut dst) {
-            dst.write(f(src));
-            guard.initialized += 1;
-        }
-        // FIXME: Convert to crate::mem::transmute once it works with generics.
-        // unsafe { crate::mem::transmute::<[MaybeUninit<U>; N], [U; N]>(dst) }
-        crate::mem::forget(guard);
-        // SAFETY: At this point we've properly initialized the whole array
-        // and we just need to cast it to the correct type.
-        unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) }
+        // SAFETY: we know for certain that this iterator will yield exactly `N`
+        // items.
+        unsafe { collect_into_array_unchecked(&mut IntoIter::new(self).map(f)) }
     }
 
     /// 'Zips up' two arrays into a single array of pairs.
@@ -481,15 +454,11 @@ impl<T, const N: usize> [T; N] {
     /// ```
     #[unstable(feature = "array_zip", issue = "80094")]
     pub fn zip<U>(self, rhs: [U; N]) -> [(T, U); N] {
-        let mut dst = MaybeUninit::uninit_array::<N>();
-        for (i, (lhs, rhs)) in IntoIter::new(self).zip(IntoIter::new(rhs)).enumerate() {
-            dst[i].write((lhs, rhs));
-        }
-        // FIXME: Convert to crate::mem::transmute once it works with generics.
-        // unsafe { crate::mem::transmute::<[MaybeUninit<U>; N], [U; N]>(dst) }
-        // SAFETY: At this point we've properly initialized the whole array
-        // and we just need to cast it to the correct type.
-        unsafe { crate::mem::transmute_copy::<_, [(T, U); N]>(&dst) }
+        let mut iter = IntoIter::new(self).zip(IntoIter::new(rhs));
+
+        // SAFETY: we know for certain that this iterator will yield exactly `N`
+        // items.
+        unsafe { collect_into_array_unchecked(&mut iter) }
     }
 
     /// Returns a slice containing the entire array. Equivalent to `&s[..]`.
@@ -535,16 +504,9 @@ impl<T, const N: usize> [T; N] {
     /// ```
     #[unstable(feature = "array_methods", issue = "76118")]
     pub fn each_ref(&self) -> [&T; N] {
-        // Unlike in `map`, we don't need a guard here, as dropping a reference
-        // is a noop.
-        let mut out = MaybeUninit::uninit_array::<N>();
-        for (src, dst) in self.iter().zip(&mut out) {
-            dst.write(src);
-        }
-
-        // SAFETY: All elements of `dst` are properly initialized and
-        // `MaybeUninit<T>` has the same layout as `T`, so this cast is valid.
-        unsafe { (&mut out as *mut _ as *mut [&T; N]).read() }
+        // SAFETY: we know for certain that this iterator will yield exactly `N`
+        // items.
+        unsafe { collect_into_array_unchecked(&mut self.iter()) }
     }
 
     /// Borrows each element mutably and returns an array of mutable references
@@ -564,15 +526,103 @@ impl<T, const N: usize> [T; N] {
     /// ```
     #[unstable(feature = "array_methods", issue = "76118")]
     pub fn each_mut(&mut self) -> [&mut T; N] {
-        // Unlike in `map`, we don't need a guard here, as dropping a reference
-        // is a noop.
-        let mut out = MaybeUninit::uninit_array::<N>();
-        for (src, dst) in self.iter_mut().zip(&mut out) {
-            dst.write(src);
-        }
-
-        // SAFETY: All elements of `dst` are properly initialized and
-        // `MaybeUninit<T>` has the same layout as `T`, so this cast is valid.
-        unsafe { (&mut out as *mut _ as *mut [&mut T; N]).read() }
+        // SAFETY: we know for certain that this iterator will yield exactly `N`
+        // items.
+        unsafe { collect_into_array_unchecked(&mut self.iter_mut()) }
     }
 }
+
+/// Pulls `N` items from `iter` and returns them as an array. If the iterator
+/// yields fewer than `N` items, this function exhibits undefined behavior.
+///
+/// See [`collect_into_array`] for more information.
+///
+///
+/// # Safety
+///
+/// It is up to the caller to guarantee that `iter` yields at least `N` items.
+/// Violating this condition causes undefined behavior.
+unsafe fn collect_into_array_unchecked<I, const N: usize>(iter: &mut I) -> [I::Item; N]
+where
+    // Note: `TrustedLen` here is somewhat of an experiment. This is just an
+    // internal function, so feel free to remove if this bound turns out to be a
+    // bad idea. In that case, remember to also remove the lower bound
+    // `debug_assert!` below!
+    I: Iterator + TrustedLen,
+{
+    debug_assert!(N <= iter.size_hint().1.unwrap_or(usize::MAX));
+    debug_assert!(N <= iter.size_hint().0);
+
+    match collect_into_array(iter) {
+        Some(array) => array,
+        // SAFETY: covered by the function contract.
+        None => unsafe { crate::hint::unreachable_unchecked() },
+    }
+}
+
+/// Pulls `N` items from `iter` and returns them as an array. If the iterator
+/// yields fewer than `N` items, `None` is returned and all already yielded
+/// items are dropped.
+///
+/// Since the iterator is passed as mutable reference and this function calls
+/// `next` at most `N` times, the iterator can still be used afterwards to
+/// retrieve the remaining items.
+///
+/// If `iter.next()` panicks, all items already yielded by the iterator are
+/// dropped.
+fn collect_into_array<I, const N: usize>(iter: &mut I) -> Option<[I::Item; N]>
+where
+    I: Iterator,
+{
+    if N == 0 {
+        // SAFETY: An empty array is always inhabited and has no validity invariants.
+        return unsafe { Some(mem::zeroed()) };
+    }
+
+    struct Guard<T, const N: usize> {
+        ptr: *mut T,
+        initialized: usize,
+    }
+
+    impl<T, const N: usize> Drop for Guard<T, N> {
+        fn drop(&mut self) {
+            debug_assert!(self.initialized <= N);
+
+            let initialized_part = crate::ptr::slice_from_raw_parts_mut(self.ptr, self.initialized);
+
+            // SAFETY: this raw slice will contain only initialized objects.
+            unsafe {
+                crate::ptr::drop_in_place(initialized_part);
+            }
+        }
+    }
+
+    let mut array = MaybeUninit::uninit_array::<N>();
+    let mut guard: Guard<_, N> =
+        Guard { ptr: MaybeUninit::slice_as_mut_ptr(&mut array), initialized: 0 };
+
+    while let Some(item) = iter.next() {
+        // SAFETY: `guard.initialized` starts at 0, is increased by one in the
+        // loop and the loop is aborted once it reaches N (which is
+        // `array.len()`).
+        unsafe {
+            array.get_unchecked_mut(guard.initialized).write(item);
+        }
+        guard.initialized += 1;
+
+        // Check if the whole array was initialized.
+        if guard.initialized == N {
+            mem::forget(guard);
+
+            // SAFETY: the condition above asserts that all elements are
+            // initialized.
+            let out = unsafe { MaybeUninit::array_assume_init(array) };
+            return Some(out);
+        }
+    }
+
+    // This is only reached if the iterator is exhausted before
+    // `guard.initialized` reaches `N`. Also note that `guard` is dropped here,
+    // dropping all already initialized elements.
+    None
+}
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index cb772458e50..cce1242d84f 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -1619,17 +1619,18 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
 
 /// The core primitive for interior mutability in Rust.
 ///
-/// `UnsafeCell<T>` is a type that wraps some `T` and indicates unsafe interior operations on the
-/// wrapped type. Types with an `UnsafeCell<T>` field are considered to have an 'unsafe interior'.
-/// The `UnsafeCell<T>` type is the only legal way to obtain aliasable data that is considered
-/// mutable. In general, transmuting a `&T` type into a `&mut T` is considered undefined behavior.
+/// If you have a reference `&T`, then normally in Rust the compiler performs optimizations based on
+/// the knowledge that `&T` points to immutable data. Mutating that data, for example through an
+/// alias or by transmuting an `&T` into an `&mut T`, is considered undefined behavior.
+/// `UnsafeCell<T>` opts-out of the immutability guarantee for `&T`: a shared reference
+/// `&UnsafeCell<T>` may point to data that is being mutated. This is called "interior mutability".
 ///
-/// If you have a reference `&SomeStruct`, then normally in Rust all fields of `SomeStruct` are
-/// immutable. The compiler makes optimizations based on the knowledge that `&T` is not mutably
-/// aliased or mutated, and that `&mut T` is unique. `UnsafeCell<T>` is the only core language
-/// feature to work around the restriction that `&T` may not be mutated. All other types that
-/// allow internal mutability, such as `Cell<T>` and `RefCell<T>`, use `UnsafeCell` to wrap their
-/// internal data. There is *no* legal way to obtain aliasing `&mut`, not even with `UnsafeCell<T>`.
+/// All other types that allow internal mutability, such as `Cell<T>` and `RefCell<T>`, internally
+/// use `UnsafeCell` to wrap their data.
+///
+/// Note that only the immutability guarantee for shared references is affected by `UnsafeCell`. The
+/// uniqueness guarantee for mutable references is unaffected. There is *no* legal way to obtain
+/// aliasing `&mut`, not even with `UnsafeCell<T>`.
 ///
 /// The `UnsafeCell` API itself is technically very simple: [`.get()`] gives you a raw pointer
 /// `*mut T` to its contents. It is up to _you_ as the abstraction designer to use that raw pointer
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 16733b7ccd3..5e46d2c17c9 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -263,6 +263,7 @@
 #![feature(exact_size_is_empty)]
 #![feature(exhaustive_patterns)]
 #![feature(extend_one)]
+#![feature(extended_key_value_attributes)]
 #![feature(external_doc)]
 #![feature(fn_traits)]
 #![feature(format_args_nl)]
diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs
index 16272aa0571..22c98d7ade9 100644
--- a/library/std/src/os/raw/mod.rs
+++ b/library/std/src/os/raw/mod.rs
@@ -11,7 +11,41 @@
 #[cfg(test)]
 mod tests;
 
-#[doc(include = "char.md")]
+use core::num::*;
+
+macro_rules! type_alias_no_nz {
+    {
+      $Docfile:tt, $Alias:ident = $Real:ty;
+      $( $Cfg:tt )*
+    } => {
+        #[doc(include = $Docfile)]
+        $( $Cfg )*
+        #[stable(feature = "raw_os", since = "1.1.0")]
+        pub type $Alias = $Real;
+    }
+}
+
+// To verify that the NonZero types in this file's macro invocations correspond
+//
+//  perl -n < library/std/src/os/raw/mod.rs -e 'next unless m/type_alias\!/; die "$_ ?" unless m/, (c_\w+) = (\w+), NonZero_(\w+) = NonZero(\w+)/; die "$_ ?" unless $3 eq $1 and $4 eq ucfirst $2'
+//
+// NB this does not check that the main c_* types are right.
+
+macro_rules! type_alias {
+    {
+      $Docfile:tt, $Alias:ident = $Real:ty, $NZAlias:ident = $NZReal:ty;
+      $( $Cfg:tt )*
+    } => {
+        type_alias_no_nz! { $Docfile, $Alias = $Real; $( $Cfg )* }
+
+        #[doc = concat!("Type alias for `NonZero` version of [`", stringify!($Alias), "`]")]
+        #[unstable(feature = "raw_os_nonzero", issue = "82363")]
+        $( $Cfg )*
+        pub type $NZAlias = $NZReal;
+    }
+}
+
+type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8;
 #[cfg(any(
     all(
         target_os = "linux",
@@ -52,10 +86,8 @@ mod tests;
         )
     ),
     all(target_os = "fuchsia", target_arch = "aarch64")
-))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_char = u8;
-#[doc(include = "char.md")]
+))]}
+type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8;
 #[cfg(not(any(
     all(
         target_os = "linux",
@@ -96,55 +128,25 @@ pub type c_char = u8;
         )
     ),
     all(target_os = "fuchsia", target_arch = "aarch64")
-)))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_char = i8;
-#[doc(include = "schar.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_schar = i8;
-#[doc(include = "uchar.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_uchar = u8;
-#[doc(include = "short.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_short = i16;
-#[doc(include = "ushort.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_ushort = u16;
-#[doc(include = "int.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_int = i32;
-#[doc(include = "uint.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_uint = u32;
-#[doc(include = "long.md")]
-#[cfg(any(target_pointer_width = "32", windows))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_long = i32;
-#[doc(include = "ulong.md")]
-#[cfg(any(target_pointer_width = "32", windows))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_ulong = u32;
-#[doc(include = "long.md")]
-#[cfg(all(target_pointer_width = "64", not(windows)))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_long = i64;
-#[doc(include = "ulong.md")]
-#[cfg(all(target_pointer_width = "64", not(windows)))]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_ulong = u64;
-#[doc(include = "longlong.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_longlong = i64;
-#[doc(include = "ulonglong.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_ulonglong = u64;
-#[doc(include = "float.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_float = f32;
-#[doc(include = "double.md")]
-#[stable(feature = "raw_os", since = "1.1.0")]
-pub type c_double = f64;
+)))]}
+type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; }
+type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; }
+type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; }
+type_alias! { "ushort.md", c_ushort = u16, NonZero_c_ushort = NonZeroU16; }
+type_alias! { "int.md", c_int = i32, NonZero_c_int = NonZeroI32; }
+type_alias! { "uint.md", c_uint = u32, NonZero_c_uint = NonZeroU32; }
+type_alias! { "long.md", c_long = i32, NonZero_c_long = NonZeroI32;
+#[cfg(any(target_pointer_width = "32", windows))] }
+type_alias! { "ulong.md", c_ulong = u32, NonZero_c_ulong = NonZeroU32;
+#[cfg(any(target_pointer_width = "32", windows))] }
+type_alias! { "long.md", c_long = i64, NonZero_c_long = NonZeroI64;
+#[cfg(all(target_pointer_width = "64", not(windows)))] }
+type_alias! { "ulong.md", c_ulong = u64, NonZero_c_ulong = NonZeroU64;
+#[cfg(all(target_pointer_width = "64", not(windows)))] }
+type_alias! { "longlong.md", c_longlong = i64, NonZero_c_longlong = NonZeroI64; }
+type_alias! { "ulonglong.md", c_ulonglong = u64, NonZero_c_ulonglong = NonZeroU64; }
+type_alias_no_nz! { "float.md", c_float = f32; }
+type_alias_no_nz! { "double.md", c_double = f64; }
 
 #[stable(feature = "raw_os", since = "1.1.0")]
 #[doc(no_inline)]
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 1cfa6090ef4..98e1299df2f 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1519,7 +1519,7 @@ fn normalize(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option<Ty<'tcx>> {
     let lifted = ty.lift_to_tcx(cx.tcx).unwrap();
     let normalized = cx.tcx.infer_ctxt().enter(|infcx| {
         infcx
-            .at(&ObligationCause::dummy(), cx.param_env.get())
+            .at(&ObligationCause::dummy(), cx.param_env)
             .normalize(lifted)
             .map(|resolved| infcx.resolve_vars_if_possible(resolved.value))
     });
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 1c2d2ad626c..dbf202a7321 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -26,10 +26,7 @@ use rustc_span::DUMMY_SP;
 
 use std::mem;
 use std::rc::Rc;
-use std::{
-    cell::{Cell, RefCell},
-    collections::hash_map::Entry,
-};
+use std::{cell::RefCell, collections::hash_map::Entry};
 
 use crate::clean;
 use crate::clean::inline::build_external_trait;
@@ -49,7 +46,7 @@ crate struct DocContext<'tcx> {
     /// Used for normalization.
     ///
     /// Most of this logic is copied from rustc_lint::late.
-    crate param_env: Cell<ParamEnv<'tcx>>,
+    crate param_env: ParamEnv<'tcx>,
     /// Later on moved into `cache`
     crate renderinfo: RefCell<RenderInfo>,
     /// Later on moved through `clean::Crate` into `cache`
@@ -67,7 +64,7 @@ crate struct DocContext<'tcx> {
     crate ct_substs: RefCell<FxHashMap<DefId, clean::Constant>>,
     /// Table synthetic type parameter for `impl Trait` in argument position -> bounds
     crate impl_trait_bounds: RefCell<FxHashMap<ImplTraitParam, Vec<clean::GenericBound>>>,
-    crate fake_def_ids: RefCell<FxHashMap<CrateNum, DefIndex>>,
+    crate fake_def_ids: FxHashMap<CrateNum, DefIndex>,
     /// Auto-trait or blanket impls processed so far, as `(self_ty, trait_def_id)`.
     // FIXME(eddyb) make this a `ty::TraitRef<'tcx>` set.
     crate generated_synthetics: RefCell<FxHashSet<(Ty<'tcx>, DefId)>>,
@@ -89,9 +86,9 @@ impl<'tcx> DocContext<'tcx> {
     }
 
     crate fn with_param_env<T, F: FnOnce(&mut Self) -> T>(&mut self, def_id: DefId, f: F) -> T {
-        let old_param_env = self.param_env.replace(self.tcx.param_env(def_id));
+        let old_param_env = mem::replace(&mut self.param_env, self.tcx.param_env(def_id));
         let ret = f(self);
-        self.param_env.set(old_param_env);
+        self.param_env = old_param_env;
         ret
     }
 
@@ -140,16 +137,14 @@ impl<'tcx> DocContext<'tcx> {
     /// [`RefCell`]: std::cell::RefCell
     /// [`Debug`]: std::fmt::Debug
     /// [`clean::Item`]: crate::clean::types::Item
-    crate fn next_def_id(&self, crate_num: CrateNum) -> DefId {
-        let mut fake_ids = self.fake_def_ids.borrow_mut();
-
-        let def_index = match fake_ids.entry(crate_num) {
+    crate fn next_def_id(&mut self, crate_num: CrateNum) -> DefId {
+        let def_index = match self.fake_def_ids.entry(crate_num) {
             Entry::Vacant(e) => {
                 let num_def_idx = {
                     let num_def_idx = if crate_num == LOCAL_CRATE {
                         self.tcx.hir().definitions().def_path_table().num_def_ids()
                     } else {
-                        self.enter_resolver(|r| r.cstore().num_def_ids(crate_num))
+                        self.resolver.borrow_mut().access(|r| r.cstore().num_def_ids(crate_num))
                     };
 
                     DefIndex::from_usize(num_def_idx)
@@ -511,7 +506,7 @@ crate fn run_global_ctxt(
     let mut ctxt = DocContext {
         tcx,
         resolver,
-        param_env: Cell::new(ParamEnv::empty()),
+        param_env: ParamEnv::empty(),
         external_traits: Default::default(),
         active_extern_traits: Default::default(),
         renderinfo: RefCell::new(renderinfo),
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index a81fd55f6f1..b7854bbf82b 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1124,6 +1124,7 @@ crate fn plain_text_summary(md: &str) -> String {
             Event::HardBreak | Event::SoftBreak => s.push(' '),
             Event::Start(Tag::CodeBlock(..)) => break,
             Event::End(Tag::Paragraph) => break,
+            Event::End(Tag::Heading(..)) => break,
             _ => (),
         }
     }
diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs
index 9da3072ec28..994fe8206e8 100644
--- a/src/librustdoc/html/markdown/tests.rs
+++ b/src/librustdoc/html/markdown/tests.rs
@@ -230,6 +230,7 @@ fn test_plain_text_summary() {
     t("code `let x = i32;` ...", "code `let x = i32;` ...");
     t("type `Type<'static>` ...", "type `Type<'static>` ...");
     t("# top header", "top header");
+    t("# top header\n\nfollowed by some text", "top header");
     t("## header", "header");
     t("first paragraph\n\nsecond paragraph", "first paragraph");
     t("```\nfn main() {}\n```", "");
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 7ca355ed11c..7f122bb8cb5 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1548,7 +1548,10 @@ impl Context<'_> {
         }
         title.push_str(" - Rust");
         let tyname = it.type_();
-        let desc = if it.is_crate() {
+        let desc = it.doc_value().as_ref().map(|doc| plain_text_summary(&doc));
+        let desc = if let Some(desc) = desc {
+            desc
+        } else if it.is_crate() {
             format!("API documentation for the Rust `{}` crate.", self.shared.layout.krate)
         } else {
             format!(
diff --git a/src/test/rustdoc/description.rs b/src/test/rustdoc/description.rs
new file mode 100644
index 00000000000..05ec4282208
--- /dev/null
+++ b/src/test/rustdoc/description.rs
@@ -0,0 +1,24 @@
+#![crate_name = "foo"]
+//! # Description test crate
+//!
+//! This is the contents of the test crate docstring.
+//! It should not show up in the description.
+
+// @has 'foo/index.html' '//meta[@name="description"]/@content' \
+//   'Description test crate'
+// @!has - '//meta[@name="description"]/@content' 'should not show up'
+
+// @has 'foo/foo_mod/index.html' '//meta[@name="description"]/@content' \
+//   'First paragraph description.'
+// @!has - '//meta[@name="description"]/@content' 'Second paragraph'
+/// First paragraph description.
+///
+/// Second paragraph should not show up.
+pub mod foo_mod {
+    pub struct __Thing {}
+}
+
+// @has 'foo/fn.foo_fn.html' '//meta[@name="description"]/@content' \
+//   'Only paragraph.'
+/// Only paragraph.
+pub fn foo_fn() {}
diff --git a/src/test/rustdoc/description_default.rs b/src/test/rustdoc/description_default.rs
new file mode 100644
index 00000000000..21d8e04d3f9
--- /dev/null
+++ b/src/test/rustdoc/description_default.rs
@@ -0,0 +1,14 @@
+#![crate_name = "foo"]
+
+// @has 'foo/index.html' '//meta[@name="description"]/@content' \
+//   'API documentation for the Rust `foo` crate.'
+
+// @has 'foo/foo_mod/index.html' '//meta[@name="description"]/@content' \
+//   'API documentation for the Rust `foo_mod` mod in crate `foo`.'
+pub mod foo_mod {
+    pub struct __Thing {}
+}
+
+// @has 'foo/fn.foo_fn.html' '//meta[@name="description"]/@content' \
+//   'API documentation for the Rust `foo_fn` fn in crate `foo`.'
+pub fn foo_fn() {}
diff --git a/src/test/ui/error-codes/E0063.rs b/src/test/ui/error-codes/E0063.rs
index 37fc0a2987d..58527cc0c5d 100644
--- a/src/test/ui/error-codes/E0063.rs
+++ b/src/test/ui/error-codes/E0063.rs
@@ -32,7 +32,7 @@ fn main() {
     let w = SingleFoo { };
     //~^ ERROR missing field `x` in initializer of `SingleFoo`
     let x = PluralFoo {x: 1};
-    //~^ ERROR missing fields `y`, `z` in initializer of `PluralFoo`
+    //~^ ERROR missing fields `y` and `z` in initializer of `PluralFoo`
     let y = TruncatedFoo{x:1};
     //~^ missing fields `a`, `b`, `y` and 1 other field in initializer of `TruncatedFoo`
     let z = TruncatedPluralFoo{x:1};
diff --git a/src/test/ui/error-codes/E0063.stderr b/src/test/ui/error-codes/E0063.stderr
index 5d366e0c1c4..5dc4927071b 100644
--- a/src/test/ui/error-codes/E0063.stderr
+++ b/src/test/ui/error-codes/E0063.stderr
@@ -4,11 +4,11 @@ error[E0063]: missing field `x` in initializer of `SingleFoo`
 LL |     let w = SingleFoo { };
    |             ^^^^^^^^^ missing `x`
 
-error[E0063]: missing fields `y`, `z` in initializer of `PluralFoo`
+error[E0063]: missing fields `y` and `z` in initializer of `PluralFoo`
   --> $DIR/E0063.rs:34:13
    |
 LL |     let x = PluralFoo {x: 1};
-   |             ^^^^^^^^^ missing `y`, `z`
+   |             ^^^^^^^^^ missing `y` and `z`
 
 error[E0063]: missing fields `a`, `b`, `y` and 1 other field in initializer of `TruncatedFoo`
   --> $DIR/E0063.rs:36:13
diff --git a/src/test/ui/issues/issue-79593.rs b/src/test/ui/issues/issue-79593.rs
index fb54b36940d..b94278bfdd2 100644
--- a/src/test/ui/issues/issue-79593.rs
+++ b/src/test/ui/issues/issue-79593.rs
@@ -23,7 +23,7 @@ fn wrong() {
     foo::Enum::Variant { x: () };
     //~^ ERROR missing field `y` in initializer of `Enum`
     foo::Enum::Variant { };
-    //~^ ERROR missing fields `x`, `y` in initializer of `Enum`
+    //~^ ERROR missing fields `x` and `y` in initializer of `Enum`
 }
 
 fn main() {}
diff --git a/src/test/ui/issues/issue-79593.stderr b/src/test/ui/issues/issue-79593.stderr
index 33dbd85032e..b8c7d4f23a2 100644
--- a/src/test/ui/issues/issue-79593.stderr
+++ b/src/test/ui/issues/issue-79593.stderr
@@ -22,11 +22,11 @@ error[E0063]: missing field `y` in initializer of `Enum`
 LL |     foo::Enum::Variant { x: () };
    |     ^^^^^^^^^^^^^^^^^^ missing `y`
 
-error[E0063]: missing fields `x`, `y` in initializer of `Enum`
+error[E0063]: missing fields `x` and `y` in initializer of `Enum`
   --> $DIR/issue-79593.rs:25:5
    |
 LL |     foo::Enum::Variant { };
-   |     ^^^^^^^^^^^^^^^^^^ missing `x`, `y`
+   |     ^^^^^^^^^^^^^^^^^^ missing `x` and `y`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/layout/hexagon-enum.rs b/src/test/ui/layout/hexagon-enum.rs
new file mode 100644
index 00000000000..4bcfa58f7cf
--- /dev/null
+++ b/src/test/ui/layout/hexagon-enum.rs
@@ -0,0 +1,33 @@
+// compile-flags: --target hexagon-unknown-linux-musl
+//
+// Verify that the hexagon targets implement the repr(C) for enums correctly.
+//
+// See #82100
+#![feature(never_type, rustc_attrs, type_alias_impl_trait, no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_core]
+
+#[lang="sized"]
+trait Sized {}
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum A { Apple } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum B { Banana = 255, } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum C { Chaenomeles = 256, } //~ ERROR: layout_of
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum P { Peach = 0x1000_0000isize, } //~ ERROR: layout_of
+
+const TANGERINE: usize = 0x8100_0000; // hack to get negative numbers without negation operator!
+
+#[rustc_layout(debug)]
+#[repr(C)]
+enum T { Tangerine = TANGERINE as isize } //~ ERROR: layout_of
diff --git a/src/test/ui/layout/hexagon-enum.stderr b/src/test/ui/layout/hexagon-enum.stderr
new file mode 100644
index 00000000000..390eff6e5b9
--- /dev/null
+++ b/src/test/ui/layout/hexagon-enum.stderr
@@ -0,0 +1,442 @@
+error: layout_of(A) = Layout {
+    fields: Arbitrary {
+        offsets: [
+            Size {
+                raw: 0,
+            },
+        ],
+        memory_index: [
+            0,
+        ],
+    },
+    variants: Multiple {
+        tag: Scalar {
+            value: Int(
+                I8,
+                false,
+            ),
+            valid_range: 0..=0,
+        },
+        tag_encoding: Direct,
+        tag_field: 0,
+        variants: [
+            Layout {
+                fields: Arbitrary {
+                    offsets: [],
+                    memory_index: [],
+                },
+                variants: Single {
+                    index: 0,
+                },
+                abi: Aggregate {
+                    sized: true,
+                },
+                largest_niche: None,
+                align: AbiAndPrefAlign {
+                    abi: Align {
+                        pow2: 0,
+                    },
+                    pref: Align {
+                        pow2: 0,
+                    },
+                },
+                size: Size {
+                    raw: 1,
+                },
+            },
+        ],
+    },
+    abi: Scalar(
+        Scalar {
+            value: Int(
+                I8,
+                false,
+            ),
+            valid_range: 0..=0,
+        },
+    ),
+    largest_niche: Some(
+        Niche {
+            offset: Size {
+                raw: 0,
+            },
+            scalar: Scalar {
+                value: Int(
+                    I8,
+                    false,
+                ),
+                valid_range: 0..=0,
+            },
+        },
+    ),
+    align: AbiAndPrefAlign {
+        abi: Align {
+            pow2: 0,
+        },
+        pref: Align {
+            pow2: 0,
+        },
+    },
+    size: Size {
+        raw: 1,
+    },
+}
+  --> $DIR/hexagon-enum.rs:15:1
+   |
+LL | enum A { Apple }
+   | ^^^^^^^^^^^^^^^^
+
+error: layout_of(B) = Layout {
+    fields: Arbitrary {
+        offsets: [
+            Size {
+                raw: 0,
+            },
+        ],
+        memory_index: [
+            0,
+        ],
+    },
+    variants: Multiple {
+        tag: Scalar {
+            value: Int(
+                I8,
+                false,
+            ),
+            valid_range: 255..=255,
+        },
+        tag_encoding: Direct,
+        tag_field: 0,
+        variants: [
+            Layout {
+                fields: Arbitrary {
+                    offsets: [],
+                    memory_index: [],
+                },
+                variants: Single {
+                    index: 0,
+                },
+                abi: Aggregate {
+                    sized: true,
+                },
+                largest_niche: None,
+                align: AbiAndPrefAlign {
+                    abi: Align {
+                        pow2: 0,
+                    },
+                    pref: Align {
+                        pow2: 0,
+                    },
+                },
+                size: Size {
+                    raw: 1,
+                },
+            },
+        ],
+    },
+    abi: Scalar(
+        Scalar {
+            value: Int(
+                I8,
+                false,
+            ),
+            valid_range: 255..=255,
+        },
+    ),
+    largest_niche: Some(
+        Niche {
+            offset: Size {
+                raw: 0,
+            },
+            scalar: Scalar {
+                value: Int(
+                    I8,
+                    false,
+                ),
+                valid_range: 255..=255,
+            },
+        },
+    ),
+    align: AbiAndPrefAlign {
+        abi: Align {
+            pow2: 0,
+        },
+        pref: Align {
+            pow2: 0,
+        },
+    },
+    size: Size {
+        raw: 1,
+    },
+}
+  --> $DIR/hexagon-enum.rs:19:1
+   |
+LL | enum B { Banana = 255, }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout_of(C) = Layout {
+    fields: Arbitrary {
+        offsets: [
+            Size {
+                raw: 0,
+            },
+        ],
+        memory_index: [
+            0,
+        ],
+    },
+    variants: Multiple {
+        tag: Scalar {
+            value: Int(
+                I16,
+                false,
+            ),
+            valid_range: 256..=256,
+        },
+        tag_encoding: Direct,
+        tag_field: 0,
+        variants: [
+            Layout {
+                fields: Arbitrary {
+                    offsets: [],
+                    memory_index: [],
+                },
+                variants: Single {
+                    index: 0,
+                },
+                abi: Aggregate {
+                    sized: true,
+                },
+                largest_niche: None,
+                align: AbiAndPrefAlign {
+                    abi: Align {
+                        pow2: 1,
+                    },
+                    pref: Align {
+                        pow2: 1,
+                    },
+                },
+                size: Size {
+                    raw: 2,
+                },
+            },
+        ],
+    },
+    abi: Scalar(
+        Scalar {
+            value: Int(
+                I16,
+                false,
+            ),
+            valid_range: 256..=256,
+        },
+    ),
+    largest_niche: Some(
+        Niche {
+            offset: Size {
+                raw: 0,
+            },
+            scalar: Scalar {
+                value: Int(
+                    I16,
+                    false,
+                ),
+                valid_range: 256..=256,
+            },
+        },
+    ),
+    align: AbiAndPrefAlign {
+        abi: Align {
+            pow2: 1,
+        },
+        pref: Align {
+            pow2: 1,
+        },
+    },
+    size: Size {
+        raw: 2,
+    },
+}
+  --> $DIR/hexagon-enum.rs:23:1
+   |
+LL | enum C { Chaenomeles = 256, }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout_of(P) = Layout {
+    fields: Arbitrary {
+        offsets: [
+            Size {
+                raw: 0,
+            },
+        ],
+        memory_index: [
+            0,
+        ],
+    },
+    variants: Multiple {
+        tag: Scalar {
+            value: Int(
+                I32,
+                false,
+            ),
+            valid_range: 268435456..=268435456,
+        },
+        tag_encoding: Direct,
+        tag_field: 0,
+        variants: [
+            Layout {
+                fields: Arbitrary {
+                    offsets: [],
+                    memory_index: [],
+                },
+                variants: Single {
+                    index: 0,
+                },
+                abi: Aggregate {
+                    sized: true,
+                },
+                largest_niche: None,
+                align: AbiAndPrefAlign {
+                    abi: Align {
+                        pow2: 2,
+                    },
+                    pref: Align {
+                        pow2: 2,
+                    },
+                },
+                size: Size {
+                    raw: 4,
+                },
+            },
+        ],
+    },
+    abi: Scalar(
+        Scalar {
+            value: Int(
+                I32,
+                false,
+            ),
+            valid_range: 268435456..=268435456,
+        },
+    ),
+    largest_niche: Some(
+        Niche {
+            offset: Size {
+                raw: 0,
+            },
+            scalar: Scalar {
+                value: Int(
+                    I32,
+                    false,
+                ),
+                valid_range: 268435456..=268435456,
+            },
+        },
+    ),
+    align: AbiAndPrefAlign {
+        abi: Align {
+            pow2: 2,
+        },
+        pref: Align {
+            pow2: 2,
+        },
+    },
+    size: Size {
+        raw: 4,
+    },
+}
+  --> $DIR/hexagon-enum.rs:27:1
+   |
+LL | enum P { Peach = 0x1000_0000isize, }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: layout_of(T) = Layout {
+    fields: Arbitrary {
+        offsets: [
+            Size {
+                raw: 0,
+            },
+        ],
+        memory_index: [
+            0,
+        ],
+    },
+    variants: Multiple {
+        tag: Scalar {
+            value: Int(
+                I32,
+                true,
+            ),
+            valid_range: 2164260864..=2164260864,
+        },
+        tag_encoding: Direct,
+        tag_field: 0,
+        variants: [
+            Layout {
+                fields: Arbitrary {
+                    offsets: [],
+                    memory_index: [],
+                },
+                variants: Single {
+                    index: 0,
+                },
+                abi: Aggregate {
+                    sized: true,
+                },
+                largest_niche: None,
+                align: AbiAndPrefAlign {
+                    abi: Align {
+                        pow2: 2,
+                    },
+                    pref: Align {
+                        pow2: 2,
+                    },
+                },
+                size: Size {
+                    raw: 4,
+                },
+            },
+        ],
+    },
+    abi: Scalar(
+        Scalar {
+            value: Int(
+                I32,
+                true,
+            ),
+            valid_range: 2164260864..=2164260864,
+        },
+    ),
+    largest_niche: Some(
+        Niche {
+            offset: Size {
+                raw: 0,
+            },
+            scalar: Scalar {
+                value: Int(
+                    I32,
+                    true,
+                ),
+                valid_range: 2164260864..=2164260864,
+            },
+        },
+    ),
+    align: AbiAndPrefAlign {
+        abi: Align {
+            pow2: 2,
+        },
+        pref: Align {
+            pow2: 2,
+        },
+    },
+    size: Size {
+        raw: 4,
+    },
+}
+  --> $DIR/hexagon-enum.rs:33:1
+   |
+LL | enum T { Tangerine = TANGERINE as isize }
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 5 previous errors
+
diff --git a/src/test/ui/parser/issue-52496.rs b/src/test/ui/parser/issue-52496.rs
index 4e945365373..05461f8b8c4 100644
--- a/src/test/ui/parser/issue-52496.rs
+++ b/src/test/ui/parser/issue-52496.rs
@@ -7,6 +7,6 @@ fn main() {
     let bar = 1.5f32;
     let _ = Foo { bar.into(), bat: -1, . };
     //~^ ERROR expected one of
-    //~| ERROR missing fields `bar`, `baz` in initializer of `Foo`
+    //~| ERROR missing fields `bar` and `baz` in initializer of `Foo`
     //~| ERROR expected identifier, found `.`
 }
diff --git a/src/test/ui/parser/issue-52496.stderr b/src/test/ui/parser/issue-52496.stderr
index 10fcc46f344..9dbf26ef4b6 100644
--- a/src/test/ui/parser/issue-52496.stderr
+++ b/src/test/ui/parser/issue-52496.stderr
@@ -26,11 +26,11 @@ error[E0063]: missing field `bat` in initializer of `Foo`
 LL |     let _ = Foo { bar: .5, baz: 42 };
    |             ^^^ missing `bat`
 
-error[E0063]: missing fields `bar`, `baz` in initializer of `Foo`
+error[E0063]: missing fields `bar` and `baz` in initializer of `Foo`
   --> $DIR/issue-52496.rs:8:13
    |
 LL |     let _ = Foo { bar.into(), bat: -1, . };
-   |             ^^^ missing `bar`, `baz`
+   |             ^^^ missing `bar` and `baz`
 
 error: aborting due to 5 previous errors
 
diff --git a/src/test/ui/parser/struct-field-numeric-shorthand.rs b/src/test/ui/parser/struct-field-numeric-shorthand.rs
index 58c40b3d96a..645abd9c719 100644
--- a/src/test/ui/parser/struct-field-numeric-shorthand.rs
+++ b/src/test/ui/parser/struct-field-numeric-shorthand.rs
@@ -5,5 +5,5 @@ fn main() {
     //~^ ERROR expected identifier, found `0`
     //~| ERROR expected identifier, found `1`
     //~| ERROR expected identifier, found `2`
-    //~| ERROR missing fields `0`, `1`, `2` in initializer of `Rgb`
+    //~| ERROR missing fields `0`, `1` and `2` in initializer of `Rgb`
 }
diff --git a/src/test/ui/parser/struct-field-numeric-shorthand.stderr b/src/test/ui/parser/struct-field-numeric-shorthand.stderr
index cfb1f820147..bfb8a931b64 100644
--- a/src/test/ui/parser/struct-field-numeric-shorthand.stderr
+++ b/src/test/ui/parser/struct-field-numeric-shorthand.stderr
@@ -22,11 +22,11 @@ LL |     let _ = Rgb { 0, 1, 2 };
    |             |
    |             while parsing this struct
 
-error[E0063]: missing fields `0`, `1`, `2` in initializer of `Rgb`
+error[E0063]: missing fields `0`, `1` and `2` in initializer of `Rgb`
   --> $DIR/struct-field-numeric-shorthand.rs:4:13
    |
 LL |     let _ = Rgb { 0, 1, 2 };
-   |             ^^^ missing `0`, `1`, `2`
+   |             ^^^ missing `0`, `1` and `2`
 
 error: aborting due to 4 previous errors