about summary refs log tree commit diff
path: root/compiler/rustc_middle
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle')
-rw-r--r--compiler/rustc_middle/src/query/mod.rs21
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs123
-rw-r--r--compiler/rustc_middle/src/ty/query.rs1
3 files changed, 87 insertions, 58 deletions
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;