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