Skip to main content

rustc_transmute/layout/
tree.rs

1use std::ops::{ControlFlow, RangeInclusive};
2
3use super::{Byte, Def, Reference, Region, Type};
4
5#[cfg(test)]
6mod tests;
7
8/// A tree-based representation of a type layout.
9///
10/// Invariants:
11/// 1. All paths through the layout have the same length (in bytes).
12///
13/// Nice-to-haves:
14/// 1. An `Alt` is never directly nested beneath another `Alt`.
15/// 2. A `Seq` is never directly nested beneath another `Seq`.
16/// 3. `Seq`s and `Alt`s with a single member do not exist.
17#[derive(#[automatically_derived]
impl<D: ::core::clone::Clone, R: ::core::clone::Clone,
    T: ::core::clone::Clone> ::core::clone::Clone for Tree<D, R, T> where
    D: Def, R: Region, T: Type {
    #[inline]
    fn clone(&self) -> Tree<D, R, T> {
        match self {
            Tree::Seq(__self_0) =>
                Tree::Seq(::core::clone::Clone::clone(__self_0)),
            Tree::Alt(__self_0) =>
                Tree::Alt(::core::clone::Clone::clone(__self_0)),
            Tree::Def(__self_0) =>
                Tree::Def(::core::clone::Clone::clone(__self_0)),
            Tree::Ref(__self_0) =>
                Tree::Ref(::core::clone::Clone::clone(__self_0)),
            Tree::Byte(__self_0) =>
                Tree::Byte(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl<D: ::core::fmt::Debug, R: ::core::fmt::Debug, T: ::core::fmt::Debug>
    ::core::fmt::Debug for Tree<D, R, T> where D: Def, R: Region, T: Type {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Tree::Seq(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Seq",
                    &__self_0),
            Tree::Alt(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Alt",
                    &__self_0),
            Tree::Def(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Def",
                    &__self_0),
            Tree::Ref(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Ref",
                    &__self_0),
            Tree::Byte(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Byte",
                    &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl<D: ::core::hash::Hash, R: ::core::hash::Hash, T: ::core::hash::Hash>
    ::core::hash::Hash for Tree<D, R, T> where D: Def, R: Region, T: Type {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            Tree::Seq(__self_0) => ::core::hash::Hash::hash(__self_0, state),
            Tree::Alt(__self_0) => ::core::hash::Hash::hash(__self_0, state),
            Tree::Def(__self_0) => ::core::hash::Hash::hash(__self_0, state),
            Tree::Ref(__self_0) => ::core::hash::Hash::hash(__self_0, state),
            Tree::Byte(__self_0) => ::core::hash::Hash::hash(__self_0, state),
        }
    }
}Hash, #[automatically_derived]
impl<D: ::core::cmp::PartialEq, R: ::core::cmp::PartialEq,
    T: ::core::cmp::PartialEq> ::core::cmp::PartialEq for Tree<D, R, T> where
    D: Def, R: Region, T: Type {
    #[inline]
    fn eq(&self, other: &Tree<D, R, T>) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (Tree::Seq(__self_0), Tree::Seq(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Tree::Alt(__self_0), Tree::Alt(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Tree::Def(__self_0), Tree::Def(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Tree::Ref(__self_0), Tree::Ref(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Tree::Byte(__self_0), Tree::Byte(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq, #[automatically_derived]
impl<D: ::core::cmp::Eq, R: ::core::cmp::Eq, T: ::core::cmp::Eq>
    ::core::cmp::Eq for Tree<D, R, T> where D: Def, R: Region, T: Type {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Vec<Self>>;
        let _: ::core::cmp::AssertParamIsEq<Vec<Self>>;
        let _: ::core::cmp::AssertParamIsEq<D>;
        let _: ::core::cmp::AssertParamIsEq<Reference<R, T>>;
        let _: ::core::cmp::AssertParamIsEq<Byte>;
    }
}Eq)]
18pub(crate) enum Tree<D, R, T>
19where
20    D: Def,
21    R: Region,
22    T: Type,
23{
24    /// A sequence of successive layouts.
25    Seq(Vec<Self>),
26    /// A choice between alternative layouts.
27    Alt(Vec<Self>),
28    /// A definition node.
29    Def(D),
30    /// A reference node.
31    Ref(Reference<R, T>),
32    /// A byte node.
33    Byte(Byte),
34}
35
36#[derive(#[automatically_derived]
impl ::core::fmt::Debug for Endian {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self { Endian::Little => "Little", Endian::Big => "Big", })
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for Endian { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Endian {
    #[inline]
    fn clone(&self) -> Endian { *self }
}Clone, #[automatically_derived]
impl ::core::cmp::Eq for Endian {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::cmp::PartialEq for Endian {
    #[inline]
    fn eq(&self, other: &Endian) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq)]
37pub(crate) enum Endian {
38    Little,
39    Big,
40}
41
42#[cfg(feature = "rustc")]
43impl From<rustc_abi::Endian> for Endian {
44    fn from(order: rustc_abi::Endian) -> Endian {
45        match order {
46            rustc_abi::Endian::Little => Endian::Little,
47            rustc_abi::Endian::Big => Endian::Big,
48        }
49    }
50}
51
52impl<D, R, T> Tree<D, R, T>
53where
54    D: Def,
55    R: Region,
56    T: Type,
57{
58    /// A `Tree` consisting only of a definition node.
59    pub(crate) fn def(def: D) -> Self {
60        Self::Def(def)
61    }
62
63    /// A `Tree` representing an uninhabited type.
64    pub(crate) fn uninhabited() -> Self {
65        Self::Alt(::alloc::vec::Vec::new()vec![])
66    }
67
68    /// A `Tree` representing a zero-sized type.
69    pub(crate) fn unit() -> Self {
70        Self::Seq(Vec::new())
71    }
72
73    /// A `Tree` containing a single, uninitialized byte.
74    pub(crate) fn uninit() -> Self {
75        Self::Byte(Byte::uninit())
76    }
77
78    /// A `Tree` representing the layout of `bool`.
79    pub(crate) fn bool() -> Self {
80        Self::byte(0x00..=0x01)
81    }
82
83    /// A `Tree` whose layout matches that of a `u8`.
84    pub(crate) fn u8() -> Self {
85        Self::byte(0x00..=0xFF)
86    }
87
88    /// A `Tree` whose layout matches that of a `char`.
89    pub(crate) fn char(order: Endian) -> Self {
90        // `char`s can be in the following ranges:
91        // - [0, 0xD7FF]
92        // - [0xE000, 10FFFF]
93        //
94        // All other `char` values are illegal. We can thus represent a `char`
95        // as a union of three possible layouts:
96        // - 00 00 [00, D7] XX
97        // - 00 00 [E0, FF] XX
98        // - 00 [01, 10] XX XX
99
100        const _0: RangeInclusive<u8> = 0..=0;
101        const BYTE: RangeInclusive<u8> = 0x00..=0xFF;
102        let x = Self::from_big_endian(order, [_0, _0, 0x00..=0xD7, BYTE]);
103        let y = Self::from_big_endian(order, [_0, _0, 0xE0..=0xFF, BYTE]);
104        let z = Self::from_big_endian(order, [_0, 0x01..=0x10, BYTE, BYTE]);
105        Self::alt([x, y, z])
106    }
107
108    /// A `Tree` whose layout matches `std::num::NonZeroXxx`.
109    #[allow(dead_code)]
110    pub(crate) fn nonzero(width_in_bytes: u64) -> Self {
111        const BYTE: RangeInclusive<u8> = 0x00..=0xFF;
112        const NONZERO: RangeInclusive<u8> = 0x01..=0xFF;
113
114        (0..width_in_bytes)
115            .map(|nz_idx| {
116                (0..width_in_bytes)
117                    .map(|pos| Self::byte(if pos == nz_idx { NONZERO } else { BYTE }))
118                    .fold(Self::unit(), Self::then)
119            })
120            .fold(Self::uninhabited(), Self::or)
121    }
122
123    pub(crate) fn bytes<const N: usize, B: Into<Byte>>(bytes: [B; N]) -> Self {
124        Self::seq(bytes.map(B::into).map(Self::Byte))
125    }
126
127    pub(crate) fn byte(byte: impl Into<Byte>) -> Self {
128        Self::Byte(byte.into())
129    }
130
131    /// A `Tree` whose layout is a number of the given width.
132    pub(crate) fn number(width_in_bytes: u64) -> Self {
133        Self::Seq(::alloc::vec::from_elem(Self::u8(), width_in_bytes.try_into().unwrap())vec![Self::u8(); width_in_bytes.try_into().unwrap()])
134    }
135
136    /// A `Tree` whose layout is entirely padding of the given width.
137    pub(crate) fn padding(width_in_bytes: usize) -> Self {
138        Self::Seq(::alloc::vec::from_elem(Self::uninit(), width_in_bytes)vec![Self::uninit(); width_in_bytes])
139    }
140
141    /// Remove all `Def` nodes, and all branches of the layout for which `f`
142    /// produces `true`.
143    pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R, T>
144    where
145        F: Fn(D) -> bool,
146    {
147        match self {
148            Self::Seq(elts) => match elts.into_iter().map(|elt| elt.prune(f)).try_fold(
149                Tree::unit(),
150                |elts, elt| {
151                    if elt == Tree::uninhabited() {
152                        ControlFlow::Break(Tree::uninhabited())
153                    } else {
154                        ControlFlow::Continue(elts.then(elt))
155                    }
156                },
157            ) {
158                ControlFlow::Break(node) | ControlFlow::Continue(node) => node,
159            },
160            Self::Alt(alts) => alts
161                .into_iter()
162                .map(|alt| alt.prune(f))
163                .fold(Tree::uninhabited(), |alts, alt| alts.or(alt)),
164            Self::Byte(b) => Tree::Byte(b),
165            Self::Ref(r) => Tree::Ref(r),
166            Self::Def(d) => {
167                if f(d) {
168                    Tree::uninhabited()
169                } else {
170                    Tree::unit()
171                }
172            }
173        }
174    }
175
176    /// Produces `true` if `Tree` is an inhabited type; otherwise false.
177    pub(crate) fn is_inhabited(&self) -> bool {
178        match self {
179            Self::Seq(elts) => elts.into_iter().all(|elt| elt.is_inhabited()),
180            Self::Alt(alts) => alts.into_iter().any(|alt| alt.is_inhabited()),
181            Self::Byte(..) | Self::Ref(..) | Self::Def(..) => true,
182        }
183    }
184
185    /// Produces a `Tree` which represents a sequence of bytes stored in
186    /// `order`.
187    ///
188    /// `bytes` is taken to be in big-endian byte order, and its order will be
189    /// swapped if `order == Endian::Little`.
190    pub(crate) fn from_big_endian<const N: usize, B: Into<Byte>>(
191        order: Endian,
192        mut bytes: [B; N],
193    ) -> Self {
194        if order == Endian::Little {
195            (&mut bytes[..]).reverse();
196        }
197
198        Self::bytes(bytes)
199    }
200
201    /// Produces a `Tree` where each of the trees in `trees` are sequenced one
202    /// after another.
203    pub(crate) fn seq<const N: usize>(trees: [Tree<D, R, T>; N]) -> Self {
204        trees.into_iter().fold(Tree::unit(), Self::then)
205    }
206
207    /// Produces a `Tree` where each of the trees in `trees` are accepted as
208    /// alternative layouts.
209    pub(crate) fn alt<const N: usize>(trees: [Tree<D, R, T>; N]) -> Self {
210        trees.into_iter().fold(Tree::uninhabited(), Self::or)
211    }
212
213    /// Produces a new `Tree` where `other` is sequenced after `self`.
214    pub(crate) fn then(self, other: Self) -> Self {
215        match (self, other) {
216            (Self::Seq(elts), other) | (other, Self::Seq(elts)) if elts.len() == 0 => other,
217            (Self::Seq(mut lhs), Self::Seq(mut rhs)) => {
218                lhs.append(&mut rhs);
219                Self::Seq(lhs)
220            }
221            (Self::Seq(mut lhs), rhs) => {
222                lhs.push(rhs);
223                Self::Seq(lhs)
224            }
225            (lhs, Self::Seq(mut rhs)) => {
226                rhs.insert(0, lhs);
227                Self::Seq(rhs)
228            }
229            (lhs, rhs) => Self::Seq(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [lhs, rhs]))vec![lhs, rhs]),
230        }
231    }
232
233    /// Produces a new `Tree` accepting either `self` or `other` as alternative layouts.
234    pub(crate) fn or(self, other: Self) -> Self {
235        match (self, other) {
236            (Self::Alt(alts), other) | (other, Self::Alt(alts)) if alts.len() == 0 => other,
237            (Self::Alt(mut lhs), Self::Alt(rhs)) => {
238                lhs.extend(rhs);
239                Self::Alt(lhs)
240            }
241            (Self::Alt(mut alts), alt) | (alt, Self::Alt(mut alts)) => {
242                alts.push(alt);
243                Self::Alt(alts)
244            }
245            (lhs, rhs) => Self::Alt(::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [lhs, rhs]))vec![lhs, rhs]),
246        }
247    }
248}
249
250#[cfg(feature = "rustc")]
251pub(crate) mod rustc {
252    use rustc_abi::{
253        FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants,
254    };
255    use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
256    use rustc_middle::ty::{
257        self, AdtDef, AdtKind, List, Region, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
258    };
259    use rustc_span::ErrorGuaranteed;
260
261    use super::Tree;
262    use crate::layout::Reference;
263    use crate::layout::rustc::{Def, layout_of};
264
265    #[derive(#[automatically_derived]
impl ::core::fmt::Debug for Err {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Err::NotYetSupported =>
                ::core::fmt::Formatter::write_str(f, "NotYetSupported"),
            Err::UnknownLayout =>
                ::core::fmt::Formatter::write_str(f, "UnknownLayout"),
            Err::SizeOverflow =>
                ::core::fmt::Formatter::write_str(f, "SizeOverflow"),
            Err::TypeError(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "TypeError", &__self_0),
        }
    }
}Debug, #[automatically_derived]
impl ::core::marker::Copy for Err { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Err {
    #[inline]
    fn clone(&self) -> Err {
        let _: ::core::clone::AssertParamIsClone<ErrorGuaranteed>;
        *self
    }
}Clone)]
266    pub(crate) enum Err {
267        /// The layout of the type is not yet supported.
268        NotYetSupported,
269        /// This error will be surfaced elsewhere by rustc, so don't surface it.
270        UnknownLayout,
271        /// Overflow size
272        SizeOverflow,
273        TypeError(ErrorGuaranteed),
274    }
275
276    impl<'tcx> From<&LayoutError<'tcx>> for Err {
277        fn from(err: &LayoutError<'tcx>) -> Self {
278            match err {
279                LayoutError::Unknown(..)
280                | LayoutError::ReferencesError(..)
281                | LayoutError::TooGeneric(..)
282                | LayoutError::InvalidSimd { .. }
283                | LayoutError::NormalizationFailure(..) => Self::UnknownLayout,
284                LayoutError::SizeOverflow(..) => Self::SizeOverflow,
285            }
286        }
287    }
288
289    impl<'tcx> Tree<Def<'tcx>, Region<'tcx>, Ty<'tcx>> {
290        pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx>) -> Result<Self, Err> {
291            use rustc_abi::HasDataLayout;
292            let layout = layout_of(cx, ty)?;
293
294            if let Err(e) = ty.error_reported() {
295                return Err(Err::TypeError(e));
296            }
297
298            let target = cx.data_layout();
299            let pointer_size = target.pointer_size();
300
301            match ty.kind() {
302                ty::Bool => Ok(Self::bool()),
303
304                ty::Float(nty) => {
305                    let width = nty.bit_width() / 8;
306                    Ok(Self::number(width.try_into().unwrap()))
307                }
308
309                ty::Int(nty) => {
310                    let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8;
311                    Ok(Self::number(width.try_into().unwrap()))
312                }
313
314                ty::Uint(nty) => {
315                    let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8;
316                    Ok(Self::number(width.try_into().unwrap()))
317                }
318
319                ty::Tuple(members) => Self::from_tuple((ty, layout), members, cx),
320
321                ty::Array(inner_ty, _len) => {
322                    let FieldsShape::Array { stride, count } = &layout.fields else {
323                        return Err(Err::NotYetSupported);
324                    };
325                    let inner_layout = layout_of(cx, *inner_ty)?;
326                    match (&*stride, &inner_layout.size) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(*stride, inner_layout.size);
327                    let elt = Tree::from_ty(*inner_ty, cx)?;
328                    Ok(std::iter::repeat_n(elt, *count as usize)
329                        .fold(Tree::unit(), |tree, elt| tree.then(elt)))
330                }
331
332                ty::Adt(adt_def, _args_ref) if !ty.is_box() => {
333                    let (lo, hi) = cx.tcx().layout_scalar_valid_range(adt_def.did());
334
335                    use core::ops::Bound::*;
336                    let is_transparent = adt_def.repr().transparent();
337                    match (adt_def.adt_kind(), lo, hi) {
338                        (AdtKind::Struct, Unbounded, Unbounded) => {
339                            Self::from_struct((ty, layout), *adt_def, cx)
340                        }
341                        (AdtKind::Struct, Included(1), Included(_hi)) if is_transparent => {
342                            // FIXME(@joshlf): Support `NonZero` types:
343                            // - Check to make sure that the first field is
344                            //   numerical
345                            // - Check to make sure that the upper bound is the
346                            //   maximum value for the field's type
347                            // - Construct `Self::nonzero`
348                            Err(Err::NotYetSupported)
349                        }
350                        (AdtKind::Enum, Unbounded, Unbounded) => {
351                            Self::from_enum((ty, layout), *adt_def, cx)
352                        }
353                        (AdtKind::Union, Unbounded, Unbounded) => {
354                            Self::from_union((ty, layout), *adt_def, cx)
355                        }
356                        _ => Err(Err::NotYetSupported),
357                    }
358                }
359
360                ty::Ref(region, ty, mutability) => {
361                    let layout = layout_of(cx, *ty)?;
362                    let referent_align = layout.align.bytes_usize();
363                    let referent_size = layout.size.bytes_usize();
364
365                    Ok(Tree::Ref(Reference {
366                        region: *region,
367                        is_mut: mutability.is_mut(),
368                        referent: *ty,
369                        referent_align,
370                        referent_size,
371                    }))
372                }
373
374                ty::Char => Ok(Self::char(cx.tcx().data_layout.endian.into())),
375
376                _ => Err(Err::NotYetSupported),
377            }
378        }
379
380        /// Constructs a `Tree` from a tuple.
381        fn from_tuple(
382            (ty, layout): (Ty<'tcx>, Layout<'tcx>),
383            members: &'tcx List<Ty<'tcx>>,
384            cx: LayoutCx<'tcx>,
385        ) -> Result<Self, Err> {
386            match &layout.fields {
387                FieldsShape::Primitive => {
388                    match (&members.len(), &1) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(members.len(), 1);
389                    let inner_ty = members[0];
390                    Self::from_ty(inner_ty, cx)
391                }
392                FieldsShape::Arbitrary { offsets, .. } => {
393                    match (&offsets.len(), &members.len()) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(offsets.len(), members.len());
394                    Self::from_variant(Def::Primitive, None, (ty, layout), layout.size, cx)
395                }
396                FieldsShape::Array { .. } | FieldsShape::Union(_) => Err(Err::NotYetSupported),
397            }
398        }
399
400        /// Constructs a `Tree` from a struct.
401        ///
402        /// # Panics
403        ///
404        /// Panics if `def` is not a struct definition.
405        fn from_struct(
406            (ty, layout): (Ty<'tcx>, Layout<'tcx>),
407            def: AdtDef<'tcx>,
408            cx: LayoutCx<'tcx>,
409        ) -> Result<Self, Err> {
410            if !def.is_struct() {
    ::core::panicking::panic("assertion failed: def.is_struct()")
};assert!(def.is_struct());
411            let def = Def::Adt(def);
412            Self::from_variant(def, None, (ty, layout), layout.size, cx)
413        }
414
415        /// Constructs a `Tree` from an enum.
416        ///
417        /// # Panics
418        ///
419        /// Panics if `def` is not an enum definition.
420        fn from_enum(
421            (ty, layout): (Ty<'tcx>, Layout<'tcx>),
422            def: AdtDef<'tcx>,
423            cx: LayoutCx<'tcx>,
424        ) -> Result<Self, Err> {
425            if !def.is_enum() {
    ::core::panicking::panic("assertion failed: def.is_enum()")
};assert!(def.is_enum());
426
427            // Computes the layout of a variant.
428            let layout_of_variant = |index, encoding: Option<_>| -> Result<Self, Err> {
429                let variant_layout = ty_variant(cx, (ty, layout), index);
430                if variant_layout.is_uninhabited() {
431                    return Ok(Self::uninhabited());
432                }
433                let tag = cx.tcx().tag_for_variant(
434                    cx.typing_env.as_query_input((cx.tcx().erase_and_anonymize_regions(ty), index)),
435                );
436                let variant_def = Def::Variant(def.variant(index));
437                Self::from_variant(
438                    variant_def,
439                    tag.map(|tag| (tag, index, encoding.unwrap())),
440                    (ty, variant_layout),
441                    layout.size,
442                    cx,
443                )
444            };
445
446            match layout.variants() {
447                Variants::Empty => Ok(Self::uninhabited()),
448                Variants::Single { index } => {
449                    // `Variants::Single` on enums with variants denotes that
450                    // the enum delegates its layout to the variant at `index`.
451                    layout_of_variant(*index, None)
452                }
453                Variants::Multiple { tag: _, tag_encoding, tag_field, .. } => {
454                    // `Variants::Multiple` denotes an enum with multiple
455                    // variants. The layout of such an enum is the disjunction
456                    // of the layouts of its tagged variants.
457
458                    // For enums (but not coroutines), the tag field is
459                    // currently always the first field of the layout.
460                    match (&*tag_field, &FieldIdx::ZERO) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(*tag_field, FieldIdx::ZERO);
461
462                    let variants = def.discriminants(cx.tcx()).try_fold(
463                        Self::uninhabited(),
464                        |variants, (idx, _discriminant)| {
465                            let variant = layout_of_variant(idx, Some(tag_encoding.clone()))?;
466                            Result::<Self, Err>::Ok(variants.or(variant))
467                        },
468                    )?;
469
470                    Ok(Self::def(Def::Adt(def)).then(variants))
471                }
472            }
473        }
474
475        /// Constructs a `Tree` from a 'variant-like' layout.
476        ///
477        /// A 'variant-like' layout includes those of structs and, of course,
478        /// enum variants. Pragmatically speaking, this method supports anything
479        /// with `FieldsShape::Arbitrary`.
480        ///
481        /// Note: This routine assumes that the optional `tag` is the first
482        /// field, and enum callers should check that `tag_field` is, in fact,
483        /// `0`.
484        fn from_variant(
485            def: Def<'tcx>,
486            tag: Option<(ScalarInt, VariantIdx, TagEncoding<VariantIdx>)>,
487            (ty, layout): (Ty<'tcx>, Layout<'tcx>),
488            total_size: Size,
489            cx: LayoutCx<'tcx>,
490        ) -> Result<Self, Err> {
491            // This constructor does not support non-`FieldsShape::Arbitrary`
492            // layouts.
493            let FieldsShape::Arbitrary { offsets, in_memory_order } = layout.fields() else {
494                return Err(Err::NotYetSupported);
495            };
496
497            // When this function is invoked with enum variants,
498            // `ty_and_layout.size` does not encompass the entire size of the
499            // enum. We rely on `total_size` for this.
500            if !(layout.size <= total_size) {
    ::core::panicking::panic("assertion failed: layout.size <= total_size")
};assert!(layout.size <= total_size);
501
502            let mut size = Size::ZERO;
503            let mut struct_tree = Self::def(def);
504
505            // If a `tag` is provided, place it at the start of the layout.
506            if let Some((tag, index, encoding)) = &tag {
507                match encoding {
508                    TagEncoding::Direct => {
509                        size += tag.size();
510                    }
511                    TagEncoding::Niche { niche_variants, .. } => {
512                        if !niche_variants.contains(index) {
513                            size += tag.size();
514                        }
515                    }
516                }
517                struct_tree = struct_tree.then(Self::from_tag(*tag, cx.tcx()));
518            }
519
520            // Append the fields, in memory order, to the layout.
521            for &field_idx in in_memory_order.iter() {
522                // Add interfield padding.
523                let padding_needed = offsets[field_idx] - size;
524                let padding = Self::padding(padding_needed.bytes_usize());
525
526                let field_ty = ty_field(cx, (ty, layout), field_idx);
527                let field_layout = layout_of(cx, field_ty)?;
528                let field_tree = Self::from_ty(field_ty, cx)?;
529
530                struct_tree = struct_tree.then(padding).then(field_tree);
531
532                size += padding_needed + field_layout.size;
533            }
534
535            // Add trailing padding.
536            let padding_needed = total_size - size;
537            let trailing_padding = Self::padding(padding_needed.bytes_usize());
538
539            Ok(struct_tree.then(trailing_padding))
540        }
541
542        /// Constructs a `Tree` representing the value of a enum tag.
543        fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self {
544            use rustc_abi::Endian;
545            let size = tag.size();
546            let bits = tag.to_bits(size);
547            let bytes: [u8; 16];
548            let bytes = match tcx.data_layout.endian {
549                Endian::Little => {
550                    bytes = bits.to_le_bytes();
551                    &bytes[..size.bytes_usize()]
552                }
553                Endian::Big => {
554                    bytes = bits.to_be_bytes();
555                    &bytes[bytes.len() - size.bytes_usize()..]
556                }
557            };
558            Self::Seq(bytes.iter().map(|&b| Self::byte(b)).collect())
559        }
560
561        /// Constructs a `Tree` from a union.
562        ///
563        /// # Panics
564        ///
565        /// Panics if `def` is not a union definition.
566        fn from_union(
567            (ty, layout): (Ty<'tcx>, Layout<'tcx>),
568            def: AdtDef<'tcx>,
569            cx: LayoutCx<'tcx>,
570        ) -> Result<Self, Err> {
571            if !def.is_union() {
    ::core::panicking::panic("assertion failed: def.is_union()")
};assert!(def.is_union());
572
573            // This constructor does not support non-`FieldsShape::Union`
574            // layouts. Fields of this shape are all placed at offset 0.
575            let FieldsShape::Union(_fields) = layout.fields() else {
576                return Err(Err::NotYetSupported);
577            };
578
579            let fields = &def.non_enum_variant().fields;
580            let fields = fields.iter_enumerated().try_fold(
581                Self::uninhabited(),
582                |fields, (idx, _field_def)| {
583                    let field_ty = ty_field(cx, (ty, layout), idx);
584                    let field_layout = layout_of(cx, field_ty)?;
585                    let field = Self::from_ty(field_ty, cx)?;
586                    let trailing_padding_needed = layout.size - field_layout.size;
587                    let trailing_padding = Self::padding(trailing_padding_needed.bytes_usize());
588                    let field_and_padding = field.then(trailing_padding);
589                    Result::<Self, Err>::Ok(fields.or(field_and_padding))
590                },
591            )?;
592
593            Ok(Self::def(Def::Adt(def)).then(fields))
594        }
595    }
596
597    fn ty_field<'tcx>(
598        cx: LayoutCx<'tcx>,
599        (ty, layout): (Ty<'tcx>, Layout<'tcx>),
600        i: FieldIdx,
601    ) -> Ty<'tcx> {
602        // We cannot use `ty_and_layout_field` to retrieve the field type, since
603        // `ty_and_layout_field` erases regions in the returned type. We must
604        // not erase regions here, since we may need to ultimately emit outlives
605        // obligations as a consequence of the transmutability analysis.
606        match ty.kind() {
607            ty::Adt(def, args) => {
608                match layout.variants {
609                    Variants::Single { index } => {
610                        let field = &def.variant(index).fields[i];
611                        field.ty(cx.tcx(), args)
612                    }
613                    Variants::Empty => {
    ::core::panicking::panic_fmt(format_args!("there is no field in Variants::Empty types"));
}panic!("there is no field in Variants::Empty types"),
614                    // Discriminant field for enums (where applicable).
615                    Variants::Multiple { tag, .. } => {
616                        match (&i.as_usize(), &0) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(i.as_usize(), 0);
617                        ty::layout::PrimitiveExt::to_ty(&tag.primitive(), cx.tcx())
618                    }
619                }
620            }
621            ty::Tuple(fields) => fields[i.as_usize()],
622            kind => {
    ::core::panicking::panic_fmt(format_args!("not implemented: {0}",
            format_args!("only a subset of `Ty::ty_and_layout_field`\'s functionality is implemented. implementation needed for {0:?}",
                kind)));
}unimplemented!(
623                "only a subset of `Ty::ty_and_layout_field`'s functionality is implemented. implementation needed for {:?}",
624                kind
625            ),
626        }
627    }
628
629    fn ty_variant<'tcx>(
630        cx: LayoutCx<'tcx>,
631        (ty, layout): (Ty<'tcx>, Layout<'tcx>),
632        i: VariantIdx,
633    ) -> Layout<'tcx> {
634        let ty = cx.tcx().erase_and_anonymize_regions(ty);
635        TyAndLayout { ty, layout }.for_variant(&cx, i).layout
636    }
637}