frontend 0.4.1

rustc's frontend with no LLVM and no std: parsing through MIR, as a library
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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
use alloc::vec::Vec;
use core::fmt;
use core::ops::{Deref, Range};

use crate::rustc_data_structures::intern::Interned;
use crate::rustc_data_structures::range_set::RangeSet;
use rustc_macros::StableHash;

use crate::rustc_abi::layout::{FieldIdx, VariantIdx};
use crate::rustc_abi::{
    AbiAlign, Align, BackendRepr, FieldsShape, Float, HasDataLayout, LayoutData, Niche,
    PointeeInfo, Primitive, Size, Variants,
};

// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.

#[derive(Copy, Clone, PartialEq, Eq, Hash, StableHash)]
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 `<LayoutData 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) -> AbiAlign {
        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
    }
}

/// 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, StableHash)]
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
    }
}

impl<'a, Ty> AsRef<LayoutData<FieldIdx, VariantIdx>> for TyAndLayout<'a, Ty> {
    fn as_ref(&self) -> &LayoutData<FieldIdx, VariantIdx> {
        &*self.layout.0.0
    }
}

/// Trait that needs to be implemented by the higher-level type representation
/// (e.g. `crate::rustc_middle::ty::Ty`), to provide `crate::rustc_target::abi` functionality.
pub trait TyAbiInterface<'a, C>: Sized + core::fmt::Debug + core::fmt::Display {
    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;
    fn is_complex_number_lang_item(this: TyAndLayout<'a, Self>, cx: &C) -> bool;
    fn is_scalable_vector(this: TyAndLayout<'a, Self>) -> bool;
    /// See [`TyAndLayout::pass_indirectly_in_non_rustic_abis`] for details.
    fn is_pass_indirectly_in_non_rustic_abis_flag_set(this: TyAndLayout<'a, Self>) -> bool;
}

impl<'a, Ty> TyAndLayout<'a, Ty> {
    /// Synthetize a layout representing the variant-specific fields of an enum-like layout.
    ///
    /// Note that the resulting layout *does not* fully describes `self.ty` at that specific
    /// variant: prefix fields (e.g. in coroutines) and tag information are lost.
    ///
    /// If you don't need type information about the variant's fields, prefer using
    /// `self.layout.variants` directly.
    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(), Primitive::Float(Float::F32 | Float::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::SimdVector { .. } => 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)
    }

    /// Returns `true` if this type needs to match the ABI of the C `_Complex` type. See
    /// [`TyAndLayout::complex_number_primitive`] for details.
    pub fn is_complex_number<C>(self, cx: &C) -> bool
    where
        Ty: TyAbiInterface<'a, C> + Copy,
    {
        self.complex_number_primitive(cx).is_some()
    }

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

    /// If this method returns `true`, then this type should always have a `PassMode` of
    /// `Indirect { on_stack: false, .. }` when being used as the argument type of a function with a
    /// non-Rustic ABI (this is true for structs annotated with the
    /// `#[rustc_pass_indirectly_in_non_rustic_abis]` attribute).
    ///
    /// This is used to replicate some of the behaviour of C array-to-pointer decay; however unlike
    /// C any changes the caller makes to the passed value will not be reflected in the callee, so
    /// the attribute is only useful for types where observing the value in the caller after the
    /// function call isn't allowed (a.k.a. `va_list`).
    ///
    /// This function handles transparent types automatically.
    pub fn pass_indirectly_in_non_rustic_abis<C>(self, cx: &C) -> bool
    where
        Ty: TyAbiInterface<'a, C> + Copy,
    {
        let base = self.peel_transparent_wrappers(cx);
        Ty::is_pass_indirectly_in_non_rustic_abis_flag_set(base)
    }

    /// Recursively peel away transparent wrappers, returning the inner value.
    ///
    /// The return value is not `repr(transparent)` and/or does
    /// not have a non-1zst field.
    pub fn peel_transparent_wrappers<C>(mut self, cx: &C) -> Self
    where
        Ty: TyAbiInterface<'a, C> + Copy,
    {
        while self.is_transparent()
            && let Some((_, field)) = self.non_1zst_field(cx)
        {
            self = field;
        }

        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<(FieldIdx, 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((FieldIdx::from_usize(field_idx), field));
        }
        found
    }

    /// If this type should match the ABI of the C `_Complex` type, returns the primitive that is
    /// used for its parts. This only returns `Some(T)` for `core::num::Complex<T>` where `T` is
    /// either a float or an integer. `repr(transparent)` wrapper types are automatically handled.
    pub fn complex_number_primitive<C>(&self, cx: &C) -> Option<Primitive>
    where
        Ty: TyAbiInterface<'a, C> + Copy,
    {
        let complex = self.peel_transparent_wrappers(cx);
        if !Ty::is_complex_number_lang_item(complex, cx) {
            return None;
        }

        let part = complex.field(cx, 0).peel_transparent_wrappers(cx);

        if let BackendRepr::Scalar(scalar) = part.backend_repr {
            // Only Complex<{ float }> and Complex<{ integer }> have special layout.
            let primitive = scalar.primitive();
            match primitive {
                // Explicitly spell out all the float types so that any new ones have to be added to
                // one of the match branches.
                Primitive::Int(..)
                | Primitive::Float(Float::F16 | Float::F32 | Float::F64 | Float::F128) => {
                    Some(primitive)
                }
                Primitive::Pointer(..) => None,
            }
        } else {
            None
        }
    }

    /// Returns `Some` if this type has the ABI of the C `_Complex` type with float parts. See
    /// [`TyAndLayout::complex_number_primitive`] for details.
    pub fn complex_float<C>(&self, cx: &C) -> Option<Float>
    where
        Ty: TyAbiInterface<'a, C> + Copy,
    {
        if let Some(Primitive::Float(float)) = self.complex_number_primitive(cx) {
            Some(float)
        } else {
            None
        }
    }

    /// Whether this type/layout has any padding that is dependent on a variant, i.e. has bytes that
    /// are padding for some, but not all, valid values of this type.
    pub fn has_variant_dependent_padding<C>(&self, cx: &C) -> bool
    where
        Ty: TyAbiInterface<'a, C> + Copy,
    {
        match self.variants {
            Variants::Multiple { .. } => true,
            Variants::Empty => false,
            Variants::Single { .. } => match &self.fields {
                FieldsShape::Primitive | FieldsShape::Union(_) => false,
                FieldsShape::Array { count, .. } => {
                    *count > 0 && self.field(cx, 0).has_variant_dependent_padding(cx)
                }
                FieldsShape::Arbitrary { offsets, .. } => {
                    (0..offsets.len()).any(|i| self.field(cx, i).has_variant_dependent_padding(cx))
                }
            },
        }
    }

    /// The ranges of bytes that are always ignored by the representation relation of this type.
    ///
    /// In other words, for any sequence of bytes, if we reset the these padding bytes to uninit,
    /// then these two sequences of bytes represent the same value (or they are both invalid).
    /// This is the "guaranteed" padding. There may be more bytes that are padding for some
    /// but not all variants of this type; those are not included.
    /// (E.g. `Option<i8>` has no guaranteed padding so the empty range set is returned, but its `None` value still has padding).
    pub fn variant_independent_padding_ranges<C>(&self, cx: &C) -> Vec<Range<Size>>
    where
        Ty: TyAbiInterface<'a, C> + Copy,
    {
        let mut data = RangeSet::new();
        self.add_data_ranges(cx, Size::ZERO, &mut data);

        // Find gaps between the data ranges.
        let mut uninit_ranges = Vec::new();
        let mut covered_until = Size::ZERO;
        for &(offset, size) in data.0.iter() {
            if offset > covered_until {
                uninit_ranges.push(covered_until..offset);
            }
            covered_until = Ord::max(covered_until, offset + size);
        }

        // Add trailing padding.
        if self.size > covered_until {
            uninit_ranges.push(covered_until..self.size);
        }

        uninit_ranges
    }

    /// The ranges of bytes that are ignored by the representation relation of this variant.
    ///
    /// The result does not include variant-independent padding.
    pub fn variant_dependent_padding_ranges<C>(
        &self,
        cx: &C,
        variant_index: VariantIdx,
    ) -> Vec<Range<Size>>
    where
        Ty: TyAbiInterface<'a, C> + Copy,
    {
        let Variants::Multiple { .. } = self.variants else {
            return Vec::new();
        };

        // Bytes that are data in some variant.
        let mut any = RangeSet::new();
        self.add_data_ranges(cx, Size::ZERO, &mut any);

        // Bytes that are data in this variant.
        let mut this = RangeSet::new();

        // The variants do not contain e.g. the discriminant or coroutine upvars.
        let FieldsShape::Arbitrary { offsets, in_memory_order: _ } = &self.fields else {
            unreachable!("a multi-variant layout should have `Arbitrary` fields")
        };

        // So add them explicitly.
        for (field, &offset) in offsets.iter_enumerated() {
            let field = self.field(cx, field.as_usize());
            field.add_data_ranges(cx, offset, &mut this);
        }

        self.for_variant(cx, variant_index).add_data_ranges(cx, Size::ZERO, &mut this);

        // Padding specific to this variant: data in some variant, but not in this one.
        any.difference(&this).0.iter().map(|&(offset, size)| offset..offset + size).collect()
    }

    /// Extend `out` with all ranges of bytes that *may* carry relevant data for values of this type.
    /// For enums and unions there are offsets that are initialized for some
    /// variants but not for others; those offset *will* get added to `out`.
    fn add_data_ranges<C>(self, cx: &C, base_offset: Size, out: &mut RangeSet<Size>)
    where
        Ty: TyAbiInterface<'a, C> + Copy,
    {
        if self.is_zst() {
            return;
        }

        // Visit the fields of this value. For enum values the fields include the discriminant.
        match &self.fields {
            FieldsShape::Primitive => {
                out.add_range(base_offset, self.size);
            }
            &FieldsShape::Union(field_count) => {
                for field in 0..field_count.get() {
                    let field = self.field(cx, field);
                    field.add_data_ranges(cx, base_offset, out);
                }
            }
            &FieldsShape::Array { stride, count } => {
                let elem = self.field(cx, 0);

                // For scalars we know there is no padding between the elements,
                // so the entire array is a single big data range.
                if elem.backend_repr.is_scalar() {
                    out.add_range(base_offset, elem.size * count);
                } else {
                    // FIXME: this is really inefficient for large arrays.
                    for idx in 0..count {
                        elem.add_data_ranges(cx, base_offset + idx * stride, out);
                    }
                }
            }
            FieldsShape::Arbitrary { offsets, in_memory_order: _ } => {
                for (field, &offset) in offsets.iter_enumerated() {
                    let field = self.field(cx, field.as_usize());
                    field.add_data_ranges(cx, base_offset + offset, out);
                }
            }
        }

        // Visit the fields of each variant.
        match &self.variants {
            Variants::Empty | Variants::Single { index: _ } => { /* done */ }
            Variants::Multiple { variants, .. } => {
                for variant in variants.indices() {
                    let variant = self.for_variant(cx, variant);
                    variant.add_data_ranges(cx, base_offset, out);
                }
            }
        }
    }
}