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    AbiAndPrefAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
9    PointeeInfo, Primitive, Scalar, Size, TargetDataLayout, 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
42rustc_index::newtype_index! {
43    /// The *source-order* index of a variant in a type.
44    ///
45    /// For enums, these are always `0..variant_count`, regardless of any
46    /// custom discriminants that may have been defined, and including any
47    /// variants that may end up uninhabited due to field types.  (Some of the
48    /// variants may not be present in a monomorphized ABI [`Variants`], but
49    /// those skipped variants are always counted when determining the *index*.)
50    ///
51    /// `struct`s, `tuples`, and `unions`s are considered to have a single variant
52    /// with variant index zero, aka [`FIRST_VARIANT`].
53    #[derive(HashStable_Generic)]
54    #[encodable]
55    #[orderable]
56    pub struct VariantIdx {
57        /// Equivalent to `VariantIdx(0)`.
58        const FIRST_VARIANT = 0;
59    }
60}
61#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
62#[rustc_pass_by_value]
63pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
64
65impl<'a> fmt::Debug for Layout<'a> {
66    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67        // See comment on `<LayoutS as Debug>::fmt` above.
68        self.0.0.fmt(f)
69    }
70}
71
72impl<'a> Deref for Layout<'a> {
73    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
74    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
75        &self.0.0
76    }
77}
78
79impl<'a> Layout<'a> {
80    pub fn fields(self) -> &'a FieldsShape<FieldIdx> {
81        &self.0.0.fields
82    }
83
84    pub fn variants(self) -> &'a Variants<FieldIdx, VariantIdx> {
85        &self.0.0.variants
86    }
87
88    pub fn backend_repr(self) -> BackendRepr {
89        self.0.0.backend_repr
90    }
91
92    pub fn largest_niche(self) -> Option<Niche> {
93        self.0.0.largest_niche
94    }
95
96    pub fn align(self) -> AbiAndPrefAlign {
97        self.0.0.align
98    }
99
100    pub fn size(self) -> Size {
101        self.0.0.size
102    }
103
104    pub fn max_repr_align(self) -> Option<Align> {
105        self.0.0.max_repr_align
106    }
107
108    pub fn unadjusted_abi_align(self) -> Align {
109        self.0.0.unadjusted_abi_align
110    }
111
112    /// Whether the layout is from a type that implements [`std::marker::PointerLike`].
113    ///
114    /// Currently, that means that the type is pointer-sized, pointer-aligned,
115    /// and has a initialized (non-union), scalar ABI.
116    pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool {
117        self.size() == data_layout.pointer_size
118            && self.align().abi == data_layout.pointer_align.abi
119            && matches!(self.backend_repr(), BackendRepr::Scalar(Scalar::Initialized { .. }))
120    }
121}
122
123/// The layout of a type, alongside the type itself.
124/// Provides various type traversal APIs (e.g., recursing into fields).
125///
126/// Note that the layout is NOT guaranteed to always be identical
127/// to that obtained from `layout_of(ty)`, as we need to produce
128/// layouts for which Rust types do not exist, such as enum variants
129/// or synthetic fields of enums (i.e., discriminants) and wide pointers.
130#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
131pub struct TyAndLayout<'a, Ty> {
132    pub ty: Ty,
133    pub layout: Layout<'a>,
134}
135
136impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> {
137    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138        // Print the type in a readable way, not its debug representation.
139        f.debug_struct("TyAndLayout")
140            .field("ty", &format_args!("{}", self.ty))
141            .field("layout", &self.layout)
142            .finish()
143    }
144}
145
146impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
147    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
148    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
149        &self.layout.0.0
150    }
151}
152
153impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
154    fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> {
155        &*self.layout.0.0
156    }
157}
158
159/// Trait that needs to be implemented by the higher-level type representation
160/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
161pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
162    fn ty_and_layout_for_variant(
163        this: TyAndLayout<'a, Self>,
164        cx: &C,
165        variant_index: VariantIdx,
166    ) -> TyAndLayout<'a, Self>;
167    fn ty_and_layout_field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> TyAndLayout<'a, Self>;
168    fn ty_and_layout_pointee_info_at(
169        this: TyAndLayout<'a, Self>,
170        cx: &C,
171        offset: Size,
172    ) -> Option<PointeeInfo>;
173    fn is_adt(this: TyAndLayout<'a, Self>) -> bool;
174    fn is_never(this: TyAndLayout<'a, Self>) -> bool;
175    fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
176    fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
177    fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
178}
179
180impl<'a, Ty> TyAndLayout<'a, Ty> {
181    pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
182    where
183        Ty: TyAbiInterface<'a, C>,
184    {
185        Ty::ty_and_layout_for_variant(self, cx, variant_index)
186    }
187
188    pub fn field<C>(self, cx: &C, i: usize) -> Self
189    where
190        Ty: TyAbiInterface<'a, C>,
191    {
192        Ty::ty_and_layout_field(self, cx, i)
193    }
194
195    pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
196    where
197        Ty: TyAbiInterface<'a, C>,
198    {
199        Ty::ty_and_layout_pointee_info_at(self, cx, offset)
200    }
201
202    pub fn is_single_fp_element<C>(self, cx: &C) -> bool
203    where
204        Ty: TyAbiInterface<'a, C>,
205        C: HasDataLayout,
206    {
207        match self.backend_repr {
208            BackendRepr::Scalar(scalar) => {
209                matches!(scalar.primitive(), Primitive::Float(Float::F32 | Float::F64))
210            }
211            BackendRepr::Memory { .. } => {
212                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
213                    self.field(cx, 0).is_single_fp_element(cx)
214                } else {
215                    false
216                }
217            }
218            _ => false,
219        }
220    }
221
222    pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool
223    where
224        Ty: TyAbiInterface<'a, C>,
225        C: HasDataLayout,
226    {
227        match self.backend_repr {
228            BackendRepr::SimdVector { .. } => self.size == expected_size,
229            BackendRepr::Memory { .. } => {
230                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
231                    self.field(cx, 0).is_single_vector_element(cx, expected_size)
232                } else {
233                    false
234                }
235            }
236            _ => false,
237        }
238    }
239
240    pub fn is_adt<C>(self) -> bool
241    where
242        Ty: TyAbiInterface<'a, C>,
243    {
244        Ty::is_adt(self)
245    }
246
247    pub fn is_never<C>(self) -> bool
248    where
249        Ty: TyAbiInterface<'a, C>,
250    {
251        Ty::is_never(self)
252    }
253
254    pub fn is_tuple<C>(self) -> bool
255    where
256        Ty: TyAbiInterface<'a, C>,
257    {
258        Ty::is_tuple(self)
259    }
260
261    pub fn is_unit<C>(self) -> bool
262    where
263        Ty: TyAbiInterface<'a, C>,
264    {
265        Ty::is_unit(self)
266    }
267
268    pub fn is_transparent<C>(self) -> bool
269    where
270        Ty: TyAbiInterface<'a, C>,
271    {
272        Ty::is_transparent(self)
273    }
274
275    /// Finds the one field that is not a 1-ZST.
276    /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
277    pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(usize, Self)>
278    where
279        Ty: TyAbiInterface<'a, C> + Copy,
280    {
281        let mut found = None;
282        for field_idx in 0..self.fields.count() {
283            let field = self.field(cx, field_idx);
284            if field.is_1zst() {
285                continue;
286            }
287            if found.is_some() {
288                // More than one non-1-ZST field.
289                return None;
290            }
291            found = Some((field_idx, field));
292        }
293        found
294    }
295}