From c1837ef1c58edd48c81341126ecc94e7adc5bd3d Mon Sep 17 00:00:00 2001
From: Eduard-Mihai Burtescu <eddyb@lyken.rs>
Date: Thu, 2 Sep 2021 00:29:15 +0300
Subject: [PATCH] Querify `fn_abi_of_{fn_ptr,instance}`.

---
 .../rustc_codegen_cranelift/src/abi/mod.rs    |  23 ++--
 compiler/rustc_codegen_cranelift/src/base.rs  |   2 +-
 .../rustc_codegen_cranelift/src/common.rs     |   4 +-
 .../src/pretty_clif.rs                        |   5 +-
 compiler/rustc_codegen_llvm/src/builder.rs    |   2 +-
 compiler/rustc_codegen_llvm/src/callee.rs     |   2 +-
 compiler/rustc_codegen_llvm/src/context.rs    |   2 +-
 .../src/coverageinfo/mod.rs                   |   2 +-
 .../src/debuginfo/create_scope_map.rs         |   2 +-
 compiler/rustc_codegen_llvm/src/intrinsic.rs  |   2 +-
 compiler/rustc_codegen_llvm/src/mono_item.rs  |   2 +-
 compiler/rustc_codegen_llvm/src/type_of.rs    |   4 +-
 compiler/rustc_codegen_ssa/src/mir/block.rs   |  23 ++--
 compiler/rustc_codegen_ssa/src/mir/mod.rs     |   2 +-
 compiler/rustc_middle/src/query/mod.rs        |  21 +++
 compiler/rustc_middle/src/ty/layout.rs        | 123 +++++++++---------
 compiler/rustc_middle/src/ty/query.rs         |   1 +
 compiler/rustc_query_impl/src/keys.rs         |  22 ++++
 compiler/rustc_target/src/abi/call/mod.rs     |   1 +
 19 files changed, 152 insertions(+), 93 deletions(-)

diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 6317e1d5d1a..15bb9067805 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -53,7 +53,11 @@ pub(crate) fn get_function_sig<'tcx>(
     inst: Instance<'tcx>,
 ) -> Signature {
     assert!(!inst.substs.needs_infer());
-    clif_sig_from_fn_abi(tcx, triple, &RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, &[]))
+    clif_sig_from_fn_abi(
+        tcx,
+        triple,
+        &RevealAllLayoutCx(tcx).fn_abi_of_instance(inst, ty::List::empty()),
+    )
 }
 
 /// Instance must be monomorphized
@@ -350,14 +354,13 @@ pub(crate) fn codegen_terminator_call<'tcx>(
     };
 
     let extra_args = &args[fn_sig.inputs().len()..];
-    let extra_args = extra_args
-        .iter()
-        .map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx)))
-        .collect::<Vec<_>>();
+    let extra_args = fx
+        .tcx
+        .mk_type_list(extra_args.iter().map(|op_arg| fx.monomorphize(op_arg.ty(fx.mir, fx.tcx))));
     let fn_abi = if let Some(instance) = instance {
-        RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, &extra_args)
+        RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(instance, extra_args)
     } else {
-        RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), &extra_args)
+        RevealAllLayoutCx(fx.tcx).fn_abi_of_fn_ptr(fn_ty.fn_sig(fx.tcx), extra_args)
     };
 
     let is_cold = instance
@@ -525,7 +528,8 @@ pub(crate) fn codegen_drop<'tcx>(
                     def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0),
                     substs: drop_instance.substs,
                 };
-                let fn_abi = RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, &[]);
+                let fn_abi =
+                    RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(virtual_drop, ty::List::empty());
 
                 let sig = clif_sig_from_fn_abi(fx.tcx, fx.triple(), &fn_abi);
                 let sig = fx.bcx.import_signature(sig);
@@ -534,7 +538,8 @@ pub(crate) fn codegen_drop<'tcx>(
             _ => {
                 assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _)));
 
-                let fn_abi = RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, &[]);
+                let fn_abi =
+                    RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty());
 
                 let arg_value = drop_place.place_ref(
                     fx,
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index 872c7edc791..d8fa2c76904 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -61,7 +61,7 @@ pub(crate) fn codegen_fn<'tcx>(
         instance,
         symbol_name,
         mir,
-        fn_abi: Some(RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, &[])),
+        fn_abi: Some(RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())),
 
         bcx,
         block_map,
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 4a8be89460f..0e84681d9ad 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -276,7 +276,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for FunctionCx<'_, '_, 'tcx> {
         &self,
         err: FnAbiError<'tcx>,
         span: Span,
-        fn_abi_request: FnAbiRequest<'_, 'tcx>,
+        fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
         RevealAllLayoutCx(self.tcx).handle_fn_abi_err(err, span, fn_abi_request)
     }
@@ -402,7 +402,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
         &self,
         err: FnAbiError<'tcx>,
         span: Span,
-        fn_abi_request: FnAbiRequest<'_, 'tcx>,
+        fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
         if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
             self.0.sess.span_fatal(span, &err.to_string())
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index 0b80ef1c04e..ec846d71960 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -80,7 +80,10 @@ impl CommentWriter {
             vec![
                 format!("symbol {}", tcx.symbol_name(instance).name),
                 format!("instance {:?}", instance),
-                format!("abi {:?}", RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, &[])),
+                format!(
+                    "abi {:?}",
+                    RevealAllLayoutCx(tcx).fn_abi_of_instance(instance, ty::List::empty())
+                ),
                 String::new(),
             ]
         } else {
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 8e3aaf56382..dab7d3eaa8c 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -107,7 +107,7 @@ impl FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
         &self,
         err: FnAbiError<'tcx>,
         span: Span,
-        fn_abi_request: FnAbiRequest<'_, 'tcx>,
+        fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
         self.cx.handle_fn_abi_err(err, span, fn_abi_request)
     }
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 1a2aea015b1..a96ba148a6c 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -42,7 +42,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value
         sym
     );
 
-    let fn_abi = cx.fn_abi_of_instance(instance, &[]);
+    let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
 
     let llfn = if let Some(llfn) = cx.get_declared_value(&sym) {
         // Create a fn pointer with the new signature.
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index f1a2968ce59..52a12b2fd81 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -867,7 +867,7 @@ impl FnAbiOfHelpers<'tcx> for CodegenCx<'ll, 'tcx> {
         &self,
         err: FnAbiError<'tcx>,
         span: Span,
-        fn_abi_request: FnAbiRequest<'_, 'tcx>,
+        fn_abi_request: FnAbiRequest<'tcx>,
     ) -> ! {
         if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
             self.sess().span_fatal(span, &err.to_string())
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index cc1376278aa..093aceda2b7 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -208,7 +208,7 @@ fn declare_unused_fn(cx: &CodegenCx<'ll, 'tcx>, def_id: &DefId) -> Instance<'tcx
                 hir::Unsafety::Unsafe,
                 Abi::Rust,
             )),
-            &[],
+            ty::List::empty(),
         ),
     );
 
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index e5fd5bae01b..1612922d439 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -93,7 +93,7 @@ fn make_mir_scope(
                 ty::ParamEnv::reveal_all(),
                 callee,
             );
-            let callee_fn_abi = cx.fn_abi_of_instance(callee, &[]);
+            let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
             cx.dbg_scope_fn(callee, &callee_fn_abi, None)
         }
         None => unsafe {
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index a046c518e1a..9d0e0e63944 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -737,7 +737,7 @@ fn gen_fn<'ll, 'tcx>(
     rust_fn_sig: ty::PolyFnSig<'tcx>,
     codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
 ) -> (&'ll Type, &'ll Value) {
-    let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, &[]);
+    let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
     let llty = fn_abi.llvm_type(cx);
     let llfn = cx.declare_fn(name, &fn_abi);
     cx.set_frame_pointer_type(llfn);
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index b0301fa75aa..34982f769d0 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -52,7 +52,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> {
     ) {
         assert!(!instance.substs.needs_infer());
 
-        let fn_abi = self.fn_abi_of_instance(instance, &[]);
+        let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
         let lldecl = self.declare_fn(symbol_name, &fn_abi);
         unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
         let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 94ad84aadd8..757ccbddbee 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -230,7 +230,9 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
                 ty::Adt(def, _) if def.is_box() => {
                     cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).llvm_type(cx))
                 }
-                ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, &[])),
+                ty::FnPtr(sig) => {
+                    cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty()))
+                }
                 _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO),
             };
             cx.scalar_lltypes.borrow_mut().insert(self.ty, llty);
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index fac72c39b5e..cc9dd378ee4 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -337,7 +337,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
                     substs: drop_fn.substs,
                 };
-                let fn_abi = bx.fn_abi_of_instance(virtual_drop, &[]);
+                let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
                 let vtable = args[1];
                 args = &args[..1];
                 (
@@ -346,7 +346,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                     fn_abi,
                 )
             }
-            _ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, &[])),
+            _ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
         };
         helper.do_call(
             self,
@@ -433,7 +433,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         // Obtain the panic entry point.
         let def_id = common::langcall(bx.tcx(), Some(span), "", lang_item);
         let instance = ty::Instance::mono(bx.tcx(), def_id);
-        let fn_abi = bx.fn_abi_of_instance(instance, &[]);
+        let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
         let llfn = bx.get_fn_addr(instance);
 
         // Codegen the actual panic invoke/call.
@@ -494,7 +494,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
                 let def_id =
                     common::langcall(bx.tcx(), Some(source_info.span), "", LangItem::Panic);
                 let instance = ty::Instance::mono(bx.tcx(), def_id);
-                let fn_abi = bx.fn_abi_of_instance(instance, &[]);
+                let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
                 let llfn = bx.get_fn_addr(instance);
 
                 // Codegen the actual panic invoke/call.
@@ -570,17 +570,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
         };
 
         let extra_args = &args[sig.inputs().skip_binder().len()..];
-        let extra_args = extra_args
-            .iter()
-            .map(|op_arg| {
-                let op_ty = op_arg.ty(self.mir, bx.tcx());
-                self.monomorphize(op_ty)
-            })
-            .collect::<Vec<_>>();
+        let extra_args = bx.tcx().mk_type_list(extra_args.iter().map(|op_arg| {
+            let op_ty = op_arg.ty(self.mir, bx.tcx());
+            self.monomorphize(op_ty)
+        }));
 
         let fn_abi = match instance {
-            Some(instance) => bx.fn_abi_of_instance(instance, &extra_args),
-            None => bx.fn_abi_of_fn_ptr(sig, &extra_args),
+            Some(instance) => bx.fn_abi_of_instance(instance, extra_args),
+            None => bx.fn_abi_of_fn_ptr(sig, extra_args),
         };
 
         if intrinsic == Some(sym::transmute) {
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 3fd9dc08c2b..9ad2a66bc6a 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -139,7 +139,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
 
     let mir = cx.tcx().instance_mir(instance.def);
 
-    let fn_abi = cx.fn_abi_of_instance(instance, &[]);
+    let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
     debug!("fn_abi: {:?}", fn_abi);
 
     let debug_context = cx.create_function_debug_context(instance, &fn_abi, llfn, &mir);
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 4296acce1ff..6a1ebbba817 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -1128,6 +1128,27 @@ rustc_queries! {
         desc { "computing layout of `{}`", key.value }
     }
 
+    /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
+    ///
+    /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance`
+    /// 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>> {
+        desc { "computing call ABI of `{}` function pointers", key.value.0 }
+    }
+
+    /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
+    /// direct calls to an `fn`.
+    ///
+    /// NB: that includes virtual calls, which are represented by "direct calls"
+    /// 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>> {
+        desc { "computing call ABI of `{}`", key.value.0 }
+    }
+
     query dylib_dependency_formats(_: CrateNum)
                                     -> &'tcx [(CrateNum, LinkagePreference)] {
         desc { "dylib dependency formats of crate" }
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 04d8eaf7c9f..f72f045e907 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,4 +1,3 @@
-use crate::ich::StableHashingContext;
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::mir::{GeneratorLayout, GeneratorSavedLocal};
 use crate::ty::subst::Subst;
@@ -6,7 +5,6 @@ use crate::ty::{self, subst::SubstsRef, ReprOptions, Ty, TyCtxt, TypeFoldable};
 
 use rustc_ast as ast;
 use rustc_attr as attr;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::BitSet;
@@ -23,10 +21,14 @@ use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Targ
 use std::cmp;
 use std::fmt;
 use std::iter;
-use std::mem;
 use std::num::NonZeroUsize;
 use std::ops::Bound;
 
+pub fn provide(providers: &mut ty::query::Providers) {
+    *providers =
+        ty::query::Providers { layout_of, fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers };
+}
+
 pub trait IntegerExt {
     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>, signed: bool) -> Ty<'tcx>;
     fn from_attr<C: HasDataLayout>(cx: &C, ity: attr::IntType) -> Integer;
@@ -191,7 +193,7 @@ pub const FAT_PTR_EXTRA: usize = 1;
 /// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
 pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
 
-#[derive(Copy, Clone, Debug, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, Debug, HashStable, TyEncodable, TyDecodable)]
 pub enum LayoutError<'tcx> {
     Unknown(Ty<'tcx>),
     SizeOverflow(Ty<'tcx>),
@@ -248,10 +250,6 @@ fn layout_of<'tcx>(
     })
 }
 
-pub fn provide(providers: &mut ty::query::Providers) {
-    *providers = ty::query::Providers { layout_of, ..*providers };
-}
-
 pub struct LayoutCx<'tcx, C> {
     pub tcx: C,
     pub param_env: ty::ParamEnv<'tcx>,
@@ -2537,18 +2535,6 @@ where
     }
 }
 
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for LayoutError<'tcx> {
-    #[inline]
-    fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
-        use crate::ty::layout::LayoutError::*;
-        mem::discriminant(self).hash_stable(hcx, hasher);
-
-        match *self {
-            Unknown(t) | SizeOverflow(t) => t.hash_stable(hcx, hasher),
-        }
-    }
-}
-
 impl<'tcx> ty::Instance<'tcx> {
     // NOTE(eddyb) this is private to avoid using it from outside of
     // `fn_abi_of_instance` - any other uses are either too high-level
@@ -2807,6 +2793,7 @@ pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
 }
 
 /// Error produced by attempting to compute or adjust a `FnAbi`.
+#[derive(Clone, Debug, HashStable)]
 pub enum FnAbiError<'tcx> {
     /// Error produced by a `layout_of` call, while computing `FnAbi` initially.
     Layout(LayoutError<'tcx>),
@@ -2839,9 +2826,9 @@ impl<'tcx> fmt::Display for FnAbiError<'tcx> {
 // FIXME(eddyb) maybe use something like this for an unified `fn_abi_of`, not
 // just for error handling.
 #[derive(Debug)]
-pub enum FnAbiRequest<'a, 'tcx> {
-    OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'a [Ty<'tcx>] },
-    OfInstance { instance: ty::Instance<'tcx>, extra_args: &'a [Ty<'tcx>] },
+pub enum FnAbiRequest<'tcx> {
+    OfFnPtr { sig: ty::PolyFnSig<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
+    OfInstance { instance: ty::Instance<'tcx>, extra_args: &'tcx ty::List<Ty<'tcx>> },
 }
 
 /// Trait for contexts that want to be able to compute `FnAbi`s.
@@ -2855,14 +2842,14 @@ pub trait FnAbiOfHelpers<'tcx>: LayoutOfHelpers<'tcx> {
     /// `Self::FnAbiOfResult` (which does not need to be a `Result<...>`).
     ///
     /// Most `impl`s, which propagate `FnAbiError`s, should simply return `err`,
-    /// but this hook allows e.g. codegen to return only `&FnABi` from its
+    /// but this hook allows e.g. codegen to return only `&FnAbi` from its
     /// `cx.fn_abi_of_*(...)`, without any `Result<...>` around it to deal with
     /// (and any `FnAbiError`s are turned into fatal errors or ICEs).
     fn handle_fn_abi_err(
         &self,
         err: FnAbiError<'tcx>,
         span: Span,
-        fn_abi_request: FnAbiRequest<'_, 'tcx>,
+        fn_abi_request: FnAbiRequest<'tcx>,
     ) -> <Self::FnAbiOfResult as MaybeResult<&'tcx FnAbi<'tcx, Ty<'tcx>>>>::Error;
 }
 
@@ -2876,18 +2863,15 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
     fn fn_abi_of_fn_ptr(
         &self,
         sig: ty::PolyFnSig<'tcx>,
-        extra_args: &[Ty<'tcx>],
+        extra_args: &'tcx ty::List<Ty<'tcx>>,
     ) -> Self::FnAbiOfResult {
         // FIXME(eddyb) get a better `span` here.
         let span = self.layout_tcx_at_span();
-        let cx = LayoutCx { tcx: self.tcx().at(span), param_env: self.param_env() };
+        let tcx = self.tcx().at(span);
 
-        MaybeResult::from(
-            cx.fn_abi_new_internal(sig, extra_args, None, CodegenFnAttrFlags::empty(), false)
-                .map_err(|err| {
-                    self.handle_fn_abi_err(err, span, FnAbiRequest::OfFnPtr { sig, extra_args })
-                }),
-        )
+        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 }),
+        ))
     }
 
     /// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
@@ -2899,36 +2883,19 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
     fn fn_abi_of_instance(
         &self,
         instance: ty::Instance<'tcx>,
-        extra_args: &[Ty<'tcx>],
+        extra_args: &'tcx ty::List<Ty<'tcx>>,
     ) -> Self::FnAbiOfResult {
         // FIXME(eddyb) get a better `span` here.
         let span = self.layout_tcx_at_span();
-        let cx = LayoutCx { tcx: self.tcx().at(span), param_env: self.param_env() };
-
-        let sig = instance.fn_sig_for_fn_abi(cx.tcx());
-
-        let caller_location = if instance.def.requires_caller_location(cx.tcx()) {
-            Some(cx.tcx.caller_location_ty())
-        } else {
-            None
-        };
-
-        let attrs = cx.tcx.codegen_fn_attrs(instance.def_id()).flags;
+        let tcx = self.tcx().at(span);
 
         MaybeResult::from(
-            cx.fn_abi_new_internal(
-                sig,
-                extra_args,
-                caller_location,
-                attrs,
-                matches!(instance.def, ty::InstanceDef::Virtual(..)),
-            )
-            .map_err(|err| {
+            tcx.fn_abi_of_instance(self.param_env().and((instance, extra_args))).map_err(|err| {
                 // HACK(eddyb) at least for definitions of/calls to `Instance`s,
                 // we can get some kind of span even if one wasn't provided.
                 // 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 { cx.tcx.def_span(instance.def_id()) };
+                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 })
             }),
         )
@@ -2937,10 +2904,50 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> {
 
 impl<C: FnAbiOfHelpers<'tcx>> FnAbiOf<'tcx> for C {}
 
-impl<'tcx> LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
+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>> {
+    let (param_env, (sig, extra_args)) = query.into_parts();
+
+    LayoutCx { tcx, param_env }.fn_abi_new_uncached(
+        sig,
+        extra_args,
+        None,
+        CodegenFnAttrFlags::empty(),
+        false,
+    )
+}
+
+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>> {
+    let (param_env, (instance, extra_args)) = query.into_parts();
+
+    let sig = instance.fn_sig_for_fn_abi(tcx);
+
+    let caller_location = if instance.def.requires_caller_location(tcx) {
+        Some(tcx.caller_location_ty())
+    } else {
+        None
+    };
+
+    let attrs = tcx.codegen_fn_attrs(instance.def_id()).flags;
+
+    LayoutCx { tcx, param_env }.fn_abi_new_uncached(
+        sig,
+        extra_args,
+        caller_location,
+        attrs,
+        matches!(instance.def, ty::InstanceDef::Virtual(..)),
+    )
+}
+
+impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
     // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?)
     // arguments of this method, into a separate `struct`.
-    fn fn_abi_new_internal(
+    fn fn_abi_new_uncached(
         &self,
         sig: ty::PolyFnSig<'tcx>,
         extra_args: &[Ty<'tcx>],
@@ -2949,7 +2956,7 @@ impl<'tcx> LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
         // FIXME(eddyb) replace this with something typed, like an `enum`.
         force_thin_self_ptr: bool,
     ) -> Result<&'tcx FnAbi<'tcx, Ty<'tcx>>, FnAbiError<'tcx>> {
-        debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
+        debug!("fn_abi_new_uncached({:?}, {:?})", sig, extra_args);
 
         let sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, sig);
 
@@ -3110,7 +3117,7 @@ impl<'tcx> LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
             can_unwind: fn_can_unwind(self.tcx(), codegen_fn_attr_flags, sig.abi),
         };
         self.fn_abi_adjust_for_abi(&mut fn_abi, sig.abi)?;
-        debug!("FnAbi::new_internal = {:?}", fn_abi);
+        debug!("fn_abi_new_uncached = {:?}", fn_abi);
         Ok(self.tcx.intern_fn_abi(fn_abi))
     }
 
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/ty/query.rs
index 15a8888ee65..154b26464a8 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/ty/query.rs
@@ -48,6 +48,7 @@ use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec};
 use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
 use rustc_session::utils::NativeLibKind;
 use rustc_session::Limits;
+use rustc_target::abi;
 use rustc_target::spec::PanicStrategy;
 
 use rustc_ast as ast;
diff --git a/compiler/rustc_query_impl/src/keys.rs b/compiler/rustc_query_impl/src/keys.rs
index 42e8b4023cf..563a3cf1438 100644
--- a/compiler/rustc_query_impl/src/keys.rs
+++ b/compiler/rustc_query_impl/src/keys.rs
@@ -449,3 +449,25 @@ impl<'tcx> Key for (ty::Predicate<'tcx>, traits::WellFormedLoc) {
         DUMMY_SP
     }
 }
+
+impl<'tcx> Key for (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+
+    fn default_span(&self, _: TyCtxt<'_>) -> Span {
+        DUMMY_SP
+    }
+}
+
+impl<'tcx> Key for (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>) {
+    #[inline(always)]
+    fn query_crate_is_local(&self) -> bool {
+        true
+    }
+
+    fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
+        self.0.default_span(tcx)
+    }
+}
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 6f06f2b56ad..324278c57bf 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -601,6 +601,7 @@ pub struct FnAbi<'a, Ty> {
 }
 
 /// Error produced by attempting to adjust a `FnAbi`, for a "foreign" ABI.
+#[derive(Clone, Debug, HashStable_Generic)]
 pub enum AdjustForForeignAbiError {
     /// Target architecture doesn't support "foreign" (i.e. non-Rust) ABIs.
     Unsupported { arch: String, abi: spec::abi::Abi },