rustc_transmute/layout/
mod.rs

1use std::fmt::{self, Debug};
2use std::hash::Hash;
3use std::ops::RangeInclusive;
4
5pub(crate) mod tree;
6pub(crate) use tree::Tree;
7
8pub(crate) mod dfa;
9pub(crate) use dfa::{Dfa, union};
10
11#[derive(Debug)]
12pub(crate) struct Uninhabited;
13
14/// A range of byte values (including an uninit byte value).
15#[derive(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)]
16pub(crate) struct Byte {
17    // An inclusive-exclusive range. We use this instead of `Range` because `Range: !Copy`.
18    //
19    // Uninit byte value is represented by 256.
20    pub(crate) start: u16,
21    pub(crate) end: u16,
22}
23
24impl Byte {
25    const UNINIT: u16 = 256;
26
27    #[inline]
28    fn new(range: RangeInclusive<u8>) -> Self {
29        let start: u16 = (*range.start()).into();
30        let end: u16 = (*range.end()).into();
31        Byte { start, end: end + 1 }
32    }
33
34    #[inline]
35    fn from_val(val: u8) -> Self {
36        let val: u16 = val.into();
37        Byte { start: val, end: val + 1 }
38    }
39
40    #[inline]
41    fn uninit() -> Byte {
42        Byte { start: 0, end: Self::UNINIT + 1 }
43    }
44
45    #[inline]
46    fn is_empty(&self) -> bool {
47        self.start == self.end
48    }
49
50    #[inline]
51    fn contains_uninit(&self) -> bool {
52        self.start <= Self::UNINIT && Self::UNINIT < self.end
53    }
54}
55
56impl fmt::Debug for Byte {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        if self.start == Self::UNINIT && self.end == Self::UNINIT + 1 {
59            write!(f, "uninit")
60        } else if self.start <= Self::UNINIT && self.end == Self::UNINIT + 1 {
61            write!(f, "{}..{}|uninit", self.start, self.end - 1)
62        } else {
63            write!(f, "{}..{}", self.start, self.end)
64        }
65    }
66}
67
68impl From<RangeInclusive<u8>> for Byte {
69    fn from(src: RangeInclusive<u8>) -> Self {
70        Self::new(src)
71    }
72}
73
74impl From<u8> for Byte {
75    #[inline]
76    fn from(src: u8) -> Self {
77        Self::from_val(src)
78    }
79}
80
81pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {
82    fn has_safety_invariants(&self) -> bool;
83}
84pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {
85    fn min_align(&self) -> usize;
86
87    fn size(&self) -> usize;
88
89    fn is_mutable(&self) -> bool;
90}
91
92impl Def for ! {
93    fn has_safety_invariants(&self) -> bool {
94        unreachable!()
95    }
96}
97
98impl Ref for ! {
99    fn min_align(&self) -> usize {
100        unreachable!()
101    }
102    fn size(&self) -> usize {
103        unreachable!()
104    }
105    fn is_mutable(&self) -> bool {
106        unreachable!()
107    }
108}
109
110#[cfg(test)]
111impl<const N: usize> Ref for [(); N] {
112    fn min_align(&self) -> usize {
113        N
114    }
115
116    fn size(&self) -> usize {
117        N
118    }
119
120    fn is_mutable(&self) -> bool {
121        false
122    }
123}
124
125#[cfg(feature = "rustc")]
126pub mod rustc {
127    use std::fmt::{self, Write};
128
129    use rustc_abi::Layout;
130    use rustc_middle::mir::Mutability;
131    use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
132    use rustc_middle::ty::{self, Ty};
133
134    /// A reference in the layout.
135    #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
136    pub struct Ref<'tcx> {
137        pub lifetime: ty::Region<'tcx>,
138        pub ty: Ty<'tcx>,
139        pub mutability: Mutability,
140        pub align: usize,
141        pub size: usize,
142    }
143
144    impl<'tcx> super::Ref for Ref<'tcx> {
145        fn min_align(&self) -> usize {
146            self.align
147        }
148
149        fn size(&self) -> usize {
150            self.size
151        }
152
153        fn is_mutable(&self) -> bool {
154            match self.mutability {
155                Mutability::Mut => true,
156                Mutability::Not => false,
157            }
158        }
159    }
160    impl<'tcx> Ref<'tcx> {}
161
162    impl<'tcx> fmt::Display for Ref<'tcx> {
163        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164            f.write_char('&')?;
165            if self.mutability == Mutability::Mut {
166                f.write_str("mut ")?;
167            }
168            self.ty.fmt(f)
169        }
170    }
171
172    /// A visibility node in the layout.
173    #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
174    pub enum Def<'tcx> {
175        Adt(ty::AdtDef<'tcx>),
176        Variant(&'tcx ty::VariantDef),
177        Field(&'tcx ty::FieldDef),
178        Primitive,
179    }
180
181    impl<'tcx> super::Def for Def<'tcx> {
182        fn has_safety_invariants(&self) -> bool {
183            // Rust presently has no notion of 'unsafe fields', so for now we
184            // make the conservative assumption that everything besides
185            // primitive types carry safety invariants.
186            self != &Self::Primitive
187        }
188    }
189
190    pub(crate) fn layout_of<'tcx>(
191        cx: LayoutCx<'tcx>,
192        ty: Ty<'tcx>,
193    ) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> {
194        use rustc_middle::ty::layout::LayoutOf;
195        let ty = cx.tcx().erase_regions(ty);
196        cx.layout_of(ty).map(|tl| tl.layout)
197    }
198}