rustc_abi/layout/
ty.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
use std::fmt;
use std::ops::Deref;

use Float::*;
use Primitive::*;
use rustc_data_structures::intern::Interned;
use rustc_macros::HashStable_Generic;

// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
use crate::{Float, *};

rustc_index::newtype_index! {
    /// The *source-order* index of a field in a variant.
    ///
    /// This is how most code after type checking refers to fields, rather than
    /// using names (as names have hygiene complications and more complex lookup).
    ///
    /// Particularly for `repr(Rust)` types, this may not be the same as *layout* order.
    /// (It is for `repr(C)` `struct`s, however.)
    ///
    /// For example, in the following types,
    /// ```rust
    /// # enum Never {}
    /// # #[repr(u16)]
    /// enum Demo1 {
    ///    Variant0 { a: Never, b: i32 } = 100,
    ///    Variant1 { c: u8, d: u64 } = 10,
    /// }
    /// struct Demo2 { e: u8, f: u16, g: u8 }
    /// ```
    /// `b` is `FieldIdx(1)` in `VariantIdx(0)`,
    /// `d` is `FieldIdx(1)` in `VariantIdx(1)`, and
    /// `f` is `FieldIdx(1)` in `VariantIdx(0)`.
    #[derive(HashStable_Generic)]
    #[encodable]
    #[orderable]
    pub struct FieldIdx {}
}

rustc_index::newtype_index! {
    /// The *source-order* index of a variant in a type.
    ///
    /// For enums, these are always `0..variant_count`, regardless of any
    /// custom discriminants that may have been defined, and including any
    /// variants that may end up uninhabited due to field types.  (Some of the
    /// variants may not be present in a monomorphized ABI [`Variants`], but
    /// those skipped variants are always counted when determining the *index*.)
    ///
    /// `struct`s, `tuples`, and `unions`s are considered to have a single variant
    /// with variant index zero, aka [`FIRST_VARIANT`].
    #[derive(HashStable_Generic)]
    #[encodable]
    #[orderable]
    pub struct VariantIdx {
        /// Equivalent to `VariantIdx(0)`.
        const FIRST_VARIANT = 0;
    }
}
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
#[rustc_pass_by_value]
pub struct Layout<'a>(pub Interned<'a, LayoutData<FieldIdx, VariantIdx>>);

impl<'a> fmt::Debug for Layout<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // See comment on `<LayoutS as Debug>::fmt` above.
        self.0.0.fmt(f)
    }
}

impl<'a> Deref for Layout<'a> {
    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
        &self.0.0
    }
}

impl<'a> Layout<'a> {
    pub fn fields(self) -> &'a FieldsShape<FieldIdx> {
        &self.0.0.fields
    }

    pub fn variants(self) -> &'a Variants<FieldIdx, VariantIdx> {
        &self.0.0.variants
    }

    pub fn backend_repr(self) -> BackendRepr {
        self.0.0.backend_repr
    }

    pub fn largest_niche(self) -> Option<Niche> {
        self.0.0.largest_niche
    }

    pub fn align(self) -> AbiAndPrefAlign {
        self.0.0.align
    }

    pub fn size(self) -> Size {
        self.0.0.size
    }

    pub fn max_repr_align(self) -> Option<Align> {
        self.0.0.max_repr_align
    }

    pub fn unadjusted_abi_align(self) -> Align {
        self.0.0.unadjusted_abi_align
    }

    /// Whether the layout is from a type that implements [`std::marker::PointerLike`].
    ///
    /// Currently, that means that the type is pointer-sized, pointer-aligned,
    /// and has a initialized (non-union), scalar ABI.
    pub fn is_pointer_like(self, data_layout: &TargetDataLayout) -> bool {
        self.size() == data_layout.pointer_size
            && self.align().abi == data_layout.pointer_align.abi
            && matches!(self.backend_repr(), BackendRepr::Scalar(Scalar::Initialized { .. }))
    }
}

/// The layout of a type, alongside the type itself.
/// Provides various type traversal APIs (e.g., recursing into fields).
///
/// Note that the layout is NOT guaranteed to always be identical
/// to that obtained from `layout_of(ty)`, as we need to produce
/// layouts for which Rust types do not exist, such as enum variants
/// or synthetic fields of enums (i.e., discriminants) and wide pointers.
#[derive(Copy, Clone, PartialEq, Eq, Hash, HashStable_Generic)]
pub struct TyAndLayout<'a, Ty> {
    pub ty: Ty,
    pub layout: Layout<'a>,
}

impl<'a, Ty: fmt::Display> fmt::Debug for TyAndLayout<'a, Ty> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Print the type in a readable way, not its debug representation.
        f.debug_struct("TyAndLayout")
            .field("ty", &format_args!("{}", self.ty))
            .field("layout", &self.layout)
            .finish()
    }
}

impl<'a, Ty> Deref for TyAndLayout<'a, Ty> {
    type Target = &'a LayoutData<FieldIdx, VariantIdx>;
    fn deref(&self) -> &&'a LayoutData<FieldIdx, VariantIdx> {
        &self.layout.0.0
    }
}

/// Trait that needs to be implemented by the higher-level type representation
/// (e.g. `rustc_middle::ty::Ty`), to provide `rustc_target::abi` functionality.
pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
    fn ty_and_layout_for_variant(
        this: TyAndLayout<'a, Self>,
        cx: &C,
        variant_index: VariantIdx,
    ) -> TyAndLayout<'a, Self>;
    fn ty_and_layout_field(this: TyAndLayout<'a, Self>, cx: &C, i: usize) -> TyAndLayout<'a, Self>;
    fn ty_and_layout_pointee_info_at(
        this: TyAndLayout<'a, Self>,
        cx: &C,
        offset: Size,
    ) -> Option<PointeeInfo>;
    fn is_adt(this: TyAndLayout<'a, Self>) -> bool;
    fn is_never(this: TyAndLayout<'a, Self>) -> bool;
    fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
    fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
    fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
}

impl<'a, Ty> TyAndLayout<'a, Ty> {
    pub fn for_variant<C>(self, cx: &C, variant_index: VariantIdx) -> Self
    where
        Ty: TyAbiInterface<'a, C>,
    {
        Ty::ty_and_layout_for_variant(self, cx, variant_index)
    }

    pub fn field<C>(self, cx: &C, i: usize) -> Self
    where
        Ty: TyAbiInterface<'a, C>,
    {
        Ty::ty_and_layout_field(self, cx, i)
    }

    pub fn pointee_info_at<C>(self, cx: &C, offset: Size) -> Option<PointeeInfo>
    where
        Ty: TyAbiInterface<'a, C>,
    {
        Ty::ty_and_layout_pointee_info_at(self, cx, offset)
    }

    pub fn is_single_fp_element<C>(self, cx: &C) -> bool
    where
        Ty: TyAbiInterface<'a, C>,
        C: HasDataLayout,
    {
        match self.backend_repr {
            BackendRepr::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)),
            BackendRepr::Memory { .. } => {
                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
                    self.field(cx, 0).is_single_fp_element(cx)
                } else {
                    false
                }
            }
            _ => false,
        }
    }

    pub fn is_single_vector_element<C>(self, cx: &C, expected_size: Size) -> bool
    where
        Ty: TyAbiInterface<'a, C>,
        C: HasDataLayout,
    {
        match self.backend_repr {
            BackendRepr::Vector { .. } => self.size == expected_size,
            BackendRepr::Memory { .. } => {
                if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
                    self.field(cx, 0).is_single_vector_element(cx, expected_size)
                } else {
                    false
                }
            }
            _ => false,
        }
    }

    pub fn is_adt<C>(self) -> bool
    where
        Ty: TyAbiInterface<'a, C>,
    {
        Ty::is_adt(self)
    }

    pub fn is_never<C>(self) -> bool
    where
        Ty: TyAbiInterface<'a, C>,
    {
        Ty::is_never(self)
    }

    pub fn is_tuple<C>(self) -> bool
    where
        Ty: TyAbiInterface<'a, C>,
    {
        Ty::is_tuple(self)
    }

    pub fn is_unit<C>(self) -> bool
    where
        Ty: TyAbiInterface<'a, C>,
    {
        Ty::is_unit(self)
    }

    pub fn is_transparent<C>(self) -> bool
    where
        Ty: TyAbiInterface<'a, C>,
    {
        Ty::is_transparent(self)
    }

    /// Finds the one field that is not a 1-ZST.
    /// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
    pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(usize, Self)>
    where
        Ty: TyAbiInterface<'a, C> + Copy,
    {
        let mut found = None;
        for field_idx in 0..self.fields.count() {
            let field = self.field(cx, field_idx);
            if field.is_1zst() {
                continue;
            }
            if found.is_some() {
                // More than one non-1-ZST field.
                return None;
            }
            found = Some((field_idx, field));
        }
        found
    }
}