From 3019c1cb2a6e3f599fd0d71a7ddc5f2f8b46385c Mon Sep 17 00:00:00 2001
From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com>
Date: Sun, 30 Apr 2023 23:05:27 +0200
Subject: [PATCH 1/2] Put `LayoutError` behind reference to shrink result

`LayoutError` is 24 bytes, which is bigger than the `Ok` types, so let's
shrink that.
---
 .../src/interpret/intrinsics.rs               |  2 +-
 .../src/util/check_validity_requirement.rs    |  6 +-
 compiler/rustc_hir_typeck/src/intrinsicck.rs  |  4 +-
 compiler/rustc_middle/src/query/erase.rs      | 10 +--
 compiler/rustc_middle/src/query/mod.rs        |  4 +-
 compiler/rustc_middle/src/ty/layout.rs        | 32 +++++----
 compiler/rustc_middle/src/values.rs           |  7 +-
 compiler/rustc_passes/src/layout_test.rs      |  1 +
 compiler/rustc_transmute/src/layout/tree.rs   |  8 +--
 compiler/rustc_ty_utils/src/abi.rs            |  2 +-
 compiler/rustc_ty_utils/src/layout.rs         | 65 ++++++++++++-------
 src/librustdoc/html/render/type_layout.rs     |  2 +-
 src/tools/miri/src/machine.rs                 |  2 +-
 13 files changed, 89 insertions(+), 56 deletions(-)

diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 8f4cf23770e..4f10e4837ce 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -72,7 +72,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
         }
         sym::pref_align_of => {
             // Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
-            let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(e)))?;
+            let layout = tcx.layout_of(param_env.and(tp_ty)).map_err(|e| err_inval!(Layout(*e)))?;
             ConstValue::from_target_usize(layout.align.pref.bytes(), &tcx)
         }
         sym::type_id => {
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index f56798d4c32..2d1970791ca 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -21,7 +21,7 @@ pub fn check_validity_requirement<'tcx>(
     tcx: TyCtxt<'tcx>,
     kind: ValidityRequirement,
     param_env_and_ty: ParamEnvAnd<'tcx, Ty<'tcx>>,
-) -> Result<bool, LayoutError<'tcx>> {
+) -> Result<bool, &'tcx LayoutError<'tcx>> {
     let layout = tcx.layout_of(param_env_and_ty)?;
 
     // There is nothing strict or lax about inhabitedness.
@@ -43,7 +43,7 @@ fn might_permit_raw_init_strict<'tcx>(
     ty: TyAndLayout<'tcx>,
     tcx: TyCtxt<'tcx>,
     kind: ValidityRequirement,
-) -> Result<bool, LayoutError<'tcx>> {
+) -> Result<bool, &'tcx LayoutError<'tcx>> {
     let machine = CompileTimeInterpreter::new(CanAccessStatics::No, CheckAlignment::Error);
 
     let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine);
@@ -75,7 +75,7 @@ fn might_permit_raw_init_lax<'tcx>(
     this: TyAndLayout<'tcx>,
     cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
     init_kind: ValidityRequirement,
-) -> Result<bool, LayoutError<'tcx>> {
+) -> Result<bool, &'tcx LayoutError<'tcx>> {
     let scalar_allows_raw_init = move |s: Scalar| -> bool {
         match init_kind {
             ValidityRequirement::Inhabited => {
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 362c07431e0..e58efc9d1e3 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -81,7 +81,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         // Try to display a sensible error with as much information as possible.
-        let skeleton_string = |ty: Ty<'tcx>, sk| match sk {
+        let skeleton_string = |ty: Ty<'tcx>, sk: Result<_, &_>| match sk {
             Ok(SizeSkeleton::Pointer { tail, .. }) => format!("pointer to `{tail}`"),
             Ok(SizeSkeleton::Known(size)) => {
                 if let Some(v) = u128::from(size.bytes()).checked_mul(8) {
@@ -101,7 +101,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 }
             }
             Err(LayoutError::Unknown(bad)) => {
-                if bad == ty {
+                if *bad == ty {
                     "this type does not have a fixed size".to_owned()
                 } else {
                     format!("size can vary because of {bad}")
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index f1ae4942b7b..9b9daac2392 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -96,15 +96,17 @@ impl EraseType for Result<ty::GenericArg<'_>, traits::query::NoSolution> {
     type Result = [u8; size_of::<Result<ty::GenericArg<'static>, traits::query::NoSolution>>()];
 }
 
-impl EraseType for Result<bool, ty::layout::LayoutError<'_>> {
-    type Result = [u8; size_of::<Result<bool, ty::layout::LayoutError<'static>>>()];
+impl EraseType for Result<bool, &ty::layout::LayoutError<'_>> {
+    type Result = [u8; size_of::<Result<bool, &'static ty::layout::LayoutError<'static>>>()];
 }
 
-impl EraseType for Result<rustc_target::abi::TyAndLayout<'_, Ty<'_>>, ty::layout::LayoutError<'_>> {
+impl EraseType
+    for Result<rustc_target::abi::TyAndLayout<'_, Ty<'_>>, &ty::layout::LayoutError<'_>>
+{
     type Result = [u8; size_of::<
         Result<
             rustc_target::abi::TyAndLayout<'static, Ty<'static>>,
-            ty::layout::LayoutError<'static>,
+            &'static ty::layout::LayoutError<'static>,
         >,
     >()];
 }
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 15215552f52..48b8de2ab52 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1383,7 +1383,7 @@ rustc_queries! {
     /// executes in "reveal all" mode, and will normalize the input type.
     query layout_of(
         key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
-    ) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> {
+    ) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> {
         depth_limit
         desc { "computing layout of `{}`", key.value }
     }
@@ -2164,7 +2164,7 @@ rustc_queries! {
         separate_provide_extern
     }
 
-    query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, ty::layout::LayoutError<'tcx>> {
+    query check_validity_requirement(key: (ValidityRequirement, ty::ParamEnvAnd<'tcx, Ty<'tcx>>)) -> Result<bool, &'tcx ty::layout::LayoutError<'tcx>> {
         desc { "checking validity requirement for `{}`: {}", key.1.value, key.0 }
     }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index c1d6856d33c..46d6e0c1531 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -310,7 +310,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
         ty: Ty<'tcx>,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-    ) -> Result<SizeSkeleton<'tcx>, LayoutError<'tcx>> {
+    ) -> Result<SizeSkeleton<'tcx>, &'tcx LayoutError<'tcx>> {
         debug_assert!(!ty.has_non_region_infer());
 
         // First try computing a static layout.
@@ -353,13 +353,13 @@ impl<'tcx> SizeSkeleton<'tcx> {
                             let size = s
                                 .bytes()
                                 .checked_mul(c)
-                                .ok_or_else(|| LayoutError::SizeOverflow(ty))?;
+                                .ok_or_else(|| &*tcx.arena.alloc(LayoutError::SizeOverflow(ty)))?;
                             return Ok(SizeSkeleton::Known(Size::from_bytes(size)));
                         }
                         let len = tcx.expand_abstract_consts(len);
                         let prev = ty::Const::from_target_usize(tcx, s.bytes());
                         let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, prev) else {
-                            return Err(LayoutError::SizeOverflow(ty));
+                            return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty)));
                         };
                         Ok(SizeSkeleton::Generic(gen_size))
                     }
@@ -367,7 +367,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
                     SizeSkeleton::Generic(g) => {
                         let len = tcx.expand_abstract_consts(len);
                         let Some(gen_size) = mul_sorted_consts(tcx, param_env, len, g) else {
-                            return Err(LayoutError::SizeOverflow(ty));
+                            return Err(tcx.arena.alloc(LayoutError::SizeOverflow(ty)));
                         };
                         Ok(SizeSkeleton::Generic(gen_size))
                     }
@@ -672,7 +672,7 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
 
         MaybeResult::from(
             tcx.layout_of(self.param_env().and(ty))
-                .map_err(|err| self.handle_layout_err(err, span, ty)),
+                .map_err(|err| self.handle_layout_err(*err, span, ty)),
         )
     }
 }
@@ -680,16 +680,21 @@ pub trait LayoutOf<'tcx>: LayoutOfHelpers<'tcx> {
 impl<'tcx, C: LayoutOfHelpers<'tcx>> LayoutOf<'tcx> for C {}
 
 impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
-    type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+    type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
 
     #[inline]
-    fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
-        err
+    fn handle_layout_err(
+        &self,
+        err: LayoutError<'tcx>,
+        _: Span,
+        _: Ty<'tcx>,
+    ) -> &'tcx LayoutError<'tcx> {
+        self.tcx.arena.alloc(err)
     }
 }
 
 impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> {
-    type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
+    type LayoutOfResult = Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>>;
 
     #[inline]
     fn layout_tcx_at_span(&self) -> Span {
@@ -697,8 +702,13 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> {
     }
 
     #[inline]
-    fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
-        err
+    fn handle_layout_err(
+        &self,
+        err: LayoutError<'tcx>,
+        _: Span,
+        _: Ty<'tcx>,
+    ) -> &'tcx LayoutError<'tcx> {
+        self.tcx.arena.alloc(err)
     }
 }
 
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index a00c77ccbcd..8758cd04d67 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -106,9 +106,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::F
     }
 }
 
-impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, ty::layout::LayoutError<'_>> {
+impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> {
     fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self {
-        Err(ty::layout::LayoutError::Cycle)
+        // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
+        // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,
+        // tcx.arena.alloc is pretty much equal to leaking).
+        Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle)))
     }
 }
 
diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs
index 9971bdf45bb..098107f8f23 100644
--- a/compiler/rustc_passes/src/layout_test.rs
+++ b/compiler/rustc_passes/src/layout_test.rs
@@ -94,6 +94,7 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
         Err(layout_error) => {
             tcx.sess.emit_fatal(Spanned {
                 node: layout_error.into_diagnostic(),
+
                 span: tcx.def_span(item_def_id.to_def_id()),
             });
         }
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 6b718be7b15..be434eb7d00 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -192,8 +192,8 @@ pub(crate) mod rustc {
         TypeError(ErrorGuaranteed),
     }
 
-    impl<'tcx> From<LayoutError<'tcx>> for Err {
-        fn from(err: LayoutError<'tcx>) -> Self {
+    impl<'tcx> From<&LayoutError<'tcx>> for Err {
+        fn from(err: &LayoutError<'tcx>) -> Self {
             match err {
                 LayoutError::Unknown(..) => Self::UnknownLayout,
                 err => unimplemented!("{:?}", err),
@@ -221,7 +221,7 @@ pub(crate) mod rustc {
     }
 
     impl LayoutSummary {
-        fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result<Self, LayoutError<'tcx>> {
+        fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result<Self, &'tcx LayoutError<'tcx>> {
             use rustc_middle::ty::ParamEnvAnd;
             use rustc_target::abi::{TyAndLayout, Variants};
 
@@ -482,7 +482,7 @@ pub(crate) mod rustc {
     fn layout_of<'tcx>(
         ctx: TyCtxt<'tcx>,
         ty: Ty<'tcx>,
-    ) -> Result<alloc::Layout, LayoutError<'tcx>> {
+    ) -> Result<alloc::Layout, &'tcx LayoutError<'tcx>> {
         use rustc_middle::ty::ParamEnvAnd;
         use rustc_target::abi::TyAndLayout;
 
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 5b3ffc9fc36..9cb9c8833f7 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -386,7 +386,7 @@ fn fn_abi_new_uncached<'tcx>(
             _ => bug!("argument to drop_in_place is not a raw ptr: {:?}", ty),
         });
 
-        let layout = cx.layout_of(ty)?;
+        let layout = cx.layout_of(ty).map_err(|err| *err)?;
         let layout = if force_thin_self_ptr && arg_idx == Some(0) {
             // Don't pass the vtable, it's not an argument of the virtual fn.
             // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index c8c2c8286b0..ac015ddcb49 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -31,7 +31,7 @@ pub fn provide(providers: &mut Providers) {
 fn layout_of<'tcx>(
     tcx: TyCtxt<'tcx>,
     query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
-) -> Result<TyAndLayout<'tcx>, LayoutError<'tcx>> {
+) -> Result<TyAndLayout<'tcx>, &'tcx LayoutError<'tcx>> {
     let (param_env, ty) = query.into_parts();
     debug!(?ty);
 
@@ -45,7 +45,9 @@ fn layout_of<'tcx>(
     let ty = match tcx.try_normalize_erasing_regions(param_env, ty) {
         Ok(t) => t,
         Err(normalization_error) => {
-            return Err(LayoutError::NormalizationFailure(ty, normalization_error));
+            return Err(tcx
+                .arena
+                .alloc(LayoutError::NormalizationFailure(ty, normalization_error)));
         }
     };
 
@@ -66,27 +68,34 @@ fn layout_of<'tcx>(
     Ok(layout)
 }
 
+fn error<'tcx>(
+    cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
+    err: LayoutError<'tcx>,
+) -> &'tcx LayoutError<'tcx> {
+    cx.tcx.arena.alloc(err)
+}
+
 fn univariant_uninterned<'tcx>(
     cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
     ty: Ty<'tcx>,
     fields: &IndexSlice<FieldIdx, Layout<'_>>,
     repr: &ReprOptions,
     kind: StructKind,
-) -> Result<LayoutS, LayoutError<'tcx>> {
+) -> Result<LayoutS, &'tcx LayoutError<'tcx>> {
     let dl = cx.data_layout();
     let pack = repr.pack;
     if pack.is_some() && repr.align.is_some() {
         cx.tcx.sess.delay_span_bug(DUMMY_SP, "struct cannot be packed and aligned");
-        return Err(LayoutError::Unknown(ty));
+        return Err(cx.tcx.arena.alloc(LayoutError::Unknown(ty)));
     }
 
-    cx.univariant(dl, fields, repr, kind).ok_or(LayoutError::SizeOverflow(ty))
+    cx.univariant(dl, fields, repr, kind).ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))
 }
 
 fn layout_of_uncached<'tcx>(
     cx: &LayoutCx<'tcx, TyCtxt<'tcx>>,
     ty: Ty<'tcx>,
-) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
+) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
     let tcx = cx.tcx;
     let param_env = cx.param_env;
     let dl = cx.data_layout();
@@ -170,7 +179,7 @@ fn layout_of_uncached<'tcx>(
                                 err = better_err;
                             }
                         }
-                        return Err(LayoutError::NormalizationFailure(pointee, err));
+                        return Err(error(cx, LayoutError::NormalizationFailure(pointee, err)));
                     },
                 };
 
@@ -181,7 +190,7 @@ fn layout_of_uncached<'tcx>(
                 }
 
                 let Abi::Scalar(metadata) = metadata_layout.abi else {
-                    return Err(LayoutError::Unknown(pointee));
+                    return Err(error(cx, LayoutError::Unknown(pointee)));
                 };
 
                 metadata
@@ -199,7 +208,7 @@ fn layout_of_uncached<'tcx>(
                         vtable
                     }
                     _ => {
-                        return Err(LayoutError::Unknown(pointee));
+                        return Err(error(cx, LayoutError::Unknown(pointee)));
                     }
                 }
             };
@@ -221,14 +230,18 @@ fn layout_of_uncached<'tcx>(
             if count.has_projections() {
                 count = tcx.normalize_erasing_regions(param_env, count);
                 if count.has_projections() {
-                    return Err(LayoutError::Unknown(ty));
+                    return Err(error(cx, LayoutError::Unknown(ty)));
                 }
             }
 
-            let count =
-                count.try_eval_target_usize(tcx, param_env).ok_or(LayoutError::Unknown(ty))?;
+            let count = count
+                .try_eval_target_usize(tcx, param_env)
+                .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?;
             let element = cx.layout_of(element)?;
-            let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow(ty))?;
+            let size = element
+                .size
+                .checked_mul(count, dl)
+                .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
 
             let abi = if count != 0 && ty.is_privately_uninhabited(tcx, param_env) {
                 Abi::Uninhabited
@@ -316,7 +329,7 @@ fn layout_of_uncached<'tcx>(
                     DUMMY_SP,
                     "#[repr(simd)] was applied to an ADT that is not a struct",
                 );
-                return Err(LayoutError::Unknown(ty));
+                return Err(error(cx, LayoutError::Unknown(ty)));
             }
 
             let fields = &def.non_enum_variant().fields;
@@ -346,7 +359,7 @@ fn layout_of_uncached<'tcx>(
                         DUMMY_SP,
                         "#[repr(simd)] was applied to an ADT with heterogeneous field type",
                     );
-                    return Err(LayoutError::Unknown(ty));
+                    return Err(error(cx, LayoutError::Unknown(ty)));
                 }
             }
 
@@ -368,7 +381,7 @@ fn layout_of_uncached<'tcx>(
 
                 // Extract the number of elements from the layout of the array field:
                 let FieldsShape::Array { count, .. } = cx.layout_of(f0_ty)?.layout.fields() else {
-                    return Err(LayoutError::Unknown(ty));
+                    return Err(error(cx, LayoutError::Unknown(ty)));
                 };
 
                 (*e_ty, *count, true)
@@ -397,7 +410,10 @@ fn layout_of_uncached<'tcx>(
             };
 
             // Compute the size and alignment of the vector:
-            let size = e_ly.size.checked_mul(e_len, dl).ok_or(LayoutError::SizeOverflow(ty))?;
+            let size = e_ly
+                .size
+                .checked_mul(e_len, dl)
+                .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?;
             let align = dl.vector_align(size);
             let size = size.align_to(align.abi);
 
@@ -438,11 +454,12 @@ fn layout_of_uncached<'tcx>(
                         tcx.def_span(def.did()),
                         "union cannot be packed and aligned",
                     );
-                    return Err(LayoutError::Unknown(ty));
+                    return Err(error(cx, LayoutError::Unknown(ty)));
                 }
 
                 return Ok(tcx.mk_layout(
-                    cx.layout_of_union(&def.repr(), &variants).ok_or(LayoutError::Unknown(ty))?,
+                    cx.layout_of_union(&def.repr(), &variants)
+                        .ok_or_else(|| error(cx, LayoutError::Unknown(ty)))?,
                 ));
             }
 
@@ -476,7 +493,7 @@ fn layout_of_uncached<'tcx>(
                             }
                     },
                 )
-                .ok_or(LayoutError::SizeOverflow(ty))?,
+                .ok_or_else(|| error(cx, LayoutError::SizeOverflow(ty)))?,
             )
         }
 
@@ -484,7 +501,7 @@ fn layout_of_uncached<'tcx>(
         ty::Alias(..) => {
             // NOTE(eddyb) `layout_of` query should've normalized these away,
             // if that was possible, so there's no reason to try again here.
-            return Err(LayoutError::Unknown(ty));
+            return Err(error(cx, LayoutError::Unknown(ty)));
         }
 
         ty::Bound(..) | ty::GeneratorWitness(..) | ty::GeneratorWitnessMIR(..) | ty::Infer(_) => {
@@ -492,7 +509,7 @@ fn layout_of_uncached<'tcx>(
         }
 
         ty::Placeholder(..) | ty::Param(_) | ty::Error(_) => {
-            return Err(LayoutError::Unknown(ty));
+            return Err(error(cx, LayoutError::Unknown(ty)));
         }
     })
 }
@@ -628,13 +645,13 @@ fn generator_layout<'tcx>(
     ty: Ty<'tcx>,
     def_id: hir::def_id::DefId,
     substs: SubstsRef<'tcx>,
-) -> Result<Layout<'tcx>, LayoutError<'tcx>> {
+) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
     use SavedLocalEligibility::*;
     let tcx = cx.tcx;
     let subst_field = |ty: Ty<'tcx>| EarlyBinder::bind(ty).subst(tcx, substs);
 
     let Some(info) = tcx.generator_layout(def_id) else {
-        return Err(LayoutError::Unknown(ty));
+        return Err(error(cx, LayoutError::Unknown(ty)));
     };
     let (ineligible_locals, assignments) = generator_saved_local_eligibility(&info);
 
diff --git a/src/librustdoc/html/render/type_layout.rs b/src/librustdoc/html/render/type_layout.rs
index c9b95b1e645..0bc32ea5a20 100644
--- a/src/librustdoc/html/render/type_layout.rs
+++ b/src/librustdoc/html/render/type_layout.rs
@@ -17,7 +17,7 @@ use crate::html::render::Context;
 #[template(path = "type_layout.html")]
 struct TypeLayout<'cx> {
     variants: Vec<(Symbol, TypeLayoutSize)>,
-    type_layout_size: Result<TypeLayoutSize, LayoutError<'cx>>,
+    type_layout_size: Result<TypeLayoutSize, &'cx LayoutError<'cx>>,
 }
 
 #[derive(Template)]
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index f88ad040e05..bbe5bbee719 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -311,7 +311,7 @@ pub struct PrimitiveLayouts<'tcx> {
 }
 
 impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
-    fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, LayoutError<'tcx>> {
+    fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, &'tcx LayoutError<'tcx>> {
         let tcx = layout_cx.tcx;
         let mut_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut });
         let const_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not });

From 4be84771a7e0b66caa84dcf76121e7beeff08a1b Mon Sep 17 00:00:00 2001
From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com>
Date: Sun, 30 Apr 2023 23:14:53 +0200
Subject: [PATCH 2/2] Put `FnAbiError` behind reference to shrink result

The `FnAbi` is just a pointer, so the error type should not be bigger.
---
 compiler/rustc_middle/src/query/erase.rs |  4 ++--
 compiler/rustc_middle/src/query/mod.rs   |  4 ++--
 compiler/rustc_middle/src/ty/layout.rs   | 20 ++++++--------------
 compiler/rustc_ty_utils/src/abi.rs       | 17 ++++++++++-------
 4 files changed, 20 insertions(+), 25 deletions(-)

diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 9b9daac2392..e8f4fca147b 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -71,8 +71,8 @@ impl<T> EraseType for Result<&'_ T, traits::CodegenObligationError> {
     type Result = [u8; size_of::<Result<&'static (), traits::CodegenObligationError>>()];
 }
 
-impl<T> EraseType for Result<&'_ T, ty::layout::FnAbiError<'_>> {
-    type Result = [u8; size_of::<Result<&'static (), ty::layout::FnAbiError<'static>>>()];
+impl<T> EraseType for Result<&'_ T, &'_ ty::layout::FnAbiError<'_>> {
+    type Result = [u8; size_of::<Result<&'static (), &'static ty::layout::FnAbiError<'static>>>()];
 }
 
 impl<T> EraseType for Result<(&'_ T, rustc_middle::thir::ExprId), rustc_errors::ErrorGuaranteed> {
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 48b8de2ab52..c12587845e5 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1394,7 +1394,7 @@ rustc_queries! {
     /// instead, where the instance is an `InstanceDef::Virtual`.
     query fn_abi_of_fn_ptr(
         key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
-    ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
+    ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> {
         desc { "computing call ABI of `{}` function pointers", key.value.0 }
     }
 
@@ -1405,7 +1405,7 @@ rustc_queries! {
     /// to an `InstanceDef::Virtual` instance (of `<dyn Trait as Trait>::fn`).
     query fn_abi_of_instance(
         key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
-    ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
+    ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> {
         desc { "computing call ABI of `{}`", key.value.0 }
     }
 
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 46d6e0c1531..9485106e95e 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1260,18 +1260,6 @@ pub enum FnAbiError<'tcx> {
     AdjustForForeignAbi(call::AdjustForForeignAbiError),
 }
 
-impl<'tcx> From<LayoutError<'tcx>> for FnAbiError<'tcx> {
-    fn from(err: LayoutError<'tcx>) -> Self {
-        Self::Layout(err)
-    }
-}
-
-impl From<call::AdjustForForeignAbiError> for FnAbiError<'_> {
-    fn from(err: call::AdjustForForeignAbiError) -> Self {
-        Self::AdjustForForeignAbi(err)
-    }
-}
-
 impl<'a, 'b> IntoDiagnostic<'a, !> for FnAbiError<'b> {
     fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, !> {
         match self {
@@ -1331,7 +1319,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
         let tcx = self.tcx().at(span);
 
         MaybeResult::from(tcx.fn_abi_of_fn_ptr(self.param_env().and((sig, extra_args))).map_err(
-            |err| self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
+            |err| self.handle_fn_abi_err(*err, span, FnAbiRequest::OfFnPtr { sig, extra_args }),
         ))
     }
 
@@ -1358,7 +1346,11 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
                 // However, we don't do this early in order to avoid calling
                 // `def_span` unconditionally (which may have a perf penalty).
                 let span = if !span.is_dummy() { span } else { tcx.def_span(instance.def_id()) };
-                self.handle_fn_abi_err(err, span, FnAbiRequest::OfInstance { instance, extra_args })
+                self.handle_fn_abi_err(
+                    *err,
+                    span,
+                    FnAbiRequest::OfInstance { instance, extra_args },
+                )
             }),
         )
     }
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 9cb9c8833f7..8e2a79dd4d4 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -202,7 +202,7 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
 fn fn_abi_of_fn_ptr<'tcx>(
     tcx: TyCtxt<'tcx>,
     query: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
-) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
     let (param_env, (sig, extra_args)) = query.into_parts();
 
     let cx = LayoutCx { tcx, param_env };
@@ -212,7 +212,7 @@ fn fn_abi_of_fn_ptr<'tcx>(
 fn fn_abi_of_instance<'tcx>(
     tcx: TyCtxt<'tcx>,
     query: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>,
-) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
     let (param_env, (instance, extra_args)) = query.into_parts();
 
     let sig = fn_sig_for_fn_abi(tcx, instance, param_env);
@@ -331,7 +331,7 @@ fn fn_abi_new_uncached<'tcx>(
     fn_def_id: Option<DefId>,
     // FIXME(eddyb) replace this with something typed, like an `enum`.
     force_thin_self_ptr: bool,
-) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
+) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, &'tcx FnAbiError<'tcx>> {
     let sig = cx.tcx.normalize_erasing_late_bound_regions(cx.param_env, sig);
 
     let conv = conv_from_spec_abi(cx.tcx(), sig.abi);
@@ -376,7 +376,7 @@ fn fn_abi_new_uncached<'tcx>(
     let is_drop_in_place =
         fn_def_id.is_some() && fn_def_id == cx.tcx.lang_items().drop_in_place_fn();
 
-    let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
+    let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, &'tcx FnAbiError<'tcx>> {
         let span = tracing::debug_span!("arg_of");
         let _entered = span.enter();
         let is_return = arg_idx.is_none();
@@ -386,7 +386,8 @@ fn fn_abi_new_uncached<'tcx>(
             _ => bug!("argument to drop_in_place is not a raw ptr: {:?}", ty),
         });
 
-        let layout = cx.layout_of(ty).map_err(|err| *err)?;
+        let layout =
+            cx.layout_of(ty).map_err(|err| &*cx.tcx.arena.alloc(FnAbiError::Layout(*err)))?;
         let layout = if force_thin_self_ptr && arg_idx == Some(0) {
             // Don't pass the vtable, it's not an argument of the virtual fn.
             // Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
@@ -454,7 +455,7 @@ fn fn_abi_adjust_for_abi<'tcx>(
     fn_abi: &mut FnAbi<'tcx, Ty<'tcx>>,
     abi: SpecAbi,
     fn_def_id: Option<DefId>,
-) -> Result<(), FnAbiError<'tcx>> {
+) -> Result<(), &'tcx FnAbiError<'tcx>> {
     if abi == SpecAbi::Unadjusted {
         return Ok(());
     }
@@ -548,7 +549,9 @@ fn fn_abi_adjust_for_abi<'tcx>(
             fixup(arg, Some(arg_idx));
         }
     } else {
-        fn_abi.adjust_for_foreign_abi(cx, abi)?;
+        fn_abi
+            .adjust_for_foreign_abi(cx, abi)
+            .map_err(|err| &*cx.tcx.arena.alloc(FnAbiError::AdjustForForeignAbi(err)))?;
     }
 
     Ok(())