Skip to main content

rustc_abi/layout/
ty.rs

1use std::fmt;
2use std::ops::Deref;
3
4use rustc_data_structures::intern::Interned;
5use rustc_macros::HashStable_Generic;
6
7use crate::layout::{FieldIdx, VariantIdx};
8use crate::{
9    AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
10    PointeeInfo, Primitive, Size, Variants,
11};
12
13// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
14
15#[derive(#[automatically_derived]
impl<'a> ::core::marker::Copy for Layout<'a> { }Copy, #[automatically_derived]
impl<'a> ::core::clone::Clone for Layout<'a> {
    #[inline]
    fn clone(&self) -> Layout<'a> {
        let _:
                ::core::clone::AssertParamIsClone<Interned<'a,
                LayoutData<FieldIdx, VariantIdx>>>;
        *self
    }
}Clone, #[automatically_derived]
impl<'a> ::core::cmp::PartialEq for Layout<'a> {
    #[inline]
    fn eq(&self, other: &Layout<'a>) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl<'a> ::core::cmp::Eq for Layout<'a> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _:
                ::core::cmp::AssertParamIsEq<Interned<'a,
                LayoutData<FieldIdx, VariantIdx>>>;
    }
}Eq, #[automatically_derived]
impl<'a> ::core::hash::Hash for Layout<'a> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.0, state)
    }
}Hash, const _: () =
    {
        impl<'a, __CTX>
            ::rustc_data_structures::stable_hasher::HashStable<__CTX> for
            Layout<'a> where __CTX: crate::HashStableContext {
            #[inline]
            fn hash_stable(&self, __hcx: &mut __CTX,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                match *self {
                    Layout(ref __binding_0) => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable_Generic)]
16#[rustc_pass_by_value]
17pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
18
19impl<'a> fmt::Debug for Layout<'a> {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        // See comment on `<LayoutData as Debug>::fmt` above.
22        self.0.0.fmt(f)
23    }
24}
25
26impl<'a> Deref for Layout<'a> {
27    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
28    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
29        &self.0.0
30    }
31}
32
33impl<'a> Layout<'a> {
34    pub fn fields(self) -> &'a FieldsShape<FieldIdx> {
35        &self.0.0.fields
36    }
37
38    pub fn variants(self) -> &'a Variants<FieldIdx, VariantIdx> {
39        &self.0.0.variants
40    }
41
42    pub fn backend_repr(self) -> BackendRepr {
43        self.0.0.backend_repr
44    }
45
46    pub fn largest_niche(self) -> Option<Niche> {
47        self.0.0.largest_niche
48    }
49
50    pub fn align(self) -> AbiAlign {
51        self.0.0.align
52    }
53
54    pub fn size(self) -> Size {
55        self.0.0.size
56    }
57
58    pub fn max_repr_align(self) -> Option<Align> {
59        self.0.0.max_repr_align
60    }
61
62    pub fn unadjusted_abi_align(self) -> Align {
63        self.0.0.unadjusted_abi_align
64    }
65}
66
67/// The layout of a type, alongside the type itself.
68/// Provides various type traversal APIs (e.g., recursing into fields).
69///
70/// Note that the layout is NOT guaranteed to always be identical
71/// to that obtained from `layout_of(ty)`, as we need to produce
72/// layouts for which Rust types do not exist, such as enum variants
73/// or synthetic fields of enums (i.e., discriminants) and wide pointers.
74#[derive(#[automatically_derived]
impl<'a, Ty: ::core::marker::Copy> ::core::marker::Copy for
    TyAndLayout<'a, Ty> {
}Copy, #[automatically_derived]
impl<'a, Ty: ::core::clone::Clone> ::core::clone::Clone for
    TyAndLayout<'a, Ty> {
    #[inline]
    fn clone(&self) -> TyAndLayout<'a, Ty> {
        TyAndLayout {
            ty: ::core::clone::Clone::clone(&self.ty),
            layout: ::core::clone::Clone::clone(&self.layout),
        }
    }
}Clone, #[automatically_derived]
impl<'a, Ty: ::core::cmp::PartialEq> ::core::cmp::PartialEq for
    TyAndLayout<'a, Ty> {
    #[inline]
    fn eq(&self, other: &TyAndLayout<'a, Ty>) -> bool {
        self.ty == other.ty && self.layout == other.layout
    }
}PartialEq, #[automatically_derived]
impl<'a, Ty: ::core::cmp::Eq> ::core::cmp::Eq for TyAndLayout<'a, Ty> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Ty>;
        let _: ::core::cmp::AssertParamIsEq<Layout<'a>>;
    }
}Eq, #[automatically_derived]
impl<'a, Ty: ::core::hash::Hash> ::core::hash::Hash for TyAndLayout<'a, Ty> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.ty, state);
        ::core::hash::Hash::hash(&self.layout, state)
    }
}Hash, const _: () =
    {
        impl<'a, Ty, __CTX>
            ::rustc_data_structures::stable_hasher::HashStable<__CTX> for
            TyAndLayout<'a, Ty> where __CTX: crate::HashStableContext,
            Ty: ::rustc_data_structures::stable_hasher::HashStable<__CTX> {
            #[inline]
            fn hash_stable(&self, __hcx: &mut __CTX,
                __hasher:
                    &mut ::rustc_data_structures::stable_hasher::StableHasher) {
                match *self {
                    TyAndLayout { ty: ref __binding_0, layout: ref __binding_1 }
                        => {
                        { __binding_0.hash_stable(__hcx, __hasher); }
                        { __binding_1.hash_stable(__hcx, __hasher); }
                    }
                }
            }
        }
    };HashStable_Generic)]
75pub struct TyAndLayout<'a, Ty> {
76    pub ty: Ty,
77    pub layout: Layout<'a>,
78}
79
80impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> {
81    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82        // Print the type in a readable way, not its debug representation.
83        f.debug_struct("TyAndLayout")
84            .field("ty", &format_args!("{0}", self.ty)format_args!("{}", self.ty))
85            .field("layout", &self.layout)
86            .finish()
87    }
88}
89
90impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
91    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
92    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
93        &self.layout.0.0
94    }
95}
96
97impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
98    fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> {
99        &*self.layout.0.0
100    }
101}
102
103/// Trait that needs to be implemented by the higher-level type representation
104/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
105pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display {
106    fn ty_and_layout_for_variant(
107        this: TyAndLayout<'a, Self>,
108        cx: &C,
109        variant_index: VariantIdx,
110    ) -> TyAndLayout<'a, Self>;
111    fn ty_and_layout_field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> TyAndLayout<'a, Self>;
112    fn ty_and_layout_pointee_info_at(
113        this: TyAndLayout<'a, Self>,
114        cx: &C,
115        offset: Size,
116    ) -> Option<PointeeInfo>;
117    fn is_adt(this: TyAndLayout<'a, Self>) -> bool;
118    fn is_never(this: TyAndLayout<'a, Self>) -> bool;
119    fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
120    fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
121    fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
122    fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool;
123    /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
124    fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
125}
126
127impl<'a, Ty> TyAndLayout<'a, Ty> {
128    pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
129    where
130        Ty: TyAbiInterface<'a, C>,
131    {
132        Ty::ty_and_layout_for_variant(self, cx, variant_index)
133    }
134
135    pub fn field<C>(self, cx: &C, i: usize) -> Self
136    where
137        Ty: TyAbiInterface<'a, C>,
138    {
139        Ty::ty_and_layout_field(self, cx, i)
140    }
141
142    pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
143    where
144        Ty: TyAbiInterface<'a, C>,
145    {
146        Ty::ty_and_layout_pointee_info_at(self, cx, offset)
147    }
148
149    pub fn is_single_fp_element<C>(self, cx: &C) -> bool
150    where
151        Ty: TyAbiInterface<'a, C>,
152        C: HasDataLayout,
153    {
154        match self.backend_repr {
155            BackendRepr::Scalar(scalar) => {
156                #[allow(non_exhaustive_omitted_patterns)] match scalar.primitive() {
    Primitive::Float(Float::F32 | Float::F64) => true,
    _ => false,
}matches!(scalar.primitive(), Primitive::Float(Float::F32 | Float::F64))
157            }
158            BackendRepr::Memory { .. } => {
159                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
160                    self.field(cx, 0).is_single_fp_element(cx)
161                } else {
162                    false
163                }
164            }
165            _ => false,
166        }
167    }
168
169    pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool
170    where
171        Ty: TyAbiInterface<'a, C>,
172        C: HasDataLayout,
173    {
174        match self.backend_repr {
175            BackendRepr::SimdVector { .. } => self.size == expected_size,
176            BackendRepr::Memory { .. } => {
177                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
178                    self.field(cx, 0).is_single_vector_element(cx, expected_size)
179                } else {
180                    false
181                }
182            }
183            _ => false,
184        }
185    }
186
187    pub fn is_adt<C>(self) -> bool
188    where
189        Ty: TyAbiInterface<'a, C>,
190    {
191        Ty::is_adt(self)
192    }
193
194    pub fn is_never<C>(self) -> bool
195    where
196        Ty: TyAbiInterface<'a, C>,
197    {
198        Ty::is_never(self)
199    }
200
201    pub fn is_tuple<C>(self) -> bool
202    where
203        Ty: TyAbiInterface<'a, C>,
204    {
205        Ty::is_tuple(self)
206    }
207
208    pub fn is_unit<C>(self) -> bool
209    where
210        Ty: TyAbiInterface<'a, C>,
211    {
212        Ty::is_unit(self)
213    }
214
215    pub fn is_transparent<C>(self) -> bool
216    where
217        Ty: TyAbiInterface<'a, C>,
218    {
219        Ty::is_transparent(self)
220    }
221
222    pub fn is_scalable_vector<C>(self) -> bool
223    where
224        Ty: TyAbiInterface<'a, C>,
225    {
226        Ty::is_scalable_vector(self)
227    }
228
229    /// If this method returns `true`, then this type should always have a `PassMode` of
230    /// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
231    /// non-Rustic ABI (this is true for structs annotated with the
232    /// `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute).
233    ///
234    /// This is used to replicate some of the behaviour of C array-to-pointer decay; however unlike
235    /// C any changes the caller makes to the passed value will not be reflected in the callee, so
236    /// the attribute is only useful for types where observing the value in the caller after the
237    /// function call isn't allowed (a.k.a. `va_list`).
238    ///
239    /// This function handles transparent types automatically.
240    pub fn pass_indirectly_in_non_rustic_abis<C>(self, cx: &C) -> bool
241    where
242        Ty: TyAbiInterface<'a, C> + Copy,
243    {
244        let base = self.peel_transparent_wrappers(cx);
245        Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(base)
246    }
247
248    /// Recursively peel away transparent wrappers, returning the inner value.
249    ///
250    /// The return value is not `repr(transparent)` and/or does
251    /// not have a non-1zst field.
252    pub fn peel_transparent_wrappers<C>(mut self, cx: &C) -> Self
253    where
254        Ty: TyAbiInterface<'a, C> + Copy,
255    {
256        while self.is_transparent()
257            && let Some((_, field)) = self.non_1zst_field(cx)
258        {
259            self = field;
260        }
261
262        self
263    }
264
265    /// Finds the one field that is not a 1-ZST.
266    /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
267    pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(FieldIdx, Self)>
268    where
269        Ty: TyAbiInterface<'a, C> + Copy,
270    {
271        let mut found = None;
272        for field_idx in 0..self.fields.count() {
273            let field = self.field(cx, field_idx);
274            if field.is_1zst() {
275                continue;
276            }
277            if found.is_some() {
278                // More than one non-1-ZST field.
279                return None;
280            }
281            found = Some((FieldIdx::from_usize(field_idx), field));
282        }
283        found
284    }
285}