Thanks to visit codestin.com
Credit goes to doc.rust-lang.org

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::{
8    AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
9    PointeeInfo, Primitive, Size, Variants,
10};
11
12// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
13
14rustc_index::newtype_index! {
15    /// The *source-order* index of a field in a variant.
16    ///
17    /// This is how most code after type checking refers to fields, rather than
18    /// using names (as names have hygiene complications and more complex lookup).
19    ///
20    /// Particularly for `repr(Rust)` types, this may not be the same as *layout* order.
21    /// (It is for `repr(C)` `struct`s, however.)
22    ///
23    /// For example, in the following types,
24    /// ```rust
25    /// # enum Never {}
26    /// # #[repr(u16)]
27    /// enum Demo1 {
28    ///    Variant0 { a: Never, b: i32 } = 100,
29    ///    Variant1 { c: u8, d: u64 } = 10,
30    /// }
31    /// struct Demo2 { e: u8, f: u16, g: u8 }
32    /// ```
33    /// `b` is `FieldIdx(1)` in `VariantIdx(0)`,
34    /// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and
35    /// `f` is `FieldIdx(1)` in `VariantIdx(0)`.
36    #[derive(HashStable_Generic)]
37    #[encodable]
38    #[orderable]
39    pub struct FieldIdx {}
40}
41
42impl FieldIdx {
43    /// The second field, at index 1.
44    ///
45    /// For use alongside [`FieldIdx::ZERO`], particularly with scalar pairs.
46    pub const ONE: FieldIdx = FieldIdx::from_u32(1);
47}
48
49rustc_index::newtype_index! {
50    /// The *source-order* index of a variant in a type.
51    ///
52    /// For enums, these are always `0..variant_count`, regardless of any
53    /// custom discriminants that may have been defined, and including any
54    /// variants that may end up uninhabited due to field types.  (Some of the
55    /// variants may not be present in a monomorphized ABI [`Variants`], but
56    /// those skipped variants are always counted when determining the *index*.)
57    ///
58    /// `struct`s, `tuples`, and `unions`s are considered to have a single variant
59    /// with variant index zero, aka [`FIRST_VARIANT`].
60    #[derive(HashStable_Generic)]
61    #[encodable]
62    #[orderable]
63    pub struct VariantIdx {
64        /// Equivalent to `VariantIdx(0)`.
65        const FIRST_VARIANT = 0;
66    }
67}
68#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
69#[rustc_pass_by_value]
70pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
71
72impl<'a> fmt::Debug for Layout<'a> {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        // See comment on `<LayoutData as Debug>::fmt` above.
75        self.0.0.fmt(f)
76    }
77}
78
79impl<'a> Deref for Layout<'a> {
80    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
81    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
82        &self.0.0
83    }
84}
85
86impl<'a> Layout<'a> {
87    pub fn fields(self) -> &'a FieldsShape<FieldIdx> {
88        &self.0.0.fields
89    }
90
91    pub fn variants(self) -> &'a Variants<FieldIdx, VariantIdx> {
92        &self.0.0.variants
93    }
94
95    pub fn backend_repr(self) -> BackendRepr {
96        self.0.0.backend_repr
97    }
98
99    pub fn largest_niche(self) -> Option<Niche> {
100        self.0.0.largest_niche
101    }
102
103    pub fn align(self) -> AbiAlign {
104        self.0.0.align
105    }
106
107    pub fn size(self) -> Size {
108        self.0.0.size
109    }
110
111    pub fn max_repr_align(self) -> Option<Align> {
112        self.0.0.max_repr_align
113    }
114
115    pub fn unadjusted_abi_align(self) -> Align {
116        self.0.0.unadjusted_abi_align
117    }
118}
119
120/// The layout of a type, alongside the type itself.
121/// Provides various type traversal APIs (e.g., recursing into fields).
122///
123/// Note that the layout is NOT guaranteed to always be identical
124/// to that obtained from `layout_of(ty)`, as we need to produce
125/// layouts for which Rust types do not exist, such as enum variants
126/// or synthetic fields of enums (i.e., discriminants) and wide pointers.
127#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
128pub struct TyAndLayout<'a, Ty> {
129    pub ty: Ty,
130    pub layout: Layout<'a>,
131}
132
133impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> {
134    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
135        // Print the type in a readable way, not its debug representation.
136        f.debug_struct("TyAndLayout")
137            .field("ty", &format_args!("{}", self.ty))
138            .field("layout", &self.layout)
139            .finish()
140    }
141}
142
143impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
144    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
145    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
146        &self.layout.0.0
147    }
148}
149
150impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
151    fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> {
152        &*self.layout.0.0
153    }
154}
155
156/// Trait that needs to be implemented by the higher-level type representation
157/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
158pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
159    fn ty_and_layout_for_variant(
160        this: TyAndLayout<'a, Self>,
161        cx: &C,
162        variant_index: VariantIdx,
163    ) -> TyAndLayout<'a, Self>;
164    fn ty_and_layout_field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> TyAndLayout<'a, Self>;
165    fn ty_and_layout_pointee_info_at(
166        this: TyAndLayout<'a, Self>,
167        cx: &C,
168        offset: Size,
169    ) -> Option<PointeeInfo>;
170    fn is_adt(this: TyAndLayout<'a, Self>) -> bool;
171    fn is_never(this: TyAndLayout<'a, Self>) -> bool;
172    fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
173    fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
174    fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
175    /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
176    fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
177}
178
179impl<'a, Ty> TyAndLayout<'a, Ty> {
180    pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
181    where
182        Ty: TyAbiInterface<'a, C>,
183    {
184        Ty::ty_and_layout_for_variant(self, cx, variant_index)
185    }
186
187    pub fn field<C>(self, cx: &C, i: usize) -> Self
188    where
189        Ty: TyAbiInterface<'a, C>,
190    {
191        Ty::ty_and_layout_field(self, cx, i)
192    }
193
194    pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
195    where
196        Ty: TyAbiInterface<'a, C>,
197    {
198        Ty::ty_and_layout_pointee_info_at(self, cx, offset)
199    }
200
201    pub fn is_single_fp_element<C>(self, cx: &C) -> bool
202    where
203        Ty: TyAbiInterface<'a, C>,
204        C: HasDataLayout,
205    {
206        match self.backend_repr {
207            BackendRepr::Scalar(scalar) => {
208                matches!(scalar.primitive(), Primitive::Float(Float::F32 | Float::F64))
209            }
210            BackendRepr::Memory { .. } => {
211                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
212                    self.field(cx, 0).is_single_fp_element(cx)
213                } else {
214                    false
215                }
216            }
217            _ => false,
218        }
219    }
220
221    pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool
222    where
223        Ty: TyAbiInterface<'a, C>,
224        C: HasDataLayout,
225    {
226        match self.backend_repr {
227            BackendRepr::SimdVector { .. } => self.size == expected_size,
228            BackendRepr::Memory { .. } => {
229                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
230                    self.field(cx, 0).is_single_vector_element(cx, expected_size)
231                } else {
232                    false
233                }
234            }
235            _ => false,
236        }
237    }
238
239    pub fn is_adt<C>(self) -> bool
240    where
241        Ty: TyAbiInterface<'a, C>,
242    {
243        Ty::is_adt(self)
244    }
245
246    pub fn is_never<C>(self) -> bool
247    where
248        Ty: TyAbiInterface<'a, C>,
249    {
250        Ty::is_never(self)
251    }
252
253    pub fn is_tuple<C>(self) -> bool
254    where
255        Ty: TyAbiInterface<'a, C>,
256    {
257        Ty::is_tuple(self)
258    }
259
260    pub fn is_unit<C>(self) -> bool
261    where
262        Ty: TyAbiInterface<'a, C>,
263    {
264        Ty::is_unit(self)
265    }
266
267    pub fn is_transparent<C>(self) -> bool
268    where
269        Ty: TyAbiInterface<'a, C>,
270    {
271        Ty::is_transparent(self)
272    }
273
274    /// If this method returns `true`, then this type should always have a `PassMode` of
275    /// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
276    /// non-Rustic ABI (this is true for structs annotated with the
277    /// `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute).
278    ///
279    /// This is used to replicate some of the behaviour of C array-to-pointer decay; however unlike
280    /// C any changes the caller makes to the passed value will not be reflected in the callee, so
281    /// the attribute is only useful for types where observing the value in the caller after the
282    /// function call isn't allowed (a.k.a. `va_list`).
283    ///
284    /// This function handles transparent types automatically.
285    pub fn pass_indirectly_in_non_rustic_abis<C>(mut self, cx: &C) -> bool
286    where
287        Ty: TyAbiInterface<'a, C> + Copy,
288    {
289        while self.is_transparent()
290            && let Some((_, field)) = self.non_1zst_field(cx)
291        {
292            self = field;
293        }
294
295        Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(self)
296    }
297
298    /// Finds the one field that is not a 1-ZST.
299    /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
300    pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(FieldIdx, Self)>
301    where
302        Ty: TyAbiInterface<'a, C> + Copy,
303    {
304        let mut found = None;
305        for field_idx in 0..self.fields.count() {
306            let field = self.field(cx, field_idx);
307            if field.is_1zst() {
308                continue;
309            }
310            if found.is_some() {
311                // More than one non-1-ZST field.
312                return None;
313            }
314            found = Some((FieldIdx::from_usize(field_idx), field));
315        }
316        found
317    }
318}