| use std::fmt; | |
| use std::ops::Deref; | |
| use rustc_data_structures::intern::Interned; | |
| use rustc_macros::HashStable_Generic; | |
| use crate::layout::{FieldIdx, VariantIdx}; | |
| use crate::{ | |
| AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche, | |
| PointeeInfo, Primitive, Size, Variants, | |
| }; | |
| // Explicitly import `Float` to avoid ambiguity with `Primitive::Float`. | |
| #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] | |
| #[rustc_pass_by_value] | |
| pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>); | |
| impl<'a> fmt::Debug for Layout<'a> { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| // See comment on `<LayoutData as Debug>::fmt` above. | |
| self.0.0.fmt(f) | |
| } | |
| } | |
| impl<'a> Deref for Layout<'a> { | |
| type Target = &'a LayoutData<FieldIdx, VariantIdx>; | |
| fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> { | |
| &self.0.0 | |
| } | |
| } | |
| impl<'a> Layout<'a> { | |
| pub fn fields(self) -> &'a FieldsShape<FieldIdx> { | |
| &self.0.0.fields | |
| } | |
| pub fn variants(self) -> &'a Variants<FieldIdx, VariantIdx> { | |
| &self.0.0.variants | |
| } | |
| pub fn backend_repr(self) -> BackendRepr { | |
| self.0.0.backend_repr | |
| } | |
| pub fn largest_niche(self) -> Option<Niche> { | |
| self.0.0.largest_niche | |
| } | |
| pub fn align(self) -> AbiAlign { | |
| self.0.0.align | |
| } | |
| pub fn size(self) -> Size { | |
| self.0.0.size | |
| } | |
| pub fn max_repr_align(self) -> Option<Align> { | |
| self.0.0.max_repr_align | |
| } | |
| pub fn unadjusted_abi_align(self) -> Align { | |
| self.0.0.unadjusted_abi_align | |
| } | |
| } | |
| /// The layout of a type, alongside the type itself. | |
| /// Provides various type traversal APIs (e.g., recursing into fields). | |
| /// | |
| /// Note that the layout is NOT guaranteed to always be identical | |
| /// to that obtained from `layout_of(ty)`, as we need to produce | |
| /// layouts for which Rust types do not exist, such as enum variants | |
| /// or synthetic fields of enums (i.e., discriminants) and wide pointers. | |
| #[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)] | |
| pub struct TyAndLayout<'a, Ty> { | |
| pub ty: Ty, | |
| pub layout: Layout<'a>, | |
| } | |
| impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| // Print the type in a readable way, not its debug representation. | |
| f.debug_struct("TyAndLayout") | |
| .field("ty", &format_args!("{}", self.ty)) | |
| .field("layout", &self.layout) | |
| .finish() | |
| } | |
| } | |
| impl<'a, Ty> Deref for TyAndLayout<'a, Ty> { | |
| type Target = &'a LayoutData<FieldIdx, VariantIdx>; | |
| fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> { | |
| &self.layout.0.0 | |
| } | |
| } | |
| impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> { | |
| fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> { | |
| &*self.layout.0.0 | |
| } | |
| } | |
| /// Trait that needs to be implemented by the higher-level type representation | |
| /// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality. | |
| pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display { | |
| fn ty_and_layout_for_variant( | |
| this: TyAndLayout<'a, Self>, | |
| cx: &C, | |
| variant_index: VariantIdx, | |
| ) -> TyAndLayout<'a, Self>; | |
| fn ty_and_layout_field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> TyAndLayout<'a, Self>; | |
| fn ty_and_layout_pointee_info_at( | |
| this: TyAndLayout<'a, Self>, | |
| cx: &C, | |
| offset: Size, | |
| ) -> Option<PointeeInfo>; | |
| fn is_adt(this: TyAndLayout<'a, Self>) -> bool; | |
| fn is_never(this: TyAndLayout<'a, Self>) -> bool; | |
| fn is_tuple(this: TyAndLayout<'a, Self>) -> bool; | |
| fn is_unit(this: TyAndLayout<'a, Self>) -> bool; | |
| fn is_transparent(this: TyAndLayout<'a, Self>) -> bool; | |
| fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool; | |
| /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details. | |
| fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool; | |
| } | |
| impl<'a, Ty> TyAndLayout<'a, Ty> { | |
| pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self | |
| where | |
| Ty: TyAbiInterface<'a, C>, | |
| { | |
| Ty::ty_and_layout_for_variant(self, cx, variant_index) | |
| } | |
| pub fn field<C>(self, cx: &C, i: usize) -> Self | |
| where | |
| Ty: TyAbiInterface<'a, C>, | |
| { | |
| Ty::ty_and_layout_field(self, cx, i) | |
| } | |
| pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo> | |
| where | |
| Ty: TyAbiInterface<'a, C>, | |
| { | |
| Ty::ty_and_layout_pointee_info_at(self, cx, offset) | |
| } | |
| pub fn is_single_fp_element<C>(self, cx: &C) -> bool | |
| where | |
| Ty: TyAbiInterface<'a, C>, | |
| C: HasDataLayout, | |
| { | |
| match self.backend_repr { | |
| BackendRepr::Scalar(scalar) => { | |
| matches!(scalar.primitive(), Primitive::Float(Float::F32 | Float::F64)) | |
| } | |
| BackendRepr::Memory { .. } => { | |
| if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { | |
| self.field(cx, 0).is_single_fp_element(cx) | |
| } else { | |
| false | |
| } | |
| } | |
| _ => false, | |
| } | |
| } | |
| pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool | |
| where | |
| Ty: TyAbiInterface<'a, C>, | |
| C: HasDataLayout, | |
| { | |
| match self.backend_repr { | |
| BackendRepr::SimdVector { .. } => self.size == expected_size, | |
| BackendRepr::Memory { .. } => { | |
| if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 { | |
| self.field(cx, 0).is_single_vector_element(cx, expected_size) | |
| } else { | |
| false | |
| } | |
| } | |
| _ => false, | |
| } | |
| } | |
| pub fn is_adt<C>(self) -> bool | |
| where | |
| Ty: TyAbiInterface<'a, C>, | |
| { | |
| Ty::is_adt(self) | |
| } | |
| pub fn is_never<C>(self) -> bool | |
| where | |
| Ty: TyAbiInterface<'a, C>, | |
| { | |
| Ty::is_never(self) | |
| } | |
| pub fn is_tuple<C>(self) -> bool | |
| where | |
| Ty: TyAbiInterface<'a, C>, | |
| { | |
| Ty::is_tuple(self) | |
| } | |
| pub fn is_unit<C>(self) -> bool | |
| where | |
| Ty: TyAbiInterface<'a, C>, | |
| { | |
| Ty::is_unit(self) | |
| } | |
| pub fn is_transparent<C>(self) -> bool | |
| where | |
| Ty: TyAbiInterface<'a, C>, | |
| { | |
| Ty::is_transparent(self) | |
| } | |
| pub fn is_scalable_vector<C>(self) -> bool | |
| where | |
| Ty: TyAbiInterface<'a, C>, | |
| { | |
| Ty::is_scalable_vector(self) | |
| } | |
| /// If this method returns `true`, then this type should always have a `PassMode` of | |
| /// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a | |
| /// non-Rustic ABI (this is true for structs annotated with the | |
| /// `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute). | |
| /// | |
| /// This is used to replicate some of the behaviour of C array-to-pointer decay; however unlike | |
| /// C any changes the caller makes to the passed value will not be reflected in the callee, so | |
| /// the attribute is only useful for types where observing the value in the caller after the | |
| /// function call isn't allowed (a.k.a. `va_list`). | |
| /// | |
| /// This function handles transparent types automatically. | |
| pub fn pass_indirectly_in_non_rustic_abis<C>(self, cx: &C) -> bool | |
| where | |
| Ty: TyAbiInterface<'a, C> + Copy, | |
| { | |
| let base = self.peel_transparent_wrappers(cx); | |
| Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(base) | |
| } | |
| /// Recursively peel away transparent wrappers, returning the inner value. | |
| /// | |
| /// The return value is not `repr(transparent)` and/or does | |
| /// not have a non-1zst field. | |
| pub fn peel_transparent_wrappers<C>(mut self, cx: &C) -> Self | |
| where | |
| Ty: TyAbiInterface<'a, C> + Copy, | |
| { | |
| while self.is_transparent() | |
| && let Some((_, field)) = self.non_1zst_field(cx) | |
| { | |
| self = field; | |
| } | |
| self | |
| } | |
| /// Finds the one field that is not a 1-ZST. | |
| /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields. | |
| pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(FieldIdx, Self)> | |
| where | |
| Ty: TyAbiInterface<'a, C> + Copy, | |
| { | |
| let mut found = None; | |
| for field_idx in 0..self.fields.count() { | |
| let field = self.field(cx, field_idx); | |
| if field.is_1zst() { | |
| continue; | |
| } | |
| if found.is_some() { | |
| // More than one non-1-ZST field. | |
| return None; | |
| } | |
| found = Some((FieldIdx::from_usize(field_idx), field)); | |
| } | |
| found | |
| } | |
| } |