Skip to main content

rustc_abi/layout/
ty.rs

1use std::fmt;
2use std::ops::{Deref, Range};
3
4use rustc_data_structures::intern::Interned;
5use rustc_data_structures::range_set::RangeSet;
6use rustc_macros::StableHash;
7
8use crate::layout::{FieldIdx, VariantIdx};
9use crate::{
10    AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche, Numeric,
11    PointeeInfo, Primitive, Size, Variants,
12};
13
14// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
15
16#[derive(#[automatically_derived]impl<'a> ::core::marker::Copy for Layout<'a> { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl<'a>
    ::core::clone::TrivialClone for Layout<'a> {
}
#[automatically_derived]impl<'a> ::core::clone::Clone for Layout<'a> {
    #[inline]
    fn clone(&self) -> Self {
        let _:
                ::core::clone::AssertParamIsClone<Interned<'a,
                LayoutData<FieldIdx, VariantIdx>>>;
        *self
    }
}Clone, #[automatically_derived]impl<'a> ::core::marker::StructuralPartialEq for
    Layout<'a> {
}
#[automatically_derived]impl<'a> ::core::cmp::PartialEq for Layout<'a> {
    #[inline]
    fn eq(&self, other: &Self) -> 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> ::rustc_data_structures::stable_hash::StableHash for
            Layout<'a> {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                match *self {
                    Layout(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash)]
17#[rustc_pass_by_value]
18pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);
19
20impl<'a> fmt::Debug for Layout<'a> {
21    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22        // See comment on `<LayoutData as Debug>::fmt` above.
23        self.0.0.fmt(f)
24    }
25}
26
27impl<'a> Deref for Layout<'a> {
28    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
29    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
30        &self.0.0
31    }
32}
33
34impl<'a> Layout<'a> {
35    pub fn fields(self) -> &'a FieldsShape<FieldIdx> {
36        &self.0.0.fields
37    }
38
39    pub fn variants(self) -> &'a Variants<FieldIdx, VariantIdx> {
40        &self.0.0.variants
41    }
42
43    pub fn backend_repr(self) -> BackendRepr {
44        self.0.0.backend_repr
45    }
46
47    pub fn largest_niche(self) -> Option<Niche> {
48        self.0.0.largest_niche
49    }
50
51    pub fn align(self) -> AbiAlign {
52        self.0.0.align
53    }
54
55    pub fn size(self) -> Size {
56        self.0.0.size
57    }
58
59    pub fn max_repr_align(self) -> Option<Align> {
60        self.0.0.max_repr_align
61    }
62
63    pub fn unadjusted_abi_align(self) -> Align {
64        self.0.0.unadjusted_abi_align
65    }
66}
67
68/// The layout of a type, alongside the type itself.
69/// Provides various type traversal APIs (e.g., recursing into fields).
70///
71/// Note that the layout is NOT guaranteed to always be identical
72/// to that obtained from `layout_of(ty)`, as we need to produce
73/// layouts for which Rust types do not exist, such as enum variants
74/// or synthetic fields of enums (i.e., discriminants) and wide pointers.
75#[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) -> Self {
        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::marker::StructuralPartialEq for TyAndLayout<'a, Ty> {
}
#[automatically_derived]impl<'a, Ty: ::core::cmp::PartialEq>
    ::core::cmp::PartialEq for TyAndLayout<'a, Ty> {
    #[inline]
    fn eq(&self, other: &Self) -> 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> ::rustc_data_structures::stable_hash::StableHash for
            TyAndLayout<'a, Ty> where
            Ty: ::rustc_data_structures::stable_hash::StableHash {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                match *self {
                    TyAndLayout { ty: ref __binding_0, layout: ref __binding_1 }
                        => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                        { __binding_1.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash)]
76pub struct TyAndLayout<'a, Ty> {
77    pub ty: Ty,
78    pub layout: Layout<'a>,
79}
80
81impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> {
82    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        // Print the type in a readable way, not its debug representation.
84        f.debug_struct("TyAndLayout")
85            .field("ty", &format_args!("{0}", self.ty)format_args!("{}", self.ty))
86            .field("layout", &self.layout)
87            .finish()
88    }
89}
90
91impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
92    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
93    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
94        &self.layout.0.0
95    }
96}
97
98impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
99    fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> {
100        &*self.layout.0.0
101    }
102}
103
104/// Trait that needs to be implemented by the higher-level type representation
105/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
106pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug + std::fmt::Display {
107    fn ty_and_layout_for_variant(
108        this: TyAndLayout<'a, Self>,
109        cx: &C,
110        variant_index: VariantIdx,
111    ) -> TyAndLayout<'a, Self>;
112    fn ty_and_layout_field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> TyAndLayout<'a, Self>;
113    fn ty_and_layout_pointee_info_at(
114        this: TyAndLayout<'a, Self>,
115        cx: &C,
116        offset: Size,
117    ) -> Option<PointeeInfo>;
118    fn is_adt(this: TyAndLayout<'a, Self>) -> bool;
119    fn is_enum(this: TyAndLayout<'a, Self>) -> bool;
120    fn is_never(this: TyAndLayout<'a, Self>) -> bool;
121    fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
122    fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
123    fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
124    fn is_complex_number_lang_item(this: TyAndLayout<'a, Self>, cx: &C) -> bool;
125    fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool;
126    /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
127    fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
128}
129
130impl<'a, Ty> TyAndLayout<'a, Ty> {
131    /// Synthetize a layout representing the variant-specific fields of an enum-like layout.
132    ///
133    /// Note that the resulting layout *does not* fully describes `self.ty` at that specific
134    /// variant: prefix fields (e.g. in coroutines) and tag information are lost.
135    ///
136    /// If you don't need type information about the variant's fields, prefer using
137    /// `self.layout.variants` directly.
138    pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
139    where
140        Ty: TyAbiInterface<'a, C>,
141    {
142        Ty::ty_and_layout_for_variant(self, cx, variant_index)
143    }
144
145    pub fn field<C>(self, cx: &C, i: usize) -> Self
146    where
147        Ty: TyAbiInterface<'a, C>,
148    {
149        Ty::ty_and_layout_field(self, cx, i)
150    }
151
152    pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
153    where
154        Ty: TyAbiInterface<'a, C>,
155    {
156        Ty::ty_and_layout_pointee_info_at(self, cx, offset)
157    }
158
159    pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool
160    where
161        Ty: TyAbiInterface<'a, C>,
162        C: HasDataLayout,
163    {
164        match self.backend_repr {
165            BackendRepr::SimdVector { .. } => self.size == expected_size,
166            BackendRepr::Memory { .. } => {
167                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
168                    self.field(cx, 0).is_single_vector_element(cx, expected_size)
169                } else {
170                    false
171                }
172            }
173            _ => false,
174        }
175    }
176
177    pub fn is_adt<C>(self) -> bool
178    where
179        Ty: TyAbiInterface<'a, C>,
180    {
181        Ty::is_adt(self)
182    }
183
184    pub fn is_enum<C>(self) -> bool
185    where
186        Ty: TyAbiInterface<'a, C>,
187    {
188        Ty::is_enum(self)
189    }
190
191    pub fn is_never<C>(self) -> bool
192    where
193        Ty: TyAbiInterface<'a, C>,
194    {
195        Ty::is_never(self)
196    }
197
198    pub fn is_tuple<C>(self) -> bool
199    where
200        Ty: TyAbiInterface<'a, C>,
201    {
202        Ty::is_tuple(self)
203    }
204
205    pub fn is_unit<C>(self) -> bool
206    where
207        Ty: TyAbiInterface<'a, C>,
208    {
209        Ty::is_unit(self)
210    }
211
212    pub fn is_transparent<C>(self) -> bool
213    where
214        Ty: TyAbiInterface<'a, C>,
215    {
216        Ty::is_transparent(self)
217    }
218
219    /// Returns `true` if this type needs to match the ABI of the C `_Complex` type. See
220    /// [`TyAndLayout::complex_number`] for details.
221    pub fn is_complex_number<C>(self, cx: &C) -> bool
222    where
223        Ty: TyAbiInterface<'a, C> + Copy,
224    {
225        self.complex_number(cx).is_some()
226    }
227
228    pub fn is_scalable_vector<C>(self) -> bool
229    where
230        Ty: TyAbiInterface<'a, C>,
231    {
232        Ty::is_scalable_vector(self)
233    }
234
235    /// If this method returns `true`, then this type should always have a `PassMode` of
236    /// `Indirect { mode: IndirectMode::Pointer, .. }` when being used as the argument type of a
237    /// function with a non-Rustic ABI (this is true for structs annotated with the
238    /// `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute).
239    ///
240    /// This is used to replicate some of the behaviour of C array-to-pointer decay; however unlike
241    /// C any changes the caller makes to the passed value will not be reflected in the callee, so
242    /// the attribute is only useful for types where observing the value in the caller after the
243    /// function call isn't allowed (a.k.a. `va_list`).
244    ///
245    /// This function handles transparent types automatically.
246    pub fn pass_indirectly_in_non_rustic_abis<C>(self, cx: &C) -> bool
247    where
248        Ty: TyAbiInterface<'a, C> + Copy,
249    {
250        // FIXME: Peeling the wrappers above would not work correctly if we are a 1-ZST. So we make
251        // `#[rustc_pass_indirectly_in_non_rustic_abis]` a NOP on 1-ZST. In the future,
252        // `non_1zst_field` should become `non_trivial_abi_field` and
253        // `#[rustc_pass_indirectly_in_non_rustic_abis]` should make a type have non-trivial ABI.
254        if self.is_1zst() {
255            return false;
256        }
257
258        let base = self.peel_transparent_wrappers_from_non_1zst(cx);
259        Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(base)
260    }
261
262    /// Recursively peel away transparent wrappers, returning the inner value.
263    /// Will not peel anything if `self` is a 1-ZST! Callers need to either check
264    /// that the result is not a 1-ZST, or have separate logic for that.
265    ///
266    /// The return value is not `repr(transparent)` and/or does
267    /// not have a non-1zst field.
268    pub fn peel_transparent_wrappers_from_non_1zst<C>(mut self, cx: &C) -> Self
269    where
270        Ty: TyAbiInterface<'a, C> + Copy,
271    {
272        while self.is_transparent()
273            && let Some((_, field)) = self.non_1zst_field(cx)
274        {
275            self = field;
276        }
277
278        self
279    }
280
281    /// Finds the one field that is not a 1-ZST.
282    /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
283    pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(FieldIdx, Self)>
284    where
285        Ty: TyAbiInterface<'a, C> + Copy,
286    {
287        let mut found = None;
288        for field_idx in 0..self.fields.count() {
289            let field = self.field(cx, field_idx);
290            if field.is_1zst() {
291                continue;
292            }
293            if found.is_some() {
294                // More than one non-1-ZST field.
295                return None;
296            }
297            found = Some((FieldIdx::from_usize(field_idx), field));
298        }
299        found
300    }
301
302    /// Finds the one field that is not a ZST.
303    /// Returns `None` if there are multiple non-ZST fields or only ZST-fields.
304    ///
305    /// Note that this function checks for ZSTs, not just 1-ZSTs.
306    pub fn non_zst_field_ignore_alignment<C>(&self, cx: &C) -> Option<(FieldIdx, Self)>
307    where
308        Ty: TyAbiInterface<'a, C> + Copy,
309    {
310        let mut found = None;
311        for field_idx in 0..self.fields.count() {
312            let field = self.field(cx, field_idx);
313            if field.is_zst() {
314                continue;
315            }
316            if found.is_some() {
317                // More than one non-ZST field.
318                return None;
319            }
320            found = Some((FieldIdx::from_usize(field_idx), field));
321        }
322        found
323    }
324
325    /// If this type should match the ABI of the C `_Complex` type, returns the primitive that is
326    /// used for its components.
327    ///
328    /// This function only returns `Some(T)` for `core::num::Complex<T>` where `T` is
329    /// either a float or an integer. `repr(transparent)` wrapper types are automatically handled.
330    pub fn complex_number<C>(&self, cx: &C) -> Option<Numeric>
331    where
332        Ty: TyAbiInterface<'a, C> + Copy,
333    {
334        // We're checking for scalar repr below which excludes 1-ZST.
335        let complex = self.peel_transparent_wrappers_from_non_1zst(cx);
336        if !Ty::is_complex_number_lang_item(complex, cx) {
337            return None;
338        }
339
340        let component = complex.field(cx, 0).peel_transparent_wrappers_from_non_1zst(cx);
341
342        let BackendRepr::Scalar(scalar) = component.backend_repr else {
343            return None;
344        };
345
346        // Only Complex<{ float }> and Complex<{ integer }> have special layout.
347        //
348        // Explicitly spell out all the float types so that any new ones have to be added to
349        // one of the match branches.
350        let primitive = scalar.primitive();
351        match primitive {
352            Primitive::Int(integer, is_signed) => Some(Numeric::Int(integer, is_signed)),
353            Primitive::Float(
354                float @ (Float::F16 | Float::F32 | Float::F64 | Float::F128 | Float::PpcF128),
355            ) => Some(Numeric::Float(float)),
356            Primitive::Pointer(..) | Primitive::Float(Float::F16B) => None,
357        }
358    }
359
360    /// Returns `Some` if this type has the ABI of the C `_Complex` type with float components.
361    /// See [`TyAndLayout::complex_number`] for details.
362    pub fn complex_float<C>(&self, cx: &C) -> Option<Float>
363    where
364        Ty: TyAbiInterface<'a, C> + Copy,
365    {
366        match self.complex_number(cx) {
367            Some(Numeric::Float(float)) => Some(float),
368            _ => None,
369        }
370    }
371
372    /// Whether this type/layout has any padding that is dependent on a variant, i.e. has bytes that
373    /// are padding for some, but not all, valid values of this type.
374    pub fn has_variant_dependent_padding<C>(&self, cx: &C) -> bool
375    where
376        Ty: TyAbiInterface<'a, C> + Copy,
377    {
378        match self.variants {
379            Variants::Multiple { .. } => true,
380            Variants::Empty => false,
381            Variants::Single { .. } => match &self.fields {
382                FieldsShape::Primitive | FieldsShape::Union(_) => false,
383                FieldsShape::Array { count, .. } => {
384                    *count > 0 && self.field(cx, 0).has_variant_dependent_padding(cx)
385                }
386                FieldsShape::Arbitrary { offsets, .. } => {
387                    (0..offsets.len()).any(|i| self.field(cx, i).has_variant_dependent_padding(cx))
388                }
389            },
390        }
391    }
392
393    /// The ranges of bytes that are always ignored by the representation relation of this type.
394    ///
395    /// In other words, for any sequence of bytes, if we reset the these padding bytes to uninit,
396    /// then these two sequences of bytes represent the same value (or they are both invalid).
397    /// This is the "guaranteed" padding. There may be more bytes that are padding for some
398    /// but not all variants of this type; those are not included.
399    /// (E.g. `Option<i8>` has no guaranteed padding so the empty range set is returned, but its `None` value still has padding).
400    pub fn variant_independent_padding_ranges<C>(&self, cx: &C) -> Vec<Range<Size>>
401    where
402        Ty: TyAbiInterface<'a, C> + Copy,
403    {
404        let mut data = RangeSet::new();
405        self.add_data_ranges(cx, Size::ZERO, &mut data);
406
407        // Find gaps between the data ranges.
408        let mut uninit_ranges = Vec::new();
409        let mut covered_until = Size::ZERO;
410        for &(offset, size) in data.0.iter() {
411            if offset > covered_until {
412                uninit_ranges.push(covered_until..offset);
413            }
414            covered_until = Ord::max(covered_until, offset + size);
415        }
416
417        // Add trailing padding.
418        if self.size > covered_until {
419            uninit_ranges.push(covered_until..self.size);
420        }
421
422        uninit_ranges
423    }
424
425    /// The ranges of bytes that are ignored by the representation relation of this variant.
426    ///
427    /// The result does not include variant-independent padding.
428    pub fn variant_dependent_padding_ranges<C>(
429        &self,
430        cx: &C,
431        variant_index: VariantIdx,
432    ) -> Vec<Range<Size>>
433    where
434        Ty: TyAbiInterface<'a, C> + Copy,
435    {
436        let Variants::Multiple { .. } = self.variants else {
437            return Vec::new();
438        };
439
440        // Bytes that are data in some variant.
441        let mut any = RangeSet::new();
442        self.add_data_ranges(cx, Size::ZERO, &mut any);
443
444        // Bytes that are data in this variant.
445        let mut this = RangeSet::new();
446
447        // The variants do not contain e.g. the discriminant or coroutine upvars.
448        let FieldsShape::Arbitrary { offsets, in_memory_order: _ } = &self.fields else {
449            {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("a multi-variant layout should have `Arbitrary` fields")));
}unreachable!("a multi-variant layout should have `Arbitrary` fields")
450        };
451
452        // So add them explicitly.
453        for (field, &offset) in offsets.iter_enumerated() {
454            let field = self.field(cx, field.as_usize());
455            field.add_data_ranges(cx, offset, &mut this);
456        }
457
458        self.for_variant(cx, variant_index).add_data_ranges(cx, Size::ZERO, &mut this);
459
460        // Padding specific to this variant: data in some variant, but not in this one.
461        any.difference(&this).0.iter().map(|&(offset, size)| offset..offset + size).collect()
462    }
463
464    /// Extend `out` with all ranges of bytes that *may* carry relevant data for values of this type.
465    /// For enums and unions there are offsets that are initialized for some
466    /// variants but not for others; those offset *will* get added to `out`.
467    fn add_data_ranges<C>(self, cx: &C, base_offset: Size, out: &mut RangeSet<Size>)
468    where
469        Ty: TyAbiInterface<'a, C> + Copy,
470    {
471        if self.is_zst() {
472            return;
473        }
474
475        // Visit the fields of this value. For enum values the fields include the discriminant.
476        match &self.fields {
477            FieldsShape::Primitive => {
478                out.add_range(base_offset, self.size);
479            }
480            &FieldsShape::Union(field_count) => {
481                for field in 0..field_count.get() {
482                    let field = self.field(cx, field);
483                    field.add_data_ranges(cx, base_offset, out);
484                }
485            }
486            &FieldsShape::Array { stride, count } => {
487                let elem = self.field(cx, 0);
488
489                // For scalars we know there is no padding between the elements,
490                // so the entire array is a single big data range.
491                if elem.backend_repr.is_scalar() {
492                    out.add_range(base_offset, elem.size * count);
493                } else {
494                    // FIXME: this is really inefficient for large arrays.
495                    for idx in 0..count {
496                        elem.add_data_ranges(cx, base_offset + idx * stride, out);
497                    }
498                }
499            }
500            FieldsShape::Arbitrary { offsets, in_memory_order: _ } => {
501                for (field, &offset) in offsets.iter_enumerated() {
502                    let field = self.field(cx, field.as_usize());
503                    field.add_data_ranges(cx, base_offset + offset, out);
504                }
505            }
506        }
507
508        // Visit the fields of each variant.
509        match &self.variants {
510            Variants::Empty | Variants::Single { index: _ } => { /* done */ }
511            Variants::Multiple { variants, .. } => {
512                for variant in variants.indices() {
513                    let variant = self.for_variant(cx, variant);
514                    variant.add_data_ranges(cx, base_offset, out);
515                }
516            }
517        }
518    }
519}