diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 0b9d0a0e9220b..f8439d2e16355 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -253,8 +253,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
         let constraint_sets: Vec<_> = unnormalized_input_output_tys
             .flat_map(|ty| {
                 debug!("build: input_or_output={:?}", ty);
-                // We add implied bounds from both the unnormalized and normalized ty
-                // See issue #87748
+                // We only add implied bounds for the normalized type as the unnormalized
+                // type may not actually get checked by the caller.
+                //
+                // Can otherwise be unsound, see #91068.
                 let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self
                     .param_env
                     .and(type_op::normalize::Normalize::new(ty))
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 7dc292ffb6579..e9fa33f656f31 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -1899,7 +1899,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                                     ObligationCause::new(
                                         span,
                                         self.tcx().hir().local_def_id_to_hir_id(def_id),
-                                        traits::ObligationCauseCode::RepeatVec(is_const_fn),
+                                        traits::ObligationCauseCode::RepeatElementCopy {
+                                            is_const_fn,
+                                        },
                                     ),
                                     self.param_env,
                                     ty::Binder::dummy(ty::TraitRef::new(
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 71ee4f1e76d6d..09b02ba74a8de 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -65,7 +65,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         Self {
             tcx: self.tcx.clone(),
             defining_use_anchor: self.defining_use_anchor.clone(),
-            reveal_defining_opaque_types: self.reveal_defining_opaque_types.clone(),
             in_progress_typeck_results: self.in_progress_typeck_results.clone(),
             inner: self.inner.clone(),
             skip_leak_check: self.skip_leak_check.clone(),
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index a9b4451e77b08..bd59bf4dea883 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -290,10 +290,6 @@ pub struct InferCtxt<'a, 'tcx> {
     /// to the outside until the end up in an `InferCtxt` for typeck or borrowck.
     pub defining_use_anchor: Option<LocalDefId>,
 
-    /// Used by WF-checking to not have to figure out hidden types itself, but
-    /// to just invoke type_of to get the already computed hidden type from typeck.
-    pub reveal_defining_opaque_types: bool,
-
     /// During type-checking/inference of a body, `in_progress_typeck_results`
     /// contains a reference to the typeck results being built up, which are
     /// used for reading closure kinds/signatures as they are inferred,
@@ -569,7 +565,6 @@ pub struct InferCtxtBuilder<'tcx> {
     tcx: TyCtxt<'tcx>,
     fresh_typeck_results: Option<RefCell<ty::TypeckResults<'tcx>>>,
     defining_use_anchor: Option<LocalDefId>,
-    reveal_defining_opaque_types: bool,
 }
 
 pub trait TyCtxtInferExt<'tcx> {
@@ -578,12 +573,7 @@ pub trait TyCtxtInferExt<'tcx> {
 
 impl<'tcx> TyCtxtInferExt<'tcx> for TyCtxt<'tcx> {
     fn infer_ctxt(self) -> InferCtxtBuilder<'tcx> {
-        InferCtxtBuilder {
-            tcx: self,
-            defining_use_anchor: None,
-            fresh_typeck_results: None,
-            reveal_defining_opaque_types: false,
-        }
+        InferCtxtBuilder { tcx: self, defining_use_anchor: None, fresh_typeck_results: None }
     }
 }
 
@@ -607,13 +597,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
         self
     }
 
-    /// WF-checking doesn't need to recompute opaque types and can instead use
-    /// the type_of query to get them from typeck.
-    pub fn reveal_defining_opaque_types(mut self) -> Self {
-        self.reveal_defining_opaque_types = true;
-        self
-    }
-
     /// Given a canonical value `C` as a starting point, create an
     /// inference context that contains each of the bound values
     /// within instantiated as a fresh variable. The `f` closure is
@@ -638,17 +621,11 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
     }
 
     pub fn enter<R>(&mut self, f: impl for<'a> FnOnce(InferCtxt<'a, 'tcx>) -> R) -> R {
-        let InferCtxtBuilder {
-            tcx,
-            defining_use_anchor,
-            reveal_defining_opaque_types,
-            ref fresh_typeck_results,
-        } = *self;
+        let InferCtxtBuilder { tcx, defining_use_anchor, ref fresh_typeck_results } = *self;
         let in_progress_typeck_results = fresh_typeck_results.as_ref();
         f(InferCtxt {
             tcx,
             defining_use_anchor,
-            reveal_defining_opaque_types,
             in_progress_typeck_results,
             inner: RefCell::new(InferCtxtInner::new()),
             lexical_region_resolutions: RefCell::new(None),
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 3d0a0d2a58e1f..1f18260d9154f 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -236,11 +236,12 @@ pub enum ObligationCauseCode<'tcx> {
     SizedBoxType,
     /// Inline asm operand type must be `Sized`.
     InlineAsmSized,
-    /// `[T, ..n]` implies that `T` must be `Copy`.
-    /// If the function in the array repeat expression is a `const fn`,
-    /// display a help message suggesting to move the function call to a
-    /// new `const` item while saying that `T` doesn't implement `Copy`.
-    RepeatVec(bool),
+    /// `[expr; N]` requires `type_of(expr): Copy`.
+    RepeatElementCopy {
+        /// If element is a `const fn` we display a help message suggesting to move the
+        /// function call to a new `const` item while saying that `T` doesn't implement `Copy`.
+        is_const_fn: bool,
+    },
 
     /// Types of fields (other than the last, except for packed structs) in a struct must be sized.
     FieldSized {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 57aec86785657..72b597bb13d29 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -198,7 +198,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
         let kind = match pat.kind {
             hir::PatKind::Wild => PatKind::Wild,
 
-            hir::PatKind::Lit(ref value) => self.lower_lit(value),
+            hir::PatKind::Lit(value) => self.lower_lit(value),
 
             hir::PatKind::Range(ref lo_expr, ref hi_expr, end) => {
                 let (lo_expr, hi_expr) = (lo_expr.as_deref(), hi_expr.as_deref());
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 468c7a3c55b36..d83781170e8c3 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -2285,10 +2285,10 @@ impl<'v> Visitor<'v> for FindTypeParam {
     }
 }
 
-pub fn recursive_type_with_infinite_size_error(
-    tcx: TyCtxt<'_>,
+pub fn recursive_type_with_infinite_size_error<'tcx>(
+    tcx: TyCtxt<'tcx>,
     type_def_id: DefId,
-    spans: Vec<Span>,
+    spans: Vec<(Span, Option<hir::HirId>)>,
 ) {
     assert!(type_def_id.is_local());
     let span = tcx.hir().span_if_local(type_def_id).unwrap();
@@ -2297,7 +2297,7 @@ pub fn recursive_type_with_infinite_size_error(
     let mut err =
         struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path);
     err.span_label(span, "recursive type has infinite size");
-    for &span in &spans {
+    for &(span, _) in &spans {
         err.span_label(span, "recursive without indirection");
     }
     let msg = format!(
@@ -2305,16 +2305,25 @@ pub fn recursive_type_with_infinite_size_error(
         path,
     );
     if spans.len() <= 4 {
+        // FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed
         err.multipart_suggestion(
             &msg,
             spans
-                .iter()
-                .flat_map(|&span| {
-                    [
-                        (span.shrink_to_lo(), "Box<".to_string()),
-                        (span.shrink_to_hi(), ">".to_string()),
-                    ]
-                    .into_iter()
+                .into_iter()
+                .flat_map(|(span, field_id)| {
+                    if let Some(generic_span) = get_option_generic_from_field_id(tcx, field_id) {
+                        // If we match an `Option` and can grab the span of the Option's generic, then
+                        // suggest boxing the generic arg for a non-null niche optimization.
+                        vec![
+                            (generic_span.shrink_to_lo(), "Box<".to_string()),
+                            (generic_span.shrink_to_hi(), ">".to_string()),
+                        ]
+                    } else {
+                        vec![
+                            (span.shrink_to_lo(), "Box<".to_string()),
+                            (span.shrink_to_hi(), ">".to_string()),
+                        ]
+                    }
                 })
                 .collect(),
             Applicability::HasPlaceholders,
@@ -2325,6 +2334,34 @@ pub fn recursive_type_with_infinite_size_error(
     err.emit();
 }
 
+/// Extract the span for the generic type `T` of `Option<T>` in a field definition
+fn get_option_generic_from_field_id(tcx: TyCtxt<'_>, field_id: Option<hir::HirId>) -> Option<Span> {
+    let node = tcx.hir().find(field_id?);
+
+    // Expect a field from our field_id
+    let Some(hir::Node::Field(field_def)) = node
+        else { bug!("Expected HirId corresponding to FieldDef, found: {:?}", node) };
+
+    // Match a type that is a simple QPath with no Self
+    let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = &field_def.ty.kind
+        else { return None };
+
+    // Check if the path we're checking resolves to Option
+    let hir::def::Res::Def(_, did) = path.res
+        else { return None };
+
+    // Bail if this path doesn't describe `::core::option::Option`
+    if !tcx.is_diagnostic_item(sym::Option, did) {
+        return None;
+    }
+
+    // Match a single generic arg in the 0th path segment
+    let generic_arg = path.segments.last()?.args?.args.get(0)?;
+
+    // Take the span out of the type, if it's a type
+    if let hir::GenericArg::Type(generic_ty) = generic_arg { Some(generic_ty.span) } else { None }
+}
+
 /// Summarizes information
 #[derive(Clone)]
 pub enum ArgKind {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 505d78d800a3a..58e002b336081 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1988,7 +1988,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             ObligationCauseCode::Coercion { source: _, target } => {
                 err.note(&format!("required by cast to type `{}`", self.ty_to_string(target)));
             }
-            ObligationCauseCode::RepeatVec(is_const_fn) => {
+            ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
                 err.note(
                     "the `Copy` trait is required because the repeated element will be copied",
                 );
diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs
index b8f3efe6462ea..7efc82efd15c3 100644
--- a/compiler/rustc_ty_utils/src/representability.rs
+++ b/compiler/rustc_ty_utils/src/representability.rs
@@ -17,12 +17,20 @@ use std::cmp;
 pub enum Representability {
     Representable,
     ContainsRecursive,
-    SelfRecursive(Vec<Span>),
+    /// Return a list of types that are included in themselves:
+    /// the spans where they are self-included, and (if found)
+    /// the HirId of the FieldDef that defines the self-inclusion.
+    SelfRecursive(Vec<(Span, Option<hir::HirId>)>),
 }
 
 /// Check whether a type is representable. This means it cannot contain unboxed
 /// structural recursion. This check is needed for structs and enums.
-pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> Representability {
+pub fn ty_is_representable<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+    sp: Span,
+    field_id: Option<hir::HirId>,
+) -> Representability {
     debug!("is_type_representable: {:?}", ty);
     // To avoid a stack overflow when checking an enum variant or struct that
     // contains a different, structurally recursive type, maintain a stack of
@@ -38,11 +46,12 @@ pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> R
     let mut force_result = false;
     let r = is_type_structurally_recursive(
         tcx,
-        sp,
         &mut seen,
         &mut shadow_seen,
         &mut representable_cache,
         ty,
+        sp,
+        field_id,
         &mut force_result,
     );
     debug!("is_type_representable: {:?} is {:?}", ty, r);
@@ -61,11 +70,12 @@ fn fold_repr<It: Iterator<Item = Representability>>(iter: It) -> Representabilit
 
 fn are_inner_types_recursive<'tcx>(
     tcx: TyCtxt<'tcx>,
-    sp: Span,
     seen: &mut Vec<Ty<'tcx>>,
     shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
     ty: Ty<'tcx>,
+    sp: Span,
+    field_id: Option<hir::HirId>,
     force_result: &mut bool,
 ) -> Representability {
     debug!("are_inner_types_recursive({:?}, {:?}, {:?})", ty, seen, shadow_seen);
@@ -75,11 +85,12 @@ fn are_inner_types_recursive<'tcx>(
             fold_repr(fields.iter().map(|ty| {
                 is_type_structurally_recursive(
                     tcx,
-                    sp,
                     seen,
                     shadow_seen,
                     representable_cache,
                     ty,
+                    sp,
+                    field_id,
                     force_result,
                 )
             }))
@@ -88,20 +99,26 @@ fn are_inner_types_recursive<'tcx>(
         // FIXME(#11924) Behavior undecided for zero-length vectors.
         ty::Array(ty, _) => is_type_structurally_recursive(
             tcx,
-            sp,
             seen,
             shadow_seen,
             representable_cache,
             *ty,
+            sp,
+            field_id,
             force_result,
         ),
         ty::Adt(def, substs) => {
             // Find non representable fields with their spans
             fold_repr(def.all_fields().map(|field| {
                 let ty = field.ty(tcx, substs);
-                let span = match field.did.as_local().and_then(|id| tcx.hir().find_by_def_id(id)) {
-                    Some(hir::Node::Field(field)) => field.ty.span,
-                    _ => sp,
+                let (sp, field_id) = match field
+                    .did
+                    .as_local()
+                    .map(|id| tcx.hir().local_def_id_to_hir_id(id))
+                    .and_then(|id| tcx.hir().find(id))
+                {
+                    Some(hir::Node::Field(field)) => (field.ty.span, Some(field.hir_id)),
+                    _ => (sp, field_id),
                 };
 
                 let mut result = None;
@@ -130,7 +147,7 @@ fn are_inner_types_recursive<'tcx>(
                 // result without adjusting).
                 if shadow_seen.len() > seen.len() && shadow_seen.first() == Some(def) {
                     *force_result = true;
-                    result = Some(Representability::SelfRecursive(vec![span]));
+                    result = Some(Representability::SelfRecursive(vec![(sp, field_id)]));
                 }
 
                 if result == None {
@@ -161,16 +178,17 @@ fn are_inner_types_recursive<'tcx>(
                         result = Some(
                             match is_type_structurally_recursive(
                                 tcx,
-                                span,
                                 &mut nested_seen,
                                 shadow_seen,
                                 representable_cache,
                                 raw_adt_ty,
+                                sp,
+                                field_id,
                                 force_result,
                             ) {
                                 Representability::SelfRecursive(_) => {
                                     if *force_result {
-                                        Representability::SelfRecursive(vec![span])
+                                        Representability::SelfRecursive(vec![(sp, field_id)])
                                     } else {
                                         Representability::ContainsRecursive
                                     }
@@ -208,15 +226,16 @@ fn are_inner_types_recursive<'tcx>(
                         result = Some(
                             match is_type_structurally_recursive(
                                 tcx,
-                                span,
                                 seen,
                                 shadow_seen,
                                 representable_cache,
                                 ty,
+                                sp,
+                                field_id,
                                 force_result,
                             ) {
                                 Representability::SelfRecursive(_) => {
-                                    Representability::SelfRecursive(vec![span])
+                                    Representability::SelfRecursive(vec![(sp, field_id)])
                                 }
                                 x => x,
                             },
@@ -247,29 +266,31 @@ fn same_adt<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
 // contain any types on stack `seen`?
 fn is_type_structurally_recursive<'tcx>(
     tcx: TyCtxt<'tcx>,
-    sp: Span,
     seen: &mut Vec<Ty<'tcx>>,
     shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
     ty: Ty<'tcx>,
+    sp: Span,
+    field_id: Option<hir::HirId>,
     force_result: &mut bool,
 ) -> Representability {
-    debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
+    debug!("is_type_structurally_recursive: {:?} {:?} {:?}", ty, sp, field_id);
     if let Some(representability) = representable_cache.get(&ty) {
         debug!(
-            "is_type_structurally_recursive: {:?} {:?} - (cached) {:?}",
-            ty, sp, representability
+            "is_type_structurally_recursive: {:?} {:?} {:?} - (cached) {:?}",
+            ty, sp, field_id, representability
         );
         return representability.clone();
     }
 
     let representability = is_type_structurally_recursive_inner(
         tcx,
-        sp,
         seen,
         shadow_seen,
         representable_cache,
         ty,
+        sp,
+        field_id,
         force_result,
     );
 
@@ -279,11 +300,12 @@ fn is_type_structurally_recursive<'tcx>(
 
 fn is_type_structurally_recursive_inner<'tcx>(
     tcx: TyCtxt<'tcx>,
-    sp: Span,
     seen: &mut Vec<Ty<'tcx>>,
     shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
     ty: Ty<'tcx>,
+    sp: Span,
+    field_id: Option<hir::HirId>,
     force_result: &mut bool,
 ) -> Representability {
     match ty.kind() {
@@ -305,7 +327,7 @@ fn is_type_structurally_recursive_inner<'tcx>(
                 if let Some(&seen_adt) = iter.next() {
                     if same_adt(seen_adt, *def) {
                         debug!("SelfRecursive: {:?} contains {:?}", seen_adt, ty);
-                        return Representability::SelfRecursive(vec![sp]);
+                        return Representability::SelfRecursive(vec![(sp, field_id)]);
                     }
                 }
 
@@ -335,11 +357,12 @@ fn is_type_structurally_recursive_inner<'tcx>(
             shadow_seen.push(*def);
             let out = are_inner_types_recursive(
                 tcx,
-                sp,
                 seen,
                 shadow_seen,
                 representable_cache,
                 ty,
+                sp,
+                field_id,
                 force_result,
             );
             shadow_seen.pop();
@@ -350,11 +373,12 @@ fn is_type_structurally_recursive_inner<'tcx>(
             // No need to push in other cases.
             are_inner_types_recursive(
                 tcx,
-                sp,
                 seen,
                 shadow_seen,
                 representable_cache,
                 ty,
+                sp,
+                field_id,
                 force_result,
             )
         }
diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs
index 5362ca8d71978..7cb478d78880a 100644
--- a/compiler/rustc_typeck/src/check/check.rs
+++ b/compiler/rustc_typeck/src/check/check.rs
@@ -1045,7 +1045,7 @@ pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalD
     // recursive type. It is only necessary to throw an error on those that
     // contain themselves. For case 2, there must be an inner type that will be
     // caught by case 1.
-    match representability::ty_is_representable(tcx, rty, sp) {
+    match representability::ty_is_representable(tcx, rty, sp, None) {
         Representability::SelfRecursive(spans) => {
             recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
             return false;
diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs
index b775f24f8efd8..e7cfa3a7c1493 100644
--- a/compiler/rustc_typeck/src/check/inherited.rs
+++ b/compiler/rustc_typeck/src/check/inherited.rs
@@ -95,13 +95,6 @@ impl<'tcx> InheritedBuilder<'tcx> {
         let def_id = self.def_id;
         self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id)))
     }
-
-    /// WF-checking doesn't need to recompute opaque types and can instead use
-    /// the type_of query to get them from typeck.
-    pub fn reveal_defining_opaque_types(mut self) -> Self {
-        self.infcx = self.infcx.reveal_defining_opaque_types();
-        self
-    }
 }
 
 impl<'a, 'tcx> Inherited<'a, 'tcx> {
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 5b3aee7428829..bd08da9529a5f 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -968,7 +968,7 @@ fn for_item<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'_>) -> CheckWfFcxBuilder<
 
 fn for_id(tcx: TyCtxt<'_>, def_id: LocalDefId, span: Span) -> CheckWfFcxBuilder<'_> {
     CheckWfFcxBuilder {
-        inherited: Inherited::build(tcx, def_id).reveal_defining_opaque_types(),
+        inherited: Inherited::build(tcx, def_id),
         id: hir::HirId::make_owner(def_id),
         span,
         param_env: tcx.param_env(def_id),
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 6a7841d3de6af..68d80022b4c80 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -84,7 +84,7 @@
 //! have to change, and is it worse or better now? Would any patterns become truly inexpressible?
 //! Could we carve out special exceptions for those patterns? Should we?
 //!
-//! A secondary goal of this project is to see if we can disamiguate the many functions of
+//! A secondary goal of this project is to see if we can disambiguate the many functions of
 //! pointer<->integer casts enough for the definition of `usize` to be loosened so that it
 //! isn't *pointer*-sized but address-space/offset/allocation-sized (we'll probably continue
 //! to conflate these notions). This would potentially make it possible to more efficiently
@@ -163,7 +163,7 @@
 //! of pointers and `usize` (and `isize`), and defining a pointer to semantically contain the
 //! following information:
 //!
-//! * The **address-space** it is part of (i.e. "data" vs "code" in WASM).
+//! * The **address-space** it is part of (e.g. "data" vs "code" in WASM).
 //! * The **address** it points to, which can be represented by a `usize`.
 //! * The **provenance** it has, defining the memory it has permission to access.
 //!
@@ -246,7 +246,7 @@
 //! be using AtomicPtr instead. If that messes up the way you atomically manipulate pointers,
 //! we would like to know why, and what needs to be done to fix it.)
 //!
-//! Something more complicated and just generally *evil* like a XOR-List requires more significant
+//! Something more complicated and just generally *evil* like an XOR-List requires more significant
 //! changes like allocating all nodes in a pre-allocated Vec or Arena and using a pointer
 //! to the whole allocation to reconstitute the XORed addresses.
 //!
@@ -257,7 +257,7 @@
 //! special attention at all, because they're generally accessing memory outside the scope of
 //! "the abstract machine", or already using "I know what I'm doing" annotations like "volatile".
 //!
-//! Under [Strict Provenance] is is Undefined Behaviour to:
+//! Under [Strict Provenance] it is Undefined Behaviour to:
 //!
 //! * Access memory through a pointer that does not have provenance over that memory.
 //!
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index a9edec80540dd..c11a35ab947a8 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -65,9 +65,10 @@
 //! For reference, the `std` library requires `AtomicBool`s and pointer-sized atomics, although
 //! `core` does not.
 //!
-//! Currently you'll need to use `#[cfg(target_arch)]` primarily to
-//! conditionally compile in code with atomics. There is an unstable
-//! `#[cfg(target_has_atomic)]` as well which may be stabilized in the future.
+//! The `#[cfg(target_has_atomic)]` attribute can be used to conditionally
+//! compile based on the target's supported bit widths. It is a key-value
+//! option set for each supported size, with values "8", "16", "32", "64",
+//! "128", and "ptr" for pointer-sized atomics.
 //!
 //! [lock-free]: https://en.wikipedia.org/wiki/Non-blocking_algorithm
 //!
diff --git a/src/test/ui/issues/issue-17431-1.stderr b/src/test/ui/issues/issue-17431-1.stderr
index 4d739a3823b10..db32eb952ba79 100644
--- a/src/test/ui/issues/issue-17431-1.stderr
+++ b/src/test/ui/issues/issue-17431-1.stderr
@@ -8,8 +8,8 @@ LL | struct Foo { foo: Option<Option<Foo>> }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-LL | struct Foo { foo: Box<Option<Option<Foo>>> }
-   |                   ++++                   +
+LL | struct Foo { foo: Option<Box<Option<Foo>>> }
+   |                          ++++           +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17431-2.stderr b/src/test/ui/issues/issue-17431-2.stderr
index e53134c5238c6..d23fd1474ac12 100644
--- a/src/test/ui/issues/issue-17431-2.stderr
+++ b/src/test/ui/issues/issue-17431-2.stderr
@@ -8,8 +8,8 @@ LL | struct Baz { q: Option<Foo> }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
    |
-LL | struct Baz { q: Box<Option<Foo>> }
-   |                 ++++           +
+LL | struct Baz { q: Option<Box<Foo>> }
+   |                        ++++   +
 
 error[E0072]: recursive type `Foo` has infinite size
   --> $DIR/issue-17431-2.rs:4:1
@@ -21,8 +21,8 @@ LL | struct Foo { q: Option<Baz> }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-LL | struct Foo { q: Box<Option<Baz>> }
-   |                 ++++           +
+LL | struct Foo { q: Option<Box<Baz>> }
+   |                        ++++   +
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-17431-4.stderr b/src/test/ui/issues/issue-17431-4.stderr
index f5aeeec733711..ddf669b8fd1cb 100644
--- a/src/test/ui/issues/issue-17431-4.stderr
+++ b/src/test/ui/issues/issue-17431-4.stderr
@@ -8,8 +8,8 @@ LL | struct Foo<T> { foo: Option<Option<Foo<T>>>, marker: marker::PhantomData<T>
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-LL | struct Foo<T> { foo: Box<Option<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
-   |                      ++++                      +
+LL | struct Foo<T> { foo: Option<Box<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
+   |                             ++++              +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17431-7.stderr b/src/test/ui/issues/issue-17431-7.stderr
index aeaadaa69175e..6f8a7e3867b09 100644
--- a/src/test/ui/issues/issue-17431-7.stderr
+++ b/src/test/ui/issues/issue-17431-7.stderr
@@ -8,8 +8,8 @@ LL | enum Foo { Voo(Option<Option<Foo>>) }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-LL | enum Foo { Voo(Box<Option<Option<Foo>>>) }
-   |                ++++                   +
+LL | enum Foo { Voo(Option<Box<Option<Foo>>>) }
+   |                       ++++           +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-3779.stderr b/src/test/ui/issues/issue-3779.stderr
index 6a21472848a74..e853d0f8c8932 100644
--- a/src/test/ui/issues/issue-3779.stderr
+++ b/src/test/ui/issues/issue-3779.stderr
@@ -9,8 +9,8 @@ LL |     element: Option<S>
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `S` representable
    |
-LL |     element: Box<Option<S>>
-   |              ++++         +
+LL |     element: Option<Box<S>>
+   |                     ++++ +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/sized-cycle-note.stderr b/src/test/ui/sized-cycle-note.stderr
index 0726b16a91948..536510814c57c 100644
--- a/src/test/ui/sized-cycle-note.stderr
+++ b/src/test/ui/sized-cycle-note.stderr
@@ -8,8 +8,8 @@ LL | struct Baz { q: Option<Foo> }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
    |
-LL | struct Baz { q: Box<Option<Foo>> }
-   |                 ++++           +
+LL | struct Baz { q: Option<Box<Foo>> }
+   |                        ++++   +
 
 error[E0072]: recursive type `Foo` has infinite size
   --> $DIR/sized-cycle-note.rs:11:1
@@ -21,8 +21,8 @@ LL | struct Foo { q: Option<Baz> }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
    |
-LL | struct Foo { q: Box<Option<Baz>> }
-   |                 ++++           +
+LL | struct Foo { q: Option<Box<Baz>> }
+   |                        ++++   +
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/span/E0072.stderr b/src/test/ui/span/E0072.stderr
index 98e92751360cf..882ed577cf366 100644
--- a/src/test/ui/span/E0072.stderr
+++ b/src/test/ui/span/E0072.stderr
@@ -9,8 +9,8 @@ LL |     tail: Option<ListNode>,
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
    |
-LL |     tail: Box<Option<ListNode>>,
-   |           ++++                +
+LL |     tail: Option<Box<ListNode>>,
+   |                  ++++        +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr
index cb71a55b09eaf..acfc60b51f330 100644
--- a/src/test/ui/span/multiline-span-E0072.stderr
+++ b/src/test/ui/span/multiline-span-E0072.stderr
@@ -12,8 +12,8 @@ LL | | }
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
    |
-LL |     tail: Box<Option<ListNode>>,
-   |           ++++                +
+LL |     tail: Option<Box<ListNode>>,
+   |                  ++++        +
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr
index c6d2434e424b1..80a494f3f65eb 100644
--- a/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr
+++ b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr
@@ -37,8 +37,8 @@ LL |     y: Option<Option<D<T>>>,
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `C` representable
    |
-LL |     y: Box<Option<Option<D<T>>>>,
-   |        ++++                    +
+LL |     y: Option<Box<Option<D<T>>>>,
+   |               ++++            +
 
 error[E0072]: recursive type `D` has infinite size
   --> $DIR/mutual-struct-recursion.rs:18:1
@@ -51,8 +51,8 @@ LL |     z: Option<Option<C<T>>>,
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `D` representable
    |
-LL |     z: Box<Option<Option<C<T>>>>,
-   |        ++++                    +
+LL |     z: Option<Box<Option<C<T>>>>,
+   |               ++++            +
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/type/type-recursive-box-shadowed.rs b/src/test/ui/type/type-recursive-box-shadowed.rs
new file mode 100644
index 0000000000000..e141c2149ffea
--- /dev/null
+++ b/src/test/ui/type/type-recursive-box-shadowed.rs
@@ -0,0 +1,12 @@
+//FIXME(compiler-errors): This fixup should suggest the full box path, not just `Box`
+
+struct Box<T> {
+    t: T,
+}
+
+struct Foo {
+    //~^ ERROR recursive type `Foo` has infinite size
+    inner: Foo,
+}
+
+fn main() {}
diff --git a/src/test/ui/type/type-recursive-box-shadowed.stderr b/src/test/ui/type/type-recursive-box-shadowed.stderr
new file mode 100644
index 0000000000000..c22d848f3797e
--- /dev/null
+++ b/src/test/ui/type/type-recursive-box-shadowed.stderr
@@ -0,0 +1,17 @@
+error[E0072]: recursive type `Foo` has infinite size
+  --> $DIR/type-recursive-box-shadowed.rs:7:1
+   |
+LL | struct Foo {
+   | ^^^^^^^^^^ recursive type has infinite size
+LL |
+LL |     inner: Foo,
+   |            --- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
+   |
+LL |     inner: Box<Foo>,
+   |            ++++   +
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0072`.
diff --git a/src/test/ui/type/type-recursive.rs b/src/test/ui/type/type-recursive.rs
index 8558f761ee8f5..e8084f0d0826a 100644
--- a/src/test/ui/type/type-recursive.rs
+++ b/src/test/ui/type/type-recursive.rs
@@ -1,6 +1,30 @@
 struct T1 { //~ ERROR E0072
     foo: isize,
-    foolish: T1
+    foolish: T1,
+}
+
+struct T2 { //~ ERROR E0072
+    inner: Option<T2>,
+}
+
+type OptionT3 = Option<T3>;
+
+struct T3 { //~ ERROR E0072
+    inner: OptionT3,
+}
+
+struct T4(Option<T4>); //~ ERROR E0072
+
+enum T5 { //~ ERROR E0072
+    Variant(Option<T5>),
+}
+
+enum T6 { //~ ERROR E0072
+    Variant{ field: Option<T6> },
+}
+
+struct T7 { //~ ERROR E0072
+    foo: std::cell::Cell<Option<T7>>,
 }
 
 fn main() { }
diff --git a/src/test/ui/type/type-recursive.stderr b/src/test/ui/type/type-recursive.stderr
index 5a94a0fd6831a..04392f7390dfc 100644
--- a/src/test/ui/type/type-recursive.stderr
+++ b/src/test/ui/type/type-recursive.stderr
@@ -4,14 +4,93 @@ error[E0072]: recursive type `T1` has infinite size
 LL | struct T1 {
    | ^^^^^^^^^ recursive type has infinite size
 LL |     foo: isize,
-LL |     foolish: T1
+LL |     foolish: T1,
    |              -- recursive without indirection
    |
 help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T1` representable
    |
-LL |     foolish: Box<T1>
+LL |     foolish: Box<T1>,
    |              ++++  +
 
-error: aborting due to previous error
+error[E0072]: recursive type `T2` has infinite size
+  --> $DIR/type-recursive.rs:6:1
+   |
+LL | struct T2 {
+   | ^^^^^^^^^ recursive type has infinite size
+LL |     inner: Option<T2>,
+   |            ---------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T2` representable
+   |
+LL |     inner: Option<Box<T2>>,
+   |                   ++++  +
+
+error[E0072]: recursive type `T3` has infinite size
+  --> $DIR/type-recursive.rs:12:1
+   |
+LL | struct T3 {
+   | ^^^^^^^^^ recursive type has infinite size
+LL |     inner: OptionT3,
+   |            -------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T3` representable
+   |
+LL |     inner: Box<OptionT3>,
+   |            ++++        +
+
+error[E0072]: recursive type `T4` has infinite size
+  --> $DIR/type-recursive.rs:16:1
+   |
+LL | struct T4(Option<T4>);
+   | ^^^^^^^^^^----------^^
+   | |         |
+   | |         recursive without indirection
+   | recursive type has infinite size
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T4` representable
+   |
+LL | struct T4(Option<Box<T4>>);
+   |                  ++++  +
+
+error[E0072]: recursive type `T5` has infinite size
+  --> $DIR/type-recursive.rs:18:1
+   |
+LL | enum T5 {
+   | ^^^^^^^ recursive type has infinite size
+LL |     Variant(Option<T5>),
+   |             ---------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T5` representable
+   |
+LL |     Variant(Option<Box<T5>>),
+   |                    ++++  +
+
+error[E0072]: recursive type `T6` has infinite size
+  --> $DIR/type-recursive.rs:22:1
+   |
+LL | enum T6 {
+   | ^^^^^^^ recursive type has infinite size
+LL |     Variant{ field: Option<T6> },
+   |                     ---------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T6` representable
+   |
+LL |     Variant{ field: Option<Box<T6>> },
+   |                            ++++  +
+
+error[E0072]: recursive type `T7` has infinite size
+  --> $DIR/type-recursive.rs:26:1
+   |
+LL | struct T7 {
+   | ^^^^^^^^^ recursive type has infinite size
+LL |     foo: std::cell::Cell<Option<T7>>,
+   |          --------------------------- recursive without indirection
+   |
+help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T7` representable
+   |
+LL |     foo: Box<std::cell::Cell<Option<T7>>>,
+   |          ++++                           +
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0072`.