diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 692f39368243a..ca7a64e254e14 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -247,12 +247,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         AnonymousLifetimeMode::PassThrough,
                         |this, idty| {
                             let ret_id = asyncness.opt_return_id();
-                            this.lower_fn_decl(
-                                &decl,
-                                Some((fn_def_id.to_def_id(), idty)),
-                                true,
-                                ret_id,
-                            )
+                            this.lower_fn_decl(&decl, Some((fn_def_id, idty)), true, ret_id)
                         },
                     );
                     let sig = hir::FnSig {
@@ -1264,7 +1259,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
             |this, idty| {
                 this.lower_fn_decl(
                     &sig.decl,
-                    Some((fn_def_id.to_def_id(), idty)),
+                    Some((fn_def_id, idty)),
                     impl_trait_return_allow,
                     is_async,
                 )
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index d0fbc2d0f11d4..c04b0471cb72f 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -228,7 +228,7 @@ enum ImplTraitContext<'b, 'a> {
     ReturnPositionOpaqueTy {
         /// `DefId` for the parent function, used to look up necessary
         /// information later.
-        fn_def_id: DefId,
+        fn_def_id: LocalDefId,
         /// Origin: Either OpaqueTyOrigin::FnReturn or OpaqueTyOrigin::AsyncFn,
         origin: hir::OpaqueTyOrigin,
     },
@@ -646,31 +646,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     /// parameter while `f` is running (and restored afterwards).
     fn collect_in_band_defs<T>(
         &mut self,
-        parent_def_id: LocalDefId,
-        anonymous_lifetime_mode: AnonymousLifetimeMode,
-        f: impl FnOnce(&mut Self) -> (Vec<hir::GenericParam<'hir>>, T),
-    ) -> (Vec<hir::GenericParam<'hir>>, T) {
-        assert!(!self.is_collecting_in_band_lifetimes);
-        assert!(self.lifetimes_to_define.is_empty());
-        let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode;
-
-        self.anonymous_lifetime_mode = anonymous_lifetime_mode;
-        self.is_collecting_in_band_lifetimes = true;
-
-        let (in_band_ty_params, res) = f(self);
-
-        self.is_collecting_in_band_lifetimes = false;
-        self.anonymous_lifetime_mode = old_anonymous_lifetime_mode;
-
-        let lifetimes_to_define = self.lifetimes_to_define.split_off(0);
+        f: impl FnOnce(&mut Self) -> T,
+    ) -> (Vec<(Span, ParamName)>, T) {
+        let was_collecting = std::mem::replace(&mut self.is_collecting_in_band_lifetimes, true);
+        let len = self.lifetimes_to_define.len();
 
-        let params = lifetimes_to_define
-            .into_iter()
-            .map(|(span, hir_name)| self.lifetime_to_generic_param(span, hir_name, parent_def_id))
-            .chain(in_band_ty_params.into_iter())
-            .collect();
+        let res = f(self);
 
-        (params, res)
+        let lifetimes_to_define = self.lifetimes_to_define.split_off(len);
+        self.is_collecting_in_band_lifetimes = was_collecting;
+        (lifetimes_to_define, res)
     }
 
     /// Converts a lifetime into a new generic parameter.
@@ -785,27 +770,39 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         anonymous_lifetime_mode: AnonymousLifetimeMode,
         f: impl FnOnce(&mut Self, &mut Vec<hir::GenericParam<'hir>>) -> T,
     ) -> (hir::Generics<'hir>, T) {
-        let (in_band_defs, (mut lowered_generics, res)) =
-            self.with_in_scope_lifetime_defs(&generics.params, |this| {
-                this.collect_in_band_defs(parent_def_id, anonymous_lifetime_mode, |this| {
-                    let mut params = Vec::new();
-                    // Note: it is necessary to lower generics *before* calling `f`.
-                    // When lowering `async fn`, there's a final step when lowering
-                    // the return type that assumes that all in-scope lifetimes have
-                    // already been added to either `in_scope_lifetimes` or
-                    // `lifetimes_to_define`. If we swapped the order of these two,
-                    // in-band-lifetimes introduced by generics or where-clauses
-                    // wouldn't have been added yet.
-                    let generics = this.lower_generics_mut(
-                        generics,
-                        ImplTraitContext::Universal(&mut params, this.current_hir_id_owner),
-                    );
-                    let res = f(this, &mut params);
-                    (params, (generics, res))
+        let (lifetimes_to_define, (mut lowered_generics, impl_trait_defs, res)) = self
+            .collect_in_band_defs(|this| {
+                this.with_anonymous_lifetime_mode(anonymous_lifetime_mode, |this| {
+                    this.with_in_scope_lifetime_defs(&generics.params, |this| {
+                        let mut impl_trait_defs = Vec::new();
+                        // Note: it is necessary to lower generics *before* calling `f`.
+                        // When lowering `async fn`, there's a final step when lowering
+                        // the return type that assumes that all in-scope lifetimes have
+                        // already been added to either `in_scope_lifetimes` or
+                        // `lifetimes_to_define`. If we swapped the order of these two,
+                        // in-band-lifetimes introduced by generics or where-clauses
+                        // wouldn't have been added yet.
+                        let generics = this.lower_generics_mut(
+                            generics,
+                            ImplTraitContext::Universal(
+                                &mut impl_trait_defs,
+                                this.current_hir_id_owner,
+                            ),
+                        );
+                        let res = f(this, &mut impl_trait_defs);
+                        (generics, impl_trait_defs, res)
+                    })
                 })
             });
 
-        lowered_generics.params.extend(in_band_defs);
+        lowered_generics.params.extend(
+            lifetimes_to_define
+                .into_iter()
+                .map(|(span, hir_name)| {
+                    self.lifetime_to_generic_param(span, hir_name, parent_def_id)
+                })
+                .chain(impl_trait_defs),
+        );
 
         let lowered_generics = lowered_generics.into_generics(self.arena);
         (lowered_generics, res)
@@ -1380,7 +1377,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_opaque_impl_trait(
         &mut self,
         span: Span,
-        fn_def_id: Option<DefId>,
+        fn_def_id: Option<LocalDefId>,
         origin: hir::OpaqueTyOrigin,
         opaque_ty_node_id: NodeId,
         capturable_lifetimes: Option<&FxHashSet<hir::LifetimeName>>,
@@ -1452,7 +1449,6 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     span: lctx.lower_span(span),
                 },
                 bounds: hir_bounds,
-                impl_trait_fn: fn_def_id,
                 origin,
             };
 
@@ -1522,7 +1518,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_fn_decl(
         &mut self,
         decl: &FnDecl,
-        mut in_band_ty_params: Option<(DefId, &mut Vec<hir::GenericParam<'hir>>)>,
+        mut in_band_ty_params: Option<(LocalDefId, &mut Vec<hir::GenericParam<'hir>>)>,
         impl_trait_return_allow: bool,
         make_ret_async: Option<NodeId>,
     ) -> &'hir hir::FnDecl<'hir> {
@@ -1580,7 +1576,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                         Some((def_id, _)) if impl_trait_return_allow => {
                             ImplTraitContext::ReturnPositionOpaqueTy {
                                 fn_def_id: def_id,
-                                origin: hir::OpaqueTyOrigin::FnReturn,
+                                origin: hir::OpaqueTyOrigin::FnReturn(def_id),
                             }
                         }
                         _ => ImplTraitContext::disallowed(),
@@ -1635,7 +1631,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_async_fn_ret_ty(
         &mut self,
         output: &FnRetTy,
-        fn_def_id: DefId,
+        fn_def_id: LocalDefId,
         opaque_ty_node_id: NodeId,
     ) -> hir::FnRetTy<'hir> {
         debug!(
@@ -1689,18 +1685,29 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         // this is because the elided lifetimes from the return type
         // should be figured out using the ordinary elision rules, and
         // this desugaring achieves that.
+
+        debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", self.in_scope_lifetimes);
+        debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", self.lifetimes_to_define);
+
+        // Calculate all the lifetimes that should be captured
+        // by the opaque type. This should include all in-scope
+        // lifetime parameters, including those defined in-band.
         //
-        // The variable `input_lifetimes_count` tracks the number of
-        // lifetime parameters to the opaque type *not counting* those
-        // lifetimes elided in the return type. This includes those
-        // that are explicitly declared (`in_scope_lifetimes`) and
-        // those elided lifetimes we found in the arguments (current
-        // content of `lifetimes_to_define`). Next, we will process
-        // the return type, which will cause `lifetimes_to_define` to
-        // grow.
-        let input_lifetimes_count = self.in_scope_lifetimes.len() + self.lifetimes_to_define.len();
-
-        let mut lifetime_params = Vec::new();
+        // `lifetime_params` is a vector of tuple (span, parameter name, lifetime name).
+
+        // Input lifetime like `'a` or `'1`:
+        let mut lifetime_params: Vec<_> = self
+            .in_scope_lifetimes
+            .iter()
+            .cloned()
+            .map(|name| (name.ident().span, name, hir::LifetimeName::Param(name)))
+            .chain(
+                self.lifetimes_to_define
+                    .iter()
+                    .map(|&(span, name)| (span, name, hir::LifetimeName::Param(name))),
+            )
+            .collect();
+
         self.with_hir_id_owner(opaque_ty_node_id, |this| {
             // We have to be careful to get elision right here. The
             // idea is that we create a lifetime parameter for each
@@ -1710,34 +1717,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
             //
             // Then, we will create `fn foo(..) -> Foo<'_, '_>`, and
             // hence the elision takes place at the fn site.
-            let future_bound = this
-                .with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| {
-                    this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
+            let (lifetimes_to_define, future_bound) =
+                this.with_anonymous_lifetime_mode(AnonymousLifetimeMode::CreateParameter, |this| {
+                    this.collect_in_band_defs(|this| {
+                        this.lower_async_fn_output_type_to_future_bound(output, fn_def_id, span)
+                    })
                 });
-
             debug!("lower_async_fn_ret_ty: future_bound={:#?}", future_bound);
+            debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", lifetimes_to_define);
 
-            // Calculate all the lifetimes that should be captured
-            // by the opaque type. This should include all in-scope
-            // lifetime parameters, including those defined in-band.
-            //
-            // Note: this must be done after lowering the output type,
-            // as the output type may introduce new in-band lifetimes.
-            lifetime_params = this
-                .in_scope_lifetimes
-                .iter()
-                .cloned()
-                .map(|name| (name.ident().span, name))
-                .chain(this.lifetimes_to_define.iter().cloned())
-                .collect();
-
-            debug!("lower_async_fn_ret_ty: in_scope_lifetimes={:#?}", this.in_scope_lifetimes);
-            debug!("lower_async_fn_ret_ty: lifetimes_to_define={:#?}", this.lifetimes_to_define);
+            lifetime_params.extend(
+                // Output lifetime like `'_`:
+                lifetimes_to_define
+                    .into_iter()
+                    .map(|(span, name)| (span, name, hir::LifetimeName::Implicit(false))),
+            );
             debug!("lower_async_fn_ret_ty: lifetime_params={:#?}", lifetime_params);
 
             let generic_params =
-                this.arena.alloc_from_iter(lifetime_params.iter().map(|(span, hir_name)| {
-                    this.lifetime_to_generic_param(*span, *hir_name, opaque_ty_def_id)
+                this.arena.alloc_from_iter(lifetime_params.iter().map(|&(span, hir_name, _)| {
+                    this.lifetime_to_generic_param(span, hir_name, opaque_ty_def_id)
                 }));
 
             let opaque_ty_item = hir::OpaqueTy {
@@ -1747,8 +1746,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                     span: this.lower_span(span),
                 },
                 bounds: arena_vec![this; future_bound],
-                impl_trait_fn: Some(fn_def_id),
-                origin: hir::OpaqueTyOrigin::AsyncFn,
+                origin: hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
             };
 
             trace!("exist ty from async fn def id: {:#?}", opaque_ty_def_id);
@@ -1771,25 +1769,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
         //
         // For the "output" lifetime parameters, we just want to
         // generate `'_`.
-        let mut generic_args = Vec::with_capacity(lifetime_params.len());
-        generic_args.extend(lifetime_params[..input_lifetimes_count].iter().map(
-            |&(span, hir_name)| {
-                // Input lifetime like `'a` or `'1`:
+        let generic_args =
+            self.arena.alloc_from_iter(lifetime_params.into_iter().map(|(span, _, name)| {
                 GenericArg::Lifetime(hir::Lifetime {
                     hir_id: self.next_id(),
                     span: self.lower_span(span),
-                    name: hir::LifetimeName::Param(hir_name),
+                    name,
                 })
-            },
-        ));
-        generic_args.extend(lifetime_params[input_lifetimes_count..].iter().map(|&(span, _)|
-            // Output lifetime like `'_`.
-            GenericArg::Lifetime(hir::Lifetime {
-                hir_id: self.next_id(),
-                span: self.lower_span(span),
-                name: hir::LifetimeName::Implicit(false),
-            })));
-        let generic_args = self.arena.alloc_from_iter(generic_args);
+            }));
 
         // Create the `Foo<...>` reference itself. Note that the `type
         // Foo = impl Trait` is, internally, created as a child of the
@@ -1805,7 +1792,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
     fn lower_async_fn_output_type_to_future_bound(
         &mut self,
         output: &FnRetTy,
-        fn_def_id: DefId,
+        fn_def_id: LocalDefId,
         span: Span,
     ) -> hir::GenericBound<'hir> {
         // Compute the `T` in `Future<Output = T>` from the return type.
@@ -1816,7 +1803,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 // generates.
                 let context = ImplTraitContext::ReturnPositionOpaqueTy {
                     fn_def_id,
-                    origin: hir::OpaqueTyOrigin::FnReturn,
+                    origin: hir::OpaqueTyOrigin::FnReturn(fn_def_id),
                 };
                 self.lower_ty(ty, context)
             }
@@ -2453,17 +2440,12 @@ impl<'hir> GenericArgsCtor<'hir> {
     }
 }
 
+#[tracing::instrument(level = "debug")]
 fn lifetimes_from_impl_trait_bounds(
     opaque_ty_id: NodeId,
     bounds: hir::GenericBounds<'_>,
     lifetimes_to_include: Option<&FxHashSet<hir::LifetimeName>>,
 ) -> Vec<(hir::LifetimeName, Span)> {
-    debug!(
-        "lifetimes_from_impl_trait_bounds(opaque_ty_id={:?}, \
-             bounds={:#?})",
-        opaque_ty_id, bounds,
-    );
-
     // This visitor walks over `impl Trait` bounds and creates defs for all lifetimes that
     // appear in the bounds, excluding lifetimes that are created within the bounds.
     // E.g., `'a`, `'b`, but not `'c` in `impl for<'c> SomeTrait<'a, 'b, 'c>`.
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 4eb7be542e7a1..76b3be7976c61 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -173,7 +173,7 @@ fn check_opaque_type_parameter_valid(
         // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
         //
         // which would error here on all of the `'static` args.
-        OpaqueTyOrigin::FnReturn | OpaqueTyOrigin::AsyncFn => return true,
+        OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
         // Check these
         OpaqueTyOrigin::TyAlias => {}
     }
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 487ae87052ba3..d393ea6893849 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -2248,7 +2248,6 @@ pub struct BareFnTy<'hir> {
 pub struct OpaqueTy<'hir> {
     pub generics: Generics<'hir>,
     pub bounds: GenericBounds<'hir>,
-    pub impl_trait_fn: Option<DefId>,
     pub origin: OpaqueTyOrigin,
 }
 
@@ -2256,9 +2255,9 @@ pub struct OpaqueTy<'hir> {
 #[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
 pub enum OpaqueTyOrigin {
     /// `-> impl Trait`
-    FnReturn,
+    FnReturn(LocalDefId),
     /// `async fn`
-    AsyncFn,
+    AsyncFn(LocalDefId),
     /// type aliases: `type Foo = impl Trait;`
     TyAlias,
 }
@@ -2809,7 +2808,9 @@ impl ItemKind<'_> {
         Some(match *self {
             ItemKind::Fn(_, ref generics, _)
             | ItemKind::TyAlias(_, ref generics)
-            | ItemKind::OpaqueTy(OpaqueTy { ref generics, impl_trait_fn: None, .. })
+            | ItemKind::OpaqueTy(OpaqueTy {
+                ref generics, origin: OpaqueTyOrigin::TyAlias, ..
+            })
             | ItemKind::Enum(_, ref generics)
             | ItemKind::Struct(_, ref generics)
             | ItemKind::Union(_, ref generics)
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
index 90bc5b3b2fed1..04eceecc5f072 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs
@@ -107,7 +107,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                         kind:
                             hir::ItemKind::OpaqueTy(hir::OpaqueTy {
                                 bounds,
-                                origin: hir::OpaqueTyOrigin::AsyncFn,
+                                origin: hir::OpaqueTyOrigin::AsyncFn(..),
                                 ..
                             }),
                         ..
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index d9ab4ae1eda29..c2ef0b41e27bf 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -276,7 +276,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         debug!(?concrete_ty);
 
         let first_own_region = match opaque_defn.origin {
-            hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => {
+            hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {
                 // We lower
                 //
                 // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
@@ -461,35 +461,29 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> {
                     if let Some(def_id) = def_id.as_local() {
                         let opaque_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
                         let parent_def_id = self.infcx.defining_use_anchor;
-                        let (in_definition_scope, origin) = match tcx.hir().expect_item(def_id).kind
-                        {
+                        let item_kind = &tcx.hir().expect_item(def_id).kind;
+                        let hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, ..  }) = item_kind else {
+                            span_bug!(
+                                self.value_span,
+                                "weird opaque type: {:#?}, {:#?}",
+                                ty.kind(),
+                                item_kind
+                            )
+                        };
+                        let in_definition_scope = match *origin {
+                            // Async `impl Trait`
+                            hir::OpaqueTyOrigin::AsyncFn(parent) => parent == parent_def_id,
                             // Anonymous `impl Trait`
-                            hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                                impl_trait_fn: Some(parent),
-                                origin,
-                                ..
-                            }) => (parent == parent_def_id.to_def_id(), origin),
+                            hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
                             // Named `type Foo = impl Bar;`
-                            hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                                impl_trait_fn: None,
-                                origin,
-                                ..
-                            }) => {
-                                (may_define_opaque_type(tcx, parent_def_id, opaque_hir_id), origin)
-                            }
-                            ref itemkind => {
-                                span_bug!(
-                                    self.value_span,
-                                    "weird opaque type: {:#?}, {:#?}",
-                                    ty.kind(),
-                                    itemkind
-                                )
+                            hir::OpaqueTyOrigin::TyAlias => {
+                                may_define_opaque_type(tcx, parent_def_id, opaque_hir_id)
                             }
                         };
                         if in_definition_scope {
                             let opaque_type_key =
                                 OpaqueTypeKey { def_id: def_id.to_def_id(), substs };
-                            return self.fold_opaque_ty(ty, opaque_type_key, origin);
+                            return self.fold_opaque_ty(ty, opaque_type_key, *origin);
                         }
 
                         debug!(
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 1dceda6c7aad0..adba7d131592e 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -1,7 +1,5 @@
 use crate::arena::Arena;
-
 use rustc_serialize::{Encodable, Encoder};
-
 use std::alloc::Layout;
 use std::cmp::Ordering;
 use std::fmt;
@@ -12,49 +10,69 @@ use std::ops::Deref;
 use std::ptr;
 use std::slice;
 
-extern "C" {
-    /// A dummy type used to force `List` to be unsized while not requiring references to it be wide
-    /// pointers.
-    type OpaqueListContents;
-}
-
-/// A wrapper for slices with the additional invariant
-/// that the slice is interned and no other slice with
-/// the same contents can exist in the same context.
-/// This means we can use pointer for both
-/// equality comparisons and hashing.
-///
-/// Unlike slices, the types contained in `List` are expected to be `Copy`
-/// and iterating over a `List` returns `T` instead of a reference.
-///
-/// Note: `Slice` was already taken by the `Ty`.
+/// `List<T>` is a bit like `&[T]`, but with some critical differences.
+/// - IMPORTANT: Every `List<T>` is *required* to have unique contents. The
+///   type's correctness relies on this, *but it does not enforce it*.
+///   Therefore, any code that creates a `List<T>` must ensure uniqueness
+///   itself. In practice this is achieved by interning.
+/// - The length is stored within the `List<T>`, so `&List<Ty>` is a thin
+///   pointer.
+/// - Because of this, you cannot get a `List<T>` that is a sub-list of another
+///   `List<T>`. You can get a sub-slice `&[T]`, however.
+/// - `List<T>` can be used with `CopyTaggedPtr`, which is useful within
+///   structs whose size must be minimized.
+/// - Because of the uniqueness assumption, we can use the address of a
+///   `List<T>` for faster equality comparisons and hashing.
+/// - `T` must be `Copy`. This lets `List<T>` be stored in a dropless arena and
+///   iterators return a `T` rather than a `&T`.
+/// - `T` must not be zero-sized.
 #[repr(C)]
 pub struct List<T> {
     len: usize,
+
+    /// Although this claims to be a zero-length array, in practice `len`
+    /// elements are actually present.
     data: [T; 0],
+
     opaque: OpaqueListContents,
 }
 
-unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> {
-    const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize;
-    #[inline]
-    fn into_usize(self) -> usize {
-        self as *const List<T> as usize
-    }
-    #[inline]
-    unsafe fn from_usize(ptr: usize) -> Self {
-        &*(ptr as *const List<T>)
-    }
-    unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
-        // Self: Copy so this is fine
-        let ptr = Self::from_usize(ptr);
-        f(&ptr)
-    }
+extern "C" {
+    /// A dummy type used to force `List` to be unsized while not requiring
+    /// references to it be wide pointers.
+    type OpaqueListContents;
 }
 
-unsafe impl<T: Sync> Sync for List<T> {}
+impl<T> List<T> {
+    /// Returns a reference to the (unique, static) empty list.
+    #[inline(always)]
+    pub fn empty<'a>() -> &'a List<T> {
+        #[repr(align(64))]
+        struct MaxAlign;
+
+        assert!(mem::align_of::<T>() <= mem::align_of::<MaxAlign>());
+
+        #[repr(C)]
+        struct InOrder<T, U>(T, U);
+
+        // The empty slice is static and contains a single `0` usize (for the
+        // length) that is 64-byte aligned, thus featuring the necessary
+        // trailing padding for elements with up to 64-byte alignment.
+        static EMPTY_SLICE: InOrder<usize, MaxAlign> = InOrder(0, MaxAlign);
+        unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
+    }
+}
 
 impl<T: Copy> List<T> {
+    /// Allocates a list from `arena` and copies the contents of `slice` into it.
+    ///
+    /// WARNING: the contents *must be unique*, such that no list with these
+    /// contents has been previously created. If not, operations such as `eq`
+    /// and `hash` might give incorrect results.
+    ///
+    /// Panics if `T` is `Drop`, or `T` is zero-sized, or the slice is empty
+    /// (because the empty list exists statically, and is available via
+    /// `empty()`).
     #[inline]
     pub(super) fn from_arena<'tcx>(arena: &'tcx Arena<'tcx>, slice: &[T]) -> &'tcx List<T> {
         assert!(!mem::needs_drop::<T>());
@@ -73,7 +91,7 @@ impl<T: Copy> List<T> {
                 .cast::<T>()
                 .copy_from_nonoverlapping(slice.as_ptr(), slice.len());
 
-            &mut *mem
+            &*mem
         }
     }
 
@@ -107,11 +125,24 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for &List<T> {
     }
 }
 
+impl<T: PartialEq> PartialEq for List<T> {
+    #[inline]
+    fn eq(&self, other: &List<T>) -> bool {
+        // Pointer equality implies list equality (due to the unique contents
+        // assumption).
+        ptr::eq(self, other)
+    }
+}
+
+impl<T: Eq> Eq for List<T> {}
+
 impl<T> Ord for List<T>
 where
     T: Ord,
 {
     fn cmp(&self, other: &List<T>) -> Ordering {
+        // Pointer equality implies list equality (due to the unique contents
+        // assumption), but the contents must be compared otherwise.
         if self == other { Ordering::Equal } else { <[T] as Ord>::cmp(&**self, &**other) }
     }
 }
@@ -121,6 +152,8 @@ where
     T: PartialOrd,
 {
     fn partial_cmp(&self, other: &List<T>) -> Option<Ordering> {
+        // Pointer equality implies list equality (due to the unique contents
+        // assumption), but the contents must be compared otherwise.
         if self == other {
             Some(Ordering::Equal)
         } else {
@@ -129,17 +162,11 @@ where
     }
 }
 
-impl<T: PartialEq> PartialEq for List<T> {
-    #[inline]
-    fn eq(&self, other: &List<T>) -> bool {
-        ptr::eq(self, other)
-    }
-}
-impl<T: Eq> Eq for List<T> {}
-
 impl<T> Hash for List<T> {
     #[inline]
     fn hash<H: Hasher>(&self, s: &mut H) {
+        // Pointer hashing is sufficient (due to the unique contents
+        // assumption).
         (self as *const List<T>).hash(s)
     }
 }
@@ -168,13 +195,24 @@ impl<'a, T: Copy> IntoIterator for &'a List<T> {
     }
 }
 
-impl<T> List<T> {
-    #[inline(always)]
-    pub fn empty<'a>() -> &'a List<T> {
-        #[repr(align(64), C)]
-        struct EmptySlice([u8; 64]);
-        static EMPTY_SLICE: EmptySlice = EmptySlice([0; 64]);
-        assert!(mem::align_of::<T>() <= 64);
-        unsafe { &*(&EMPTY_SLICE as *const _ as *const List<T>) }
+unsafe impl<T: Sync> Sync for List<T> {}
+
+unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> {
+    const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize;
+
+    #[inline]
+    fn into_usize(self) -> usize {
+        self as *const List<T> as usize
+    }
+
+    #[inline]
+    unsafe fn from_usize(ptr: usize) -> &'a List<T> {
+        &*(ptr as *const List<T>)
+    }
+
+    unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
+        // `Self` is `&'a List<T>` which impls `Copy`, so this is fine.
+        let ptr = Self::from_usize(ptr);
+        f(&ptr)
     }
 }
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 7e1804673df2c..fd1409949f0a7 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -2055,13 +2055,17 @@ impl<'tcx> TyCtxt<'tcx> {
     }
 }
 
-/// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition.
-pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
-    if let Some(def_id) = def_id.as_local() {
-        if let Node::Item(item) = tcx.hir().get(tcx.hir().local_def_id_to_hir_id(def_id)) {
-            if let hir::ItemKind::OpaqueTy(ref opaque_ty) = item.kind {
-                return opaque_ty.impl_trait_fn;
-            }
+/// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition.
+pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId> {
+    let def_id = def_id.as_local()?;
+    if let Node::Item(item) = tcx.hir().get(tcx.hir().local_def_id_to_hir_id(def_id)) {
+        if let hir::ItemKind::OpaqueTy(ref opaque_ty) = item.kind {
+            return match opaque_ty.origin {
+                hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
+                    Some(parent)
+                }
+                hir::OpaqueTyOrigin::TyAlias => None,
+            };
         }
     }
     None
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index c6661e9c74e9b..23d59c8007135 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -105,6 +105,11 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
                                     a misaligned reference is undefined behavior (even if that \
                                     reference is never dereferenced)",
                                 )
+                                .help(
+                                    "copy the field contents to a local variable, or replace the \
+                                    reference with a raw pointer and use `read_unaligned`/`write_unaligned` \
+                                    (loads and stores via `*p` must be properly aligned even when using raw pointers)"
+                                )
                                 .emit()
                         },
                     );
diff --git a/compiler/rustc_resolve/src/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs
index 1ff33689b53c7..c94c56df75b78 100644
--- a/compiler/rustc_resolve/src/late/lifetimes.rs
+++ b/compiler/rustc_resolve/src/late/lifetimes.rs
@@ -968,7 +968,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                 let (generics, bounds) = match opaque_ty.kind {
                     // Named opaque `impl Trait` types are reached via `TyKind::Path`.
                     // This arm is for `impl Trait` in the types of statics, constants and locals.
-                    hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: None, .. }) => {
+                    hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+                        origin: hir::OpaqueTyOrigin::TyAlias,
+                        ..
+                    }) => {
                         intravisit::walk_ty(self, ty);
 
                         // Elided lifetimes are not allowed in non-return
@@ -985,7 +988,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
                     }
                     // RPIT (return position impl trait)
                     hir::ItemKind::OpaqueTy(hir::OpaqueTy {
-                        impl_trait_fn: Some(_),
+                        origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
                         ref generics,
                         bounds,
                         ..
@@ -1695,7 +1698,11 @@ fn compute_object_lifetime_defaults(
         hir::ItemKind::Struct(_, ref generics)
         | hir::ItemKind::Union(_, ref generics)
         | hir::ItemKind::Enum(_, ref generics)
-        | hir::ItemKind::OpaqueTy(hir::OpaqueTy { ref generics, impl_trait_fn: None, .. })
+        | hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+            ref generics,
+            origin: hir::OpaqueTyOrigin::TyAlias,
+            ..
+        })
         | hir::ItemKind::TyAlias(_, ref generics)
         | hir::ItemKind::Trait(_, _, ref generics, ..) => {
             let result = object_lifetime_defaults_for_item(tcx, generics);
@@ -2067,7 +2074,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
                                     ..
                                 }) = self.tcx.hir().get(parent_hir_id)
                                 {
-                                    if opaque.origin != hir::OpaqueTyOrigin::AsyncFn {
+                                    if !matches!(opaque.origin, hir::OpaqueTyOrigin::AsyncFn(..)) {
                                         continue 'lifetimes;
                                     }
                                     // We want to do this only if the liftime identifier is already defined
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index 711a6f2fbebdd..74a015d4c348e 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -248,7 +248,7 @@ fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
 fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
     // The param_env of an impl Trait type is its defining function's param_env
     if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
-        return param_env(tcx, parent);
+        return param_env(tcx, parent.to_def_id());
     }
     // Compute the bounds on Self and the type parameters.
 
@@ -313,7 +313,7 @@ fn well_formed_types_in_env<'tcx>(
 
     // The environment of an impl Trait type is its defining function's environment.
     if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
-        return well_formed_types_in_env(tcx, parent);
+        return well_formed_types_in_env(tcx, parent.to_def_id());
     }
 
     // Compute the bounds on `Self` and the type parameters.
diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs
index 427268d6d63f7..dc52c49499a58 100644
--- a/compiler/rustc_typeck/src/astconv/mod.rs
+++ b/compiler/rustc_typeck/src/astconv/mod.rs
@@ -2336,9 +2336,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
                 let def_id = item_id.def_id.to_def_id();
 
                 match opaque_ty.kind {
-                    hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
-                        self.impl_trait_ty_to_ty(def_id, lifetimes, impl_trait_fn.is_some())
-                    }
+                    hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => self
+                        .impl_trait_ty_to_ty(
+                            def_id,
+                            lifetimes,
+                            matches!(
+                                origin,
+                                hir::OpaqueTyOrigin::FnReturn(..)
+                                    | hir::OpaqueTyOrigin::AsyncFn(..)
+                            ),
+                        ),
                     ref i => bug!("`impl Trait` pointed to non-opaque type?? {:#?}", i),
                 }
             }
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 2061f955d968f..a6b16e7f0d4d8 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -541,7 +541,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
     }
 
     if let ItemKind::OpaqueTy(hir::OpaqueTy {
-        origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn,
+        origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
         ..
     }) = item.kind
     {
@@ -567,7 +567,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
             visitor.visit_item(&item);
             let is_async = match item.kind {
                 ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => {
-                    matches!(origin, hir::OpaqueTyOrigin::AsyncFn)
+                    matches!(origin, hir::OpaqueTyOrigin::AsyncFn(..))
                 }
                 _ => unreachable!(),
             };
@@ -604,7 +604,7 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
 ) -> Result<(), ErrorReported> {
     if tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs).is_err() {
         match origin {
-            hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span),
+            hir::OpaqueTyOrigin::AsyncFn(..) => async_opaque_type_cycle_error(tcx, span),
             _ => opaque_type_cycle_error(tcx, def_id, span),
         }
         Err(ErrorReported)
@@ -635,7 +635,7 @@ fn check_opaque_meets_bounds<'tcx>(
 ) {
     match origin {
         // Checked when type checking the function containing them.
-        hir::OpaqueTyOrigin::FnReturn | hir::OpaqueTyOrigin::AsyncFn => return,
+        hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => return,
         // Can have different predicates to their defining use
         hir::OpaqueTyOrigin::TyAlias => {}
     }
diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs
index fda96e49eb967..1334328f4e2ae 100644
--- a/compiler/rustc_typeck/src/collect.rs
+++ b/compiler/rustc_typeck/src/collect.rs
@@ -594,7 +594,11 @@ fn type_param_predicates(
                 ItemKind::Fn(.., ref generics, _)
                 | ItemKind::Impl(hir::Impl { ref generics, .. })
                 | ItemKind::TyAlias(_, ref generics)
-                | ItemKind::OpaqueTy(OpaqueTy { ref generics, impl_trait_fn: None, .. })
+                | ItemKind::OpaqueTy(OpaqueTy {
+                    ref generics,
+                    origin: hir::OpaqueTyOrigin::TyAlias,
+                    ..
+                })
                 | ItemKind::Enum(_, ref generics)
                 | ItemKind::Struct(_, ref generics)
                 | ItemKind::Union(_, ref generics) => generics,
@@ -793,7 +797,10 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) {
         }
 
         // Desugared from `impl Trait`, so visited by the function's return type.
-        hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => {}
+        hir::ItemKind::OpaqueTy(hir::OpaqueTy {
+            origin: hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..),
+            ..
+        }) => {}
 
         // Don't call `type_of` on opaque types, since that depends on type
         // checking function bodies. `check_item_type` ensures that it's called
@@ -1488,15 +1495,18 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
             Some(tcx.typeck_root_def_id(def_id))
         }
         Node::Item(item) => match item.kind {
-            ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn, .. }) => {
-                impl_trait_fn.or_else(|| {
-                    let parent_id = tcx.hir().get_parent_item(hir_id);
-                    assert!(parent_id != hir_id && parent_id != CRATE_HIR_ID);
-                    debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
-                    // Opaque types are always nested within another item, and
-                    // inherit the generics of the item.
-                    Some(tcx.hir().local_def_id(parent_id).to_def_id())
-                })
+            ItemKind::OpaqueTy(hir::OpaqueTy {
+                origin:
+                    hir::OpaqueTyOrigin::FnReturn(fn_def_id) | hir::OpaqueTyOrigin::AsyncFn(fn_def_id),
+                ..
+            }) => Some(fn_def_id.to_def_id()),
+            ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
+                let parent_id = tcx.hir().get_parent_item(hir_id);
+                assert!(parent_id != hir_id && parent_id != CRATE_HIR_ID);
+                debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
+                // Opaque types are always nested within another item, and
+                // inherit the generics of the item.
+                Some(tcx.hir().local_def_id(parent_id).to_def_id())
             }
             _ => None,
         },
@@ -2051,31 +2061,32 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                     generics
                 }
                 ItemKind::OpaqueTy(OpaqueTy {
-                    bounds: _,
-                    impl_trait_fn,
+                    origin: hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..),
+                    ..
+                }) => {
+                    // return-position impl trait
+                    //
+                    // We don't inherit predicates from the parent here:
+                    // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
+                    // then the return type is `f::<'static, T>::{{opaque}}`.
+                    //
+                    // If we inherited the predicates of `f` then we would
+                    // require that `T: 'static` to show that the return
+                    // type is well-formed.
+                    //
+                    // The only way to have something with this opaque type
+                    // is from the return type of the containing function,
+                    // which will ensure that the function's predicates
+                    // hold.
+                    return ty::GenericPredicates { parent: None, predicates: &[] };
+                }
+                ItemKind::OpaqueTy(OpaqueTy {
                     ref generics,
-                    origin: _,
+                    origin: hir::OpaqueTyOrigin::TyAlias,
+                    ..
                 }) => {
-                    if impl_trait_fn.is_some() {
-                        // return-position impl trait
-                        //
-                        // We don't inherit predicates from the parent here:
-                        // If we have, say `fn f<'a, T: 'a>() -> impl Sized {}`
-                        // then the return type is `f::<'static, T>::{{opaque}}`.
-                        //
-                        // If we inherited the predicates of `f` then we would
-                        // require that `T: 'static` to show that the return
-                        // type is well-formed.
-                        //
-                        // The only way to have something with this opaque type
-                        // is from the return type of the containing function,
-                        // which will ensure that the function's predicates
-                        // hold.
-                        return ty::GenericPredicates { parent: None, predicates: &[] };
-                    } else {
-                        // type-alias impl trait
-                        generics
-                    }
+                    // type-alias impl trait
+                    generics
                 }
 
                 _ => NO_GENERICS,
diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs
index b684844744de3..af199ca99460f 100644
--- a/compiler/rustc_typeck/src/collect/type_of.rs
+++ b/compiler/rustc_typeck/src/collect/type_of.rs
@@ -394,13 +394,13 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                     let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
                     tcx.mk_adt(def, substs)
                 }
-                ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: None, .. }) => {
+                ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
                     find_opaque_ty_constraints(tcx, def_id)
                 }
                 // Opaque types desugared from `impl Trait`.
-                ItemKind::OpaqueTy(OpaqueTy { impl_trait_fn: Some(owner), .. }) => {
+                ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::FnReturn(owner) | hir::OpaqueTyOrigin::AsyncFn(owner), .. }) => {
                     let concrete_ty = tcx
-                        .mir_borrowck(owner.expect_local())
+                        .mir_borrowck(owner)
                         .concrete_opaque_types
                         .get_value_matching(|(key, _)| key.def_id == def_id.to_def_id())
                         .copied()
@@ -413,7 +413,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> {
                                 ),
                             );
                             if let Some(ErrorReported) =
-                                tcx.typeck(owner.expect_local()).tainted_by_errors
+                                tcx.typeck(owner).tainted_by_errors
                             {
                                 // Some error in the
                                 // owner fn prevented us from populating
diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs
index 4b89bc363268d..920fa59c8ad6e 100644
--- a/library/core/src/iter/adapters/zip.rs
+++ b/library/core/src/iter/adapters/zip.rs
@@ -45,15 +45,23 @@ impl<A: Iterator, B: Iterator> Zip<A, B> {
 ///
 /// let xs = [1, 2, 3];
 /// let ys = [4, 5, 6];
-/// for (x, y) in zip(&xs, &ys) {
-///     println!("x:{}, y:{}", x, y);
-/// }
+///
+/// let mut iter = zip(xs, ys);
+///
+/// assert_eq!(iter.next().unwrap(), (1, 4));
+/// assert_eq!(iter.next().unwrap(), (2, 5));
+/// assert_eq!(iter.next().unwrap(), (3, 6));
+/// assert!(iter.next().is_none());
 ///
 /// // Nested zips are also possible:
 /// let zs = [7, 8, 9];
-/// for ((x, y), z) in zip(zip(&xs, &ys), &zs) {
-///     println!("x:{}, y:{}, z:{}", x, y, z);
-/// }
+///
+/// let mut iter = zip(zip(xs, ys), zs);
+///
+/// assert_eq!(iter.next().unwrap(), ((1, 4), 7));
+/// assert_eq!(iter.next().unwrap(), ((2, 5), 8));
+/// assert_eq!(iter.next().unwrap(), ((3, 6), 9));
+/// assert!(iter.next().is_none());
 /// ```
 #[unstable(feature = "iter_zip", issue = "83574")]
 pub fn zip<A, B>(a: A, b: B) -> Zip<A::IntoIter, B::IntoIter>
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 014d5119b05fd..dae85027b6c29 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -1058,7 +1058,7 @@ impl Metadata {
     /// }
     /// ```
     #[must_use]
-    #[stable(feature = "is_symlink", since = "1.57.0")]
+    #[stable(feature = "is_symlink", since = "1.58.0")]
     pub fn is_symlink(&self) -> bool {
         self.file_type().is_symlink()
     }
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 9ade2847e8ea9..7d401cff591c1 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -2817,7 +2817,7 @@ impl Path {
     /// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call
     /// [`fs::Metadata::is_symlink`] if it was [`Ok`].
     #[must_use]
-    #[stable(feature = "is_symlink", since = "1.57.0")]
+    #[stable(feature = "is_symlink", since = "1.58.0")]
     pub fn is_symlink(&self) -> bool {
         fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
     }
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index ee19567be102f..35df5fa1b7470 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -327,6 +327,19 @@ impl Options {
             return Err(0);
         }
 
+        let color = config::parse_color(matches);
+        let config::JsonConfig { json_rendered, json_unused_externs, .. } =
+            config::parse_json(matches);
+        let error_format = config::parse_error_format(matches, color, json_rendered);
+
+        let codegen_options = CodegenOptions::build(matches, error_format);
+        let debugging_opts = DebuggingOptions::build(matches, error_format);
+
+        let diag = new_handler(error_format, None, &debugging_opts);
+
+        // check for deprecated options
+        check_deprecated_options(matches, &diag);
+
         if matches.opt_strs("passes") == ["list"] {
             println!("Available passes for running rustdoc:");
             for pass in passes::PASSES {
@@ -359,19 +372,6 @@ impl Options {
             return Err(0);
         }
 
-        let color = config::parse_color(matches);
-        let config::JsonConfig { json_rendered, json_unused_externs, .. } =
-            config::parse_json(matches);
-        let error_format = config::parse_error_format(matches, color, json_rendered);
-
-        let codegen_options = CodegenOptions::build(matches, error_format);
-        let debugging_opts = DebuggingOptions::build(matches, error_format);
-
-        let diag = new_handler(error_format, None, &debugging_opts);
-
-        // check for deprecated options
-        check_deprecated_options(matches, &diag);
-
         let mut emit = Vec::new();
         for list in matches.opt_strs("emit") {
             for kind in list.split(',') {
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 1691de93bdda2..9943e23b9281c 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -976,6 +976,7 @@ fn item_typedef(
     // associated items from the aliased type (see discussion in #32077), but
     // we need #14072 to make sense of the generics.
     render_assoc_items(w, cx, it, def_id, AssocItemRender::All);
+    document_type_layout(w, cx, def_id);
 }
 
 fn item_union(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, s: &clean::Union) {
diff --git a/src/test/rustdoc-ui/issue-91713.rs b/src/test/rustdoc-ui/issue-91713.rs
new file mode 100644
index 0000000000000..b7057d868c275
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91713.rs
@@ -0,0 +1,3 @@
+// check-pass
+// compile-flags: --passes list
+// error-pattern: the `passes` flag is deprecated
diff --git a/src/test/rustdoc-ui/issue-91713.stderr b/src/test/rustdoc-ui/issue-91713.stderr
new file mode 100644
index 0000000000000..70c22b3c01e9e
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91713.stderr
@@ -0,0 +1,4 @@
+warning: the `passes` flag is deprecated
+   |
+   = note: see issue #44136 <https://github.com/rust-lang/rust/issues/44136> for more information
+
diff --git a/src/test/rustdoc-ui/issue-91713.stdout b/src/test/rustdoc-ui/issue-91713.stdout
new file mode 100644
index 0000000000000..d0372d4945f3a
--- /dev/null
+++ b/src/test/rustdoc-ui/issue-91713.stdout
@@ -0,0 +1,31 @@
+Available passes for running rustdoc:
+check_doc_test_visibility - run various visibility-related lints on doctests
+        strip-hidden - strips all `#[doc(hidden)]` items from the output
+   unindent-comments - removes excess indentation on comments in order for markdown to like it
+       strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports
+  strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate
+   propagate-doc-cfg - propagates `#[doc(cfg(...))]` to child items
+collect-intra-doc-links - resolves intra-doc links
+check-code-block-syntax - validates syntax inside Rust code blocks
+ collect-trait-impls - retrieves trait impls for items in the crate
+calculate-doc-coverage - counts the number of items with and without documentation
+check-invalid-html-tags - detects invalid HTML tags in doc comments
+     check-bare-urls - detects URLs that are not hyperlinks
+
+Default passes for rustdoc:
+ collect-trait-impls
+   unindent-comments
+check_doc_test_visibility
+        strip-hidden  (when not --document-hidden-items)
+       strip-private  (when not --document-private-items)
+  strip-priv-imports  (when --document-private-items)
+collect-intra-doc-links
+check-code-block-syntax
+check-invalid-html-tags
+   propagate-doc-cfg
+     check-bare-urls
+
+Passes run with `--show-coverage`:
+        strip-hidden  (when not --document-hidden-items)
+       strip-private  (when not --document-private-items)
+calculate-doc-coverage
diff --git a/src/test/rustdoc/type-layout.rs b/src/test/rustdoc/type-layout.rs
index 0868486fa59cd..4eea9809ac58f 100644
--- a/src/test/rustdoc/type-layout.rs
+++ b/src/test/rustdoc/type-layout.rs
@@ -50,6 +50,18 @@ pub struct GenericLifetimes<'a>(&'a str);
 // @has - '(unsized)'
 pub struct Unsized([u8]);
 
+// @has type_layout/type.TypeAlias.html 'Size: '
+// @has - ' bytes'
+pub type TypeAlias = X;
+
+// @has type_layout/type.GenericTypeAlias.html 'Size: '
+// @has - '8 bytes'
+pub type GenericTypeAlias = (Generic<(u32, ())>, Generic<u32>);
+
+// Regression test for the rustdoc equivalent of #85103.
+// @has type_layout/type.Edges.html 'Encountered an error during type layout; the type failed to be normalized.'
+pub type Edges<'a, E> = std::borrow::Cow<'a, [E]>;
+
 // @!has type_layout/trait.MyTrait.html 'Size: '
 pub trait MyTrait {}
 
diff --git a/src/test/ui/async-await/generics-and-bounds.rs b/src/test/ui/async-await/generics-and-bounds.rs
index 963b19b34a620..90ab0c01f5450 100644
--- a/src/test/ui/async-await/generics-and-bounds.rs
+++ b/src/test/ui/async-await/generics-and-bounds.rs
@@ -2,6 +2,8 @@
 // edition:2018
 // compile-flags: --crate-type lib
 
+#![feature(in_band_lifetimes)]
+
 use std::future::Future;
 
 pub async fn simple_generic<T>() {}
@@ -71,6 +73,10 @@ pub fn call_with_ref_block<'a>(f: &'a (impl Foo + 'a)) -> impl Future<Output = (
     async move { f.foo() }
 }
 
+pub fn call_with_ref_block_in_band(f: &'a (impl Foo + 'a)) -> impl Future<Output = ()> + 'a {
+    async move { f.foo() }
+}
+
 pub fn async_block_with_same_generic_params_unifies() {
     let mut a = call_generic_bound_block(FooType);
     a = call_generic_bound_block(FooType);
@@ -85,4 +91,9 @@ pub fn async_block_with_same_generic_params_unifies() {
     let f_two = FooType;
     let mut d = call_with_ref_block(&f_one);
     d = call_with_ref_block(&f_two);
+
+    let f_one = FooType;
+    let f_two = FooType;
+    let mut d = call_with_ref_block_in_band(&f_one);
+    d = call_with_ref_block_in_band(&f_two);
 }
diff --git a/src/test/ui/binding/issue-53114-safety-checks.stderr b/src/test/ui/binding/issue-53114-safety-checks.stderr
index 9e7deea4524cb..84cdb1453f82d 100644
--- a/src/test/ui/binding/issue-53114-safety-checks.stderr
+++ b/src/test/ui/binding/issue-53114-safety-checks.stderr
@@ -8,6 +8,7 @@ LL |     let _ = &p.b;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 warning: reference to packed field is unaligned
   --> $DIR/issue-53114-safety-checks.rs:29:17
@@ -18,6 +19,7 @@ LL |     let (_,) = (&p.b,);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 warning: reference to packed field is unaligned
   --> $DIR/issue-53114-safety-checks.rs:39:11
@@ -28,6 +30,7 @@ LL |     match &p.b  { _ => { } }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 warning: reference to packed field is unaligned
   --> $DIR/issue-53114-safety-checks.rs:45:12
@@ -38,6 +41,7 @@ LL |     match (&p.b,)  { (_,) => { } }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error[E0133]: access to union field is unsafe and requires unsafe function or block
   --> $DIR/issue-53114-safety-checks.rs:26:13
diff --git a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
index 5acf3797ab53f..fc0179d2cb4ca 100644
--- a/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
+++ b/src/test/ui/closures/2229_closure_analysis/diagnostics/repr_packed.stderr
@@ -8,6 +8,7 @@ LL |         println!("{}", foo.x);
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
    = note: this warning originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: 1 warning emitted
diff --git a/src/test/ui/lint/unaligned_references.stderr b/src/test/ui/lint/unaligned_references.stderr
index 6a5cc91963da0..53c9380fb7efb 100644
--- a/src/test/ui/lint/unaligned_references.stderr
+++ b/src/test/ui/lint/unaligned_references.stderr
@@ -12,6 +12,7 @@ LL | #![deny(unaligned_references)]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: reference to packed field is unaligned
   --> $DIR/unaligned_references.rs:24:17
@@ -22,6 +23,7 @@ LL |         let _ = &good.data;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: reference to packed field is unaligned
   --> $DIR/unaligned_references.rs:27:17
@@ -32,6 +34,7 @@ LL |         let _ = &good.data as *const _;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: reference to packed field is unaligned
   --> $DIR/unaligned_references.rs:29:27
@@ -42,6 +45,7 @@ LL |         let _: *const _ = &good.data;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: reference to packed field is unaligned
   --> $DIR/unaligned_references.rs:32:17
@@ -52,6 +56,7 @@ LL |         let _ = good.data.clone();
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: reference to packed field is unaligned
   --> $DIR/unaligned_references.rs:35:17
@@ -62,6 +67,7 @@ LL |         let _ = &good.data2[0];
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: reference to packed field is unaligned
   --> $DIR/unaligned_references.rs:45:17
@@ -72,6 +78,7 @@ LL |         let _ = &packed2.x;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: aborting due to 7 previous errors
 
diff --git a/src/test/ui/lint/unaligned_references_external_macro.stderr b/src/test/ui/lint/unaligned_references_external_macro.stderr
index 5e84fdca1d3ce..01e2395049df4 100644
--- a/src/test/ui/lint/unaligned_references_external_macro.stderr
+++ b/src/test/ui/lint/unaligned_references_external_macro.stderr
@@ -24,6 +24,7 @@ LL | | }
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
    = note: this error originates in the macro `unaligned_references_external_crate::mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
diff --git a/src/test/ui/packed/issue-27060.stderr b/src/test/ui/packed/issue-27060.stderr
index 09297884ed377..bba056d59f831 100644
--- a/src/test/ui/packed/issue-27060.stderr
+++ b/src/test/ui/packed/issue-27060.stderr
@@ -12,6 +12,7 @@ LL | #[deny(unaligned_references)]
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: reference to packed field is unaligned
   --> $DIR/issue-27060.rs:18:13
@@ -22,6 +23,7 @@ LL |     let _ = &good.data2[0];
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: reference to packed field is unaligned
   --> $DIR/issue-27060.rs:21:13
@@ -32,6 +34,7 @@ LL |     let _ = &good.data;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: reference to packed field is unaligned
   --> $DIR/issue-27060.rs:23:13
@@ -42,6 +45,7 @@ LL |     let _ = &good.data2[0];
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr b/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr
index 766d8a72c349e..04585b499862b 100644
--- a/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr
+++ b/src/test/ui/packed/packed-struct-borrow-element-64bit.stderr
@@ -8,6 +8,7 @@ LL |     let brw = &foo.baz;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 warning: 1 warning emitted
 
diff --git a/src/test/ui/packed/packed-struct-borrow-element.stderr b/src/test/ui/packed/packed-struct-borrow-element.stderr
index 5764e951a4600..a50b130200151 100644
--- a/src/test/ui/packed/packed-struct-borrow-element.stderr
+++ b/src/test/ui/packed/packed-struct-borrow-element.stderr
@@ -8,6 +8,7 @@ LL |     let brw = &foo.baz;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 warning: reference to packed field is unaligned
   --> $DIR/packed-struct-borrow-element.rs:30:15
@@ -18,6 +19,7 @@ LL |     let brw = &foo.baz;
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #82523 <https://github.com/rust-lang/rust/issues/82523>
    = note: fields of packed structs are not properly aligned, and creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+   = help: copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
 
 warning: 2 warnings emitted