rustc_abi/
lib.rs

1// tidy-alphabetical-start
2#![cfg_attr(feature = "nightly", allow(internal_features))]
3#![cfg_attr(feature = "nightly", doc(rust_logo))]
4#![cfg_attr(feature = "nightly", feature(assert_matches))]
5#![cfg_attr(feature = "nightly", feature(rustc_attrs))]
6#![cfg_attr(feature = "nightly", feature(rustdoc_internals))]
7#![cfg_attr(feature = "nightly", feature(step_trait))]
8// tidy-alphabetical-end
9
10/*! ABI handling for rustc
11
12## What is an "ABI"?
13
14Literally, "application binary interface", which means it is everything about how code interacts,
15at the machine level, with other code. This means it technically covers all of the following:
16- object binary format for e.g. relocations or offset tables
17- in-memory layout of types
18- procedure calling conventions
19
20When we discuss "ABI" in the context of rustc, we are probably discussing calling conventions.
21To describe those `rustc_abi` also covers type layout, as it must for values passed on the stack.
22Despite `rustc_abi` being about calling conventions, it is good to remember these usages exist.
23You will encounter all of them and more if you study target-specific codegen enough!
24Even in general conversation, when someone says "the Rust ABI is unstable", it may allude to
25either or both of
26- `repr(Rust)` types have a mostly-unspecified layout
27- `extern "Rust" fn(A) -> R` has an unspecified calling convention
28
29## Crate Goal
30
31ABI is a foundational concept, so the `rustc_abi` crate serves as an equally foundational crate.
32It cannot carry all details relevant to an ABI: those permeate code generation and linkage.
33Instead, `rustc_abi` is intended to provide the interface for reasoning about the binary interface.
34It should contain traits and types that other crates then use in their implementation.
35For example, a platform's `extern "C" fn` calling convention will be implemented in `rustc_target`
36but `rustc_abi` contains the types for calculating layout and describing register-passing.
37This makes it easier to describe things in the same way across targets, codegen backends, and
38even other Rust compilers, such as rust-analyzer!
39
40*/
41
42use std::fmt;
43#[cfg(feature = "nightly")]
44use std::iter::Step;
45use std::num::{NonZeroUsize, ParseIntError};
46use std::ops::{Add, AddAssign, Deref, Mul, RangeInclusive, Sub};
47use std::str::FromStr;
48
49use bitflags::bitflags;
50#[cfg(feature = "nightly")]
51use rustc_data_structures::stable_hasher::StableOrd;
52use rustc_hashes::Hash64;
53use rustc_index::{Idx, IndexSlice, IndexVec};
54#[cfg(feature = "nightly")]
55use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_Generic};
56
57mod callconv;
58mod canon_abi;
59mod extern_abi;
60mod layout;
61#[cfg(test)]
62mod tests;
63
64pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
65pub use canon_abi::{ArmCall, CanonAbi, InterruptKind, X86Call};
66pub use extern_abi::{ExternAbi, all_names};
67#[cfg(feature = "nightly")]
68pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
69pub use layout::{LayoutCalculator, LayoutCalculatorError};
70
71/// Requirements for a `StableHashingContext` to be used in this crate.
72/// This is a hack to allow using the `HashStable_Generic` derive macro
73/// instead of implementing everything in `rustc_middle`.
74#[cfg(feature = "nightly")]
75pub trait HashStableContext {}
76
77#[derive(Clone, Copy, PartialEq, Eq, Default)]
78#[cfg_attr(
79    feature = "nightly",
80    derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic)
81)]
82pub struct ReprFlags(u8);
83
84bitflags! {
85    impl ReprFlags: u8 {
86        const IS_C               = 1 << 0;
87        const IS_SIMD            = 1 << 1;
88        const IS_TRANSPARENT     = 1 << 2;
89        // Internal only for now. If true, don't reorder fields.
90        // On its own it does not prevent ABI optimizations.
91        const IS_LINEAR          = 1 << 3;
92        // If true, the type's crate has opted into layout randomization.
93        // Other flags can still inhibit reordering and thus randomization.
94        // The seed stored in `ReprOptions.field_shuffle_seed`.
95        const RANDOMIZE_LAYOUT   = 1 << 4;
96        // Any of these flags being set prevent field reordering optimisation.
97        const FIELD_ORDER_UNOPTIMIZABLE   = ReprFlags::IS_C.bits()
98                                 | ReprFlags::IS_SIMD.bits()
99                                 | ReprFlags::IS_LINEAR.bits();
100        const ABI_UNOPTIMIZABLE = ReprFlags::IS_C.bits() | ReprFlags::IS_SIMD.bits();
101    }
102}
103
104// This is the same as `rustc_data_structures::external_bitflags_debug` but without the
105// `rustc_data_structures` to make it build on stable.
106impl std::fmt::Debug for ReprFlags {
107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108        bitflags::parser::to_writer(self, f)
109    }
110}
111
112#[derive(Copy, Clone, Debug, Eq, PartialEq)]
113#[cfg_attr(
114    feature = "nightly",
115    derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic)
116)]
117pub enum IntegerType {
118    /// Pointer-sized integer type, i.e. `isize` and `usize`. The field shows signedness, e.g.
119    /// `Pointer(true)` means `isize`.
120    Pointer(bool),
121    /// Fixed-sized integer type, e.g. `i8`, `u32`, `i128`. The bool field shows signedness, e.g.
122    /// `Fixed(I8, false)` means `u8`.
123    Fixed(Integer, bool),
124}
125
126impl IntegerType {
127    pub fn is_signed(&self) -> bool {
128        match self {
129            IntegerType::Pointer(b) => *b,
130            IntegerType::Fixed(_, b) => *b,
131        }
132    }
133}
134
135/// Represents the repr options provided by the user.
136#[derive(Copy, Clone, Debug, Eq, PartialEq, Default)]
137#[cfg_attr(
138    feature = "nightly",
139    derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic)
140)]
141pub struct ReprOptions {
142    pub int: Option<IntegerType>,
143    pub align: Option<Align>,
144    pub pack: Option<Align>,
145    pub flags: ReprFlags,
146    /// The seed to be used for randomizing a type's layout
147    ///
148    /// Note: This could technically be a `u128` which would
149    /// be the "most accurate" hash as it'd encompass the item and crate
150    /// hash without loss, but it does pay the price of being larger.
151    /// Everything's a tradeoff, a 64-bit seed should be sufficient for our
152    /// purposes (primarily `-Z randomize-layout`)
153    pub field_shuffle_seed: Hash64,
154}
155
156impl ReprOptions {
157    #[inline]
158    pub fn simd(&self) -> bool {
159        self.flags.contains(ReprFlags::IS_SIMD)
160    }
161
162    #[inline]
163    pub fn c(&self) -> bool {
164        self.flags.contains(ReprFlags::IS_C)
165    }
166
167    #[inline]
168    pub fn packed(&self) -> bool {
169        self.pack.is_some()
170    }
171
172    #[inline]
173    pub fn transparent(&self) -> bool {
174        self.flags.contains(ReprFlags::IS_TRANSPARENT)
175    }
176
177    #[inline]
178    pub fn linear(&self) -> bool {
179        self.flags.contains(ReprFlags::IS_LINEAR)
180    }
181
182    /// Returns the discriminant type, given these `repr` options.
183    /// This must only be called on enums!
184    pub fn discr_type(&self) -> IntegerType {
185        self.int.unwrap_or(IntegerType::Pointer(true))
186    }
187
188    /// Returns `true` if this `#[repr()]` should inhabit "smart enum
189    /// layout" optimizations, such as representing `Foo<&T>` as a
190    /// single pointer.
191    pub fn inhibit_enum_layout_opt(&self) -> bool {
192        self.c() || self.int.is_some()
193    }
194
195    pub fn inhibit_newtype_abi_optimization(&self) -> bool {
196        self.flags.intersects(ReprFlags::ABI_UNOPTIMIZABLE)
197    }
198
199    /// Returns `true` if this `#[repr()]` guarantees a fixed field order,
200    /// e.g. `repr(C)` or `repr(<int>)`.
201    pub fn inhibit_struct_field_reordering(&self) -> bool {
202        self.flags.intersects(ReprFlags::FIELD_ORDER_UNOPTIMIZABLE) || self.int.is_some()
203    }
204
205    /// Returns `true` if this type is valid for reordering and `-Z randomize-layout`
206    /// was enabled for its declaration crate.
207    pub fn can_randomize_type_layout(&self) -> bool {
208        !self.inhibit_struct_field_reordering() && self.flags.contains(ReprFlags::RANDOMIZE_LAYOUT)
209    }
210
211    /// Returns `true` if this `#[repr()]` should inhibit union ABI optimisations.
212    pub fn inhibits_union_abi_opt(&self) -> bool {
213        self.c()
214    }
215}
216
217/// The maximum supported number of lanes in a SIMD vector.
218///
219/// This value is selected based on backend support:
220/// * LLVM does not appear to have a vector width limit.
221/// * Cranelift stores the base-2 log of the lane count in a 4 bit integer.
222pub const MAX_SIMD_LANES: u64 = 1 << 0xF;
223
224/// Parsed [Data layout](https://llvm.org/docs/LangRef.html#data-layout)
225/// for a target, which contains everything needed to compute layouts.
226#[derive(Debug, PartialEq, Eq)]
227pub struct TargetDataLayout {
228    pub endian: Endian,
229    pub i1_align: AbiAlign,
230    pub i8_align: AbiAlign,
231    pub i16_align: AbiAlign,
232    pub i32_align: AbiAlign,
233    pub i64_align: AbiAlign,
234    pub i128_align: AbiAlign,
235    pub f16_align: AbiAlign,
236    pub f32_align: AbiAlign,
237    pub f64_align: AbiAlign,
238    pub f128_align: AbiAlign,
239    pub pointer_size: Size,
240    pub pointer_align: AbiAlign,
241    pub aggregate_align: AbiAlign,
242
243    /// Alignments for vector types.
244    pub vector_align: Vec<(Size, AbiAlign)>,
245
246    pub instruction_address_space: AddressSpace,
247
248    /// Minimum size of #[repr(C)] enums (default c_int::BITS, usually 32)
249    /// Note: This isn't in LLVM's data layout string, it is `short_enum`
250    /// so the only valid spec for LLVM is c_int::BITS or 8
251    pub c_enum_min_size: Integer,
252}
253
254impl Default for TargetDataLayout {
255    /// Creates an instance of `TargetDataLayout`.
256    fn default() -> TargetDataLayout {
257        let align = |bits| Align::from_bits(bits).unwrap();
258        TargetDataLayout {
259            endian: Endian::Big,
260            i1_align: AbiAlign::new(align(8)),
261            i8_align: AbiAlign::new(align(8)),
262            i16_align: AbiAlign::new(align(16)),
263            i32_align: AbiAlign::new(align(32)),
264            i64_align: AbiAlign::new(align(32)),
265            i128_align: AbiAlign::new(align(32)),
266            f16_align: AbiAlign::new(align(16)),
267            f32_align: AbiAlign::new(align(32)),
268            f64_align: AbiAlign::new(align(64)),
269            f128_align: AbiAlign::new(align(128)),
270            pointer_size: Size::from_bits(64),
271            pointer_align: AbiAlign::new(align(64)),
272            aggregate_align: AbiAlign { abi: align(8) },
273            vector_align: vec![
274                (Size::from_bits(64), AbiAlign::new(align(64))),
275                (Size::from_bits(128), AbiAlign::new(align(128))),
276            ],
277            instruction_address_space: AddressSpace::DATA,
278            c_enum_min_size: Integer::I32,
279        }
280    }
281}
282
283pub enum TargetDataLayoutErrors<'a> {
284    InvalidAddressSpace { addr_space: &'a str, cause: &'a str, err: ParseIntError },
285    InvalidBits { kind: &'a str, bit: &'a str, cause: &'a str, err: ParseIntError },
286    MissingAlignment { cause: &'a str },
287    InvalidAlignment { cause: &'a str, err: AlignFromBytesError },
288    InconsistentTargetArchitecture { dl: &'a str, target: &'a str },
289    InconsistentTargetPointerWidth { pointer_size: u64, target: u32 },
290    InvalidBitsSize { err: String },
291}
292
293impl TargetDataLayout {
294    /// Parse data layout from an
295    /// [llvm data layout string](https://llvm.org/docs/LangRef.html#data-layout)
296    ///
297    /// This function doesn't fill `c_enum_min_size` and it will always be `I32` since it can not be
298    /// determined from llvm string.
299    pub fn parse_from_llvm_datalayout_string<'a>(
300        input: &'a str,
301    ) -> Result<TargetDataLayout, TargetDataLayoutErrors<'a>> {
302        // Parse an address space index from a string.
303        let parse_address_space = |s: &'a str, cause: &'a str| {
304            s.parse::<u32>().map(AddressSpace).map_err(|err| {
305                TargetDataLayoutErrors::InvalidAddressSpace { addr_space: s, cause, err }
306            })
307        };
308
309        // Parse a bit count from a string.
310        let parse_bits = |s: &'a str, kind: &'a str, cause: &'a str| {
311            s.parse::<u64>().map_err(|err| TargetDataLayoutErrors::InvalidBits {
312                kind,
313                bit: s,
314                cause,
315                err,
316            })
317        };
318
319        // Parse a size string.
320        let parse_size =
321            |s: &'a str, cause: &'a str| parse_bits(s, "size", cause).map(Size::from_bits);
322
323        // Parse an alignment string.
324        let parse_align = |s: &[&'a str], cause: &'a str| {
325            if s.is_empty() {
326                return Err(TargetDataLayoutErrors::MissingAlignment { cause });
327            }
328            let align_from_bits = |bits| {
329                Align::from_bits(bits)
330                    .map_err(|err| TargetDataLayoutErrors::InvalidAlignment { cause, err })
331            };
332            let abi = parse_bits(s[0], "alignment", cause)?;
333            Ok(AbiAlign::new(align_from_bits(abi)?))
334        };
335
336        let mut dl = TargetDataLayout::default();
337        let mut i128_align_src = 64;
338        for spec in input.split('-') {
339            let spec_parts = spec.split(':').collect::<Vec<_>>();
340
341            match &*spec_parts {
342                ["e"] => dl.endian = Endian::Little,
343                ["E"] => dl.endian = Endian::Big,
344                [p] if p.starts_with('P') => {
345                    dl.instruction_address_space = parse_address_space(&p[1..], "P")?
346                }
347                ["a", a @ ..] => dl.aggregate_align = parse_align(a, "a")?,
348                ["f16", a @ ..] => dl.f16_align = parse_align(a, "f16")?,
349                ["f32", a @ ..] => dl.f32_align = parse_align(a, "f32")?,
350                ["f64", a @ ..] => dl.f64_align = parse_align(a, "f64")?,
351                ["f128", a @ ..] => dl.f128_align = parse_align(a, "f128")?,
352                // FIXME(erikdesjardins): we should be parsing nonzero address spaces
353                // this will require replacing TargetDataLayout::{pointer_size,pointer_align}
354                // with e.g. `fn pointer_size_in(AddressSpace)`
355                [p @ "p", s, a @ ..] | [p @ "p0", s, a @ ..] => {
356                    dl.pointer_size = parse_size(s, p)?;
357                    dl.pointer_align = parse_align(a, p)?;
358                }
359                [s, a @ ..] if s.starts_with('i') => {
360                    let Ok(bits) = s[1..].parse::<u64>() else {
361                        parse_size(&s[1..], "i")?; // For the user error.
362                        continue;
363                    };
364                    let a = parse_align(a, s)?;
365                    match bits {
366                        1 => dl.i1_align = a,
367                        8 => dl.i8_align = a,
368                        16 => dl.i16_align = a,
369                        32 => dl.i32_align = a,
370                        64 => dl.i64_align = a,
371                        _ => {}
372                    }
373                    if bits >= i128_align_src && bits <= 128 {
374                        // Default alignment for i128 is decided by taking the alignment of
375                        // largest-sized i{64..=128}.
376                        i128_align_src = bits;
377                        dl.i128_align = a;
378                    }
379                }
380                [s, a @ ..] if s.starts_with('v') => {
381                    let v_size = parse_size(&s[1..], "v")?;
382                    let a = parse_align(a, s)?;
383                    if let Some(v) = dl.vector_align.iter_mut().find(|v| v.0 == v_size) {
384                        v.1 = a;
385                        continue;
386                    }
387                    // No existing entry, add a new one.
388                    dl.vector_align.push((v_size, a));
389                }
390                _ => {} // Ignore everything else.
391            }
392        }
393        Ok(dl)
394    }
395
396    /// Returns **exclusive** upper bound on object size in bytes.
397    ///
398    /// The theoretical maximum object size is defined as the maximum positive `isize` value.
399    /// This ensures that the `offset` semantics remain well-defined by allowing it to correctly
400    /// index every address within an object along with one byte past the end, along with allowing
401    /// `isize` to store the difference between any two pointers into an object.
402    ///
403    /// LLVM uses a 64-bit integer to represent object size in *bits*, but we care only for bytes,
404    /// so we adopt such a more-constrained size bound due to its technical limitations.
405    #[inline]
406    pub fn obj_size_bound(&self) -> u64 {
407        match self.pointer_size.bits() {
408            16 => 1 << 15,
409            32 => 1 << 31,
410            64 => 1 << 61,
411            bits => panic!("obj_size_bound: unknown pointer bit size {bits}"),
412        }
413    }
414
415    #[inline]
416    pub fn ptr_sized_integer(&self) -> Integer {
417        use Integer::*;
418        match self.pointer_size.bits() {
419            16 => I16,
420            32 => I32,
421            64 => I64,
422            bits => panic!("ptr_sized_integer: unknown pointer bit size {bits}"),
423        }
424    }
425
426    /// psABI-mandated alignment for a vector type, if any
427    #[inline]
428    fn cabi_vector_align(&self, vec_size: Size) -> Option<AbiAlign> {
429        self.vector_align
430            .iter()
431            .find(|(size, _align)| *size == vec_size)
432            .map(|(_size, align)| *align)
433    }
434
435    /// an alignment resembling the one LLVM would pick for a vector
436    #[inline]
437    pub fn llvmlike_vector_align(&self, vec_size: Size) -> AbiAlign {
438        self.cabi_vector_align(vec_size).unwrap_or(AbiAlign::new(
439            Align::from_bytes(vec_size.bytes().next_power_of_two()).unwrap(),
440        ))
441    }
442}
443
444pub trait HasDataLayout {
445    fn data_layout(&self) -> &TargetDataLayout;
446}
447
448impl HasDataLayout for TargetDataLayout {
449    #[inline]
450    fn data_layout(&self) -> &TargetDataLayout {
451        self
452    }
453}
454
455// used by rust-analyzer
456impl HasDataLayout for &TargetDataLayout {
457    #[inline]
458    fn data_layout(&self) -> &TargetDataLayout {
459        (**self).data_layout()
460    }
461}
462
463/// Endianness of the target, which must match cfg(target-endian).
464#[derive(Copy, Clone, PartialEq, Eq)]
465pub enum Endian {
466    Little,
467    Big,
468}
469
470impl Endian {
471    pub fn as_str(&self) -> &'static str {
472        match self {
473            Self::Little => "little",
474            Self::Big => "big",
475        }
476    }
477}
478
479impl fmt::Debug for Endian {
480    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
481        f.write_str(self.as_str())
482    }
483}
484
485impl FromStr for Endian {
486    type Err = String;
487
488    fn from_str(s: &str) -> Result<Self, Self::Err> {
489        match s {
490            "little" => Ok(Self::Little),
491            "big" => Ok(Self::Big),
492            _ => Err(format!(r#"unknown endian: "{s}""#)),
493        }
494    }
495}
496
497/// Size of a type in bytes.
498#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
499#[cfg_attr(
500    feature = "nightly",
501    derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic)
502)]
503pub struct Size {
504    raw: u64,
505}
506
507#[cfg(feature = "nightly")]
508impl StableOrd for Size {
509    const CAN_USE_UNSTABLE_SORT: bool = true;
510
511    // `Ord` is implemented as just comparing numerical values and numerical values
512    // are not changed by (de-)serialization.
513    const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
514}
515
516// This is debug-printed a lot in larger structs, don't waste too much space there
517impl fmt::Debug for Size {
518    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
519        write!(f, "Size({} bytes)", self.bytes())
520    }
521}
522
523impl Size {
524    pub const ZERO: Size = Size { raw: 0 };
525
526    /// Rounds `bits` up to the next-higher byte boundary, if `bits` is
527    /// not a multiple of 8.
528    pub fn from_bits(bits: impl TryInto<u64>) -> Size {
529        let bits = bits.try_into().ok().unwrap();
530        // Avoid potential overflow from `bits + 7`.
531        Size { raw: bits / 8 + ((bits % 8) + 7) / 8 }
532    }
533
534    #[inline]
535    pub fn from_bytes(bytes: impl TryInto<u64>) -> Size {
536        let bytes: u64 = bytes.try_into().ok().unwrap();
537        Size { raw: bytes }
538    }
539
540    #[inline]
541    pub fn bytes(self) -> u64 {
542        self.raw
543    }
544
545    #[inline]
546    pub fn bytes_usize(self) -> usize {
547        self.bytes().try_into().unwrap()
548    }
549
550    #[inline]
551    pub fn bits(self) -> u64 {
552        #[cold]
553        fn overflow(bytes: u64) -> ! {
554            panic!("Size::bits: {bytes} bytes in bits doesn't fit in u64")
555        }
556
557        self.bytes().checked_mul(8).unwrap_or_else(|| overflow(self.bytes()))
558    }
559
560    #[inline]
561    pub fn bits_usize(self) -> usize {
562        self.bits().try_into().unwrap()
563    }
564
565    #[inline]
566    pub fn align_to(self, align: Align) -> Size {
567        let mask = align.bytes() - 1;
568        Size::from_bytes((self.bytes() + mask) & !mask)
569    }
570
571    #[inline]
572    pub fn is_aligned(self, align: Align) -> bool {
573        let mask = align.bytes() - 1;
574        self.bytes() & mask == 0
575    }
576
577    #[inline]
578    pub fn checked_add<C: HasDataLayout>(self, offset: Size, cx: &C) -> Option<Size> {
579        let dl = cx.data_layout();
580
581        let bytes = self.bytes().checked_add(offset.bytes())?;
582
583        if bytes < dl.obj_size_bound() { Some(Size::from_bytes(bytes)) } else { None }
584    }
585
586    #[inline]
587    pub fn checked_mul<C: HasDataLayout>(self, count: u64, cx: &C) -> Option<Size> {
588        let dl = cx.data_layout();
589
590        let bytes = self.bytes().checked_mul(count)?;
591        if bytes < dl.obj_size_bound() { Some(Size::from_bytes(bytes)) } else { None }
592    }
593
594    /// Truncates `value` to `self` bits and then sign-extends it to 128 bits
595    /// (i.e., if it is negative, fill with 1's on the left).
596    #[inline]
597    pub fn sign_extend(self, value: u128) -> i128 {
598        let size = self.bits();
599        if size == 0 {
600            // Truncated until nothing is left.
601            return 0;
602        }
603        // Sign-extend it.
604        let shift = 128 - size;
605        // Shift the unsigned value to the left, then shift back to the right as signed
606        // (essentially fills with sign bit on the left).
607        ((value << shift) as i128) >> shift
608    }
609
610    /// Truncates `value` to `self` bits.
611    #[inline]
612    pub fn truncate(self, value: u128) -> u128 {
613        let size = self.bits();
614        if size == 0 {
615            // Truncated until nothing is left.
616            return 0;
617        }
618        let shift = 128 - size;
619        // Truncate (shift left to drop out leftover values, shift right to fill with zeroes).
620        (value << shift) >> shift
621    }
622
623    #[inline]
624    pub fn signed_int_min(&self) -> i128 {
625        self.sign_extend(1_u128 << (self.bits() - 1))
626    }
627
628    #[inline]
629    pub fn signed_int_max(&self) -> i128 {
630        i128::MAX >> (128 - self.bits())
631    }
632
633    #[inline]
634    pub fn unsigned_int_max(&self) -> u128 {
635        u128::MAX >> (128 - self.bits())
636    }
637}
638
639// Panicking addition, subtraction and multiplication for convenience.
640// Avoid during layout computation, return `LayoutError` instead.
641
642impl Add for Size {
643    type Output = Size;
644    #[inline]
645    fn add(self, other: Size) -> Size {
646        Size::from_bytes(self.bytes().checked_add(other.bytes()).unwrap_or_else(|| {
647            panic!("Size::add: {} + {} doesn't fit in u64", self.bytes(), other.bytes())
648        }))
649    }
650}
651
652impl Sub for Size {
653    type Output = Size;
654    #[inline]
655    fn sub(self, other: Size) -> Size {
656        Size::from_bytes(self.bytes().checked_sub(other.bytes()).unwrap_or_else(|| {
657            panic!("Size::sub: {} - {} would result in negative size", self.bytes(), other.bytes())
658        }))
659    }
660}
661
662impl Mul<Size> for u64 {
663    type Output = Size;
664    #[inline]
665    fn mul(self, size: Size) -> Size {
666        size * self
667    }
668}
669
670impl Mul<u64> for Size {
671    type Output = Size;
672    #[inline]
673    fn mul(self, count: u64) -> Size {
674        match self.bytes().checked_mul(count) {
675            Some(bytes) => Size::from_bytes(bytes),
676            None => panic!("Size::mul: {} * {} doesn't fit in u64", self.bytes(), count),
677        }
678    }
679}
680
681impl AddAssign for Size {
682    #[inline]
683    fn add_assign(&mut self, other: Size) {
684        *self = *self + other;
685    }
686}
687
688#[cfg(feature = "nightly")]
689impl Step for Size {
690    #[inline]
691    fn steps_between(start: &Self, end: &Self) -> (usize, Option<usize>) {
692        u64::steps_between(&start.bytes(), &end.bytes())
693    }
694
695    #[inline]
696    fn forward_checked(start: Self, count: usize) -> Option<Self> {
697        u64::forward_checked(start.bytes(), count).map(Self::from_bytes)
698    }
699
700    #[inline]
701    fn forward(start: Self, count: usize) -> Self {
702        Self::from_bytes(u64::forward(start.bytes(), count))
703    }
704
705    #[inline]
706    unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
707        Self::from_bytes(unsafe { u64::forward_unchecked(start.bytes(), count) })
708    }
709
710    #[inline]
711    fn backward_checked(start: Self, count: usize) -> Option<Self> {
712        u64::backward_checked(start.bytes(), count).map(Self::from_bytes)
713    }
714
715    #[inline]
716    fn backward(start: Self, count: usize) -> Self {
717        Self::from_bytes(u64::backward(start.bytes(), count))
718    }
719
720    #[inline]
721    unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
722        Self::from_bytes(unsafe { u64::backward_unchecked(start.bytes(), count) })
723    }
724}
725
726/// Alignment of a type in bytes (always a power of two).
727#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
728#[cfg_attr(
729    feature = "nightly",
730    derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic)
731)]
732pub struct Align {
733    pow2: u8,
734}
735
736// This is debug-printed a lot in larger structs, don't waste too much space there
737impl fmt::Debug for Align {
738    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
739        write!(f, "Align({} bytes)", self.bytes())
740    }
741}
742
743#[derive(Clone, Copy)]
744pub enum AlignFromBytesError {
745    NotPowerOfTwo(u64),
746    TooLarge(u64),
747}
748
749impl AlignFromBytesError {
750    pub fn diag_ident(self) -> &'static str {
751        match self {
752            Self::NotPowerOfTwo(_) => "not_power_of_two",
753            Self::TooLarge(_) => "too_large",
754        }
755    }
756
757    pub fn align(self) -> u64 {
758        let (Self::NotPowerOfTwo(align) | Self::TooLarge(align)) = self;
759        align
760    }
761}
762
763impl fmt::Debug for AlignFromBytesError {
764    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
765        fmt::Display::fmt(self, f)
766    }
767}
768
769impl fmt::Display for AlignFromBytesError {
770    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
771        match self {
772            AlignFromBytesError::NotPowerOfTwo(align) => write!(f, "`{align}` is not a power of 2"),
773            AlignFromBytesError::TooLarge(align) => write!(f, "`{align}` is too large"),
774        }
775    }
776}
777
778impl Align {
779    pub const ONE: Align = Align { pow2: 0 };
780    pub const EIGHT: Align = Align { pow2: 3 };
781    // LLVM has a maximal supported alignment of 2^29, we inherit that.
782    pub const MAX: Align = Align { pow2: 29 };
783
784    #[inline]
785    pub fn from_bits(bits: u64) -> Result<Align, AlignFromBytesError> {
786        Align::from_bytes(Size::from_bits(bits).bytes())
787    }
788
789    #[inline]
790    pub const fn from_bytes(align: u64) -> Result<Align, AlignFromBytesError> {
791        // Treat an alignment of 0 bytes like 1-byte alignment.
792        if align == 0 {
793            return Ok(Align::ONE);
794        }
795
796        #[cold]
797        const fn not_power_of_2(align: u64) -> AlignFromBytesError {
798            AlignFromBytesError::NotPowerOfTwo(align)
799        }
800
801        #[cold]
802        const fn too_large(align: u64) -> AlignFromBytesError {
803            AlignFromBytesError::TooLarge(align)
804        }
805
806        let tz = align.trailing_zeros();
807        if align != (1 << tz) {
808            return Err(not_power_of_2(align));
809        }
810
811        let pow2 = tz as u8;
812        if pow2 > Self::MAX.pow2 {
813            return Err(too_large(align));
814        }
815
816        Ok(Align { pow2 })
817    }
818
819    #[inline]
820    pub const fn bytes(self) -> u64 {
821        1 << self.pow2
822    }
823
824    #[inline]
825    pub fn bytes_usize(self) -> usize {
826        self.bytes().try_into().unwrap()
827    }
828
829    #[inline]
830    pub const fn bits(self) -> u64 {
831        self.bytes() * 8
832    }
833
834    #[inline]
835    pub fn bits_usize(self) -> usize {
836        self.bits().try_into().unwrap()
837    }
838
839    /// Obtain the greatest factor of `size` that is an alignment
840    /// (the largest power of two the Size is a multiple of).
841    ///
842    /// Note that all numbers are factors of 0
843    #[inline]
844    pub fn max_aligned_factor(size: Size) -> Align {
845        Align { pow2: size.bytes().trailing_zeros() as u8 }
846    }
847
848    /// Reduces Align to an aligned factor of `size`.
849    #[inline]
850    pub fn restrict_for_offset(self, size: Size) -> Align {
851        self.min(Align::max_aligned_factor(size))
852    }
853}
854
855/// A pair of alignments, ABI-mandated and preferred.
856///
857/// The "preferred" alignment is an LLVM concept that is virtually meaningless to Rust code:
858/// it is not exposed semantically to programmers nor can they meaningfully affect it.
859/// The only concern for us is that preferred alignment must not be less than the mandated alignment
860/// and thus in practice the two values are almost always identical.
861///
862/// An example of a rare thing actually affected by preferred alignment is aligning of statics.
863/// It is of effectively no consequence for layout in structs and on the stack.
864#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
865#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
866pub struct AbiAlign {
867    pub abi: Align,
868}
869
870impl AbiAlign {
871    #[inline]
872    pub fn new(align: Align) -> AbiAlign {
873        AbiAlign { abi: align }
874    }
875
876    #[inline]
877    pub fn min(self, other: AbiAlign) -> AbiAlign {
878        AbiAlign { abi: self.abi.min(other.abi) }
879    }
880
881    #[inline]
882    pub fn max(self, other: AbiAlign) -> AbiAlign {
883        AbiAlign { abi: self.abi.max(other.abi) }
884    }
885}
886
887impl Deref for AbiAlign {
888    type Target = Align;
889
890    fn deref(&self) -> &Self::Target {
891        &self.abi
892    }
893}
894
895/// Integers, also used for enum discriminants.
896#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
897#[cfg_attr(
898    feature = "nightly",
899    derive(Encodable_NoContext, Decodable_NoContext, HashStable_Generic)
900)]
901pub enum Integer {
902    I8,
903    I16,
904    I32,
905    I64,
906    I128,
907}
908
909impl Integer {
910    pub fn int_ty_str(self) -> &'static str {
911        use Integer::*;
912        match self {
913            I8 => "i8",
914            I16 => "i16",
915            I32 => "i32",
916            I64 => "i64",
917            I128 => "i128",
918        }
919    }
920
921    pub fn uint_ty_str(self) -> &'static str {
922        use Integer::*;
923        match self {
924            I8 => "u8",
925            I16 => "u16",
926            I32 => "u32",
927            I64 => "u64",
928            I128 => "u128",
929        }
930    }
931
932    #[inline]
933    pub fn size(self) -> Size {
934        use Integer::*;
935        match self {
936            I8 => Size::from_bytes(1),
937            I16 => Size::from_bytes(2),
938            I32 => Size::from_bytes(4),
939            I64 => Size::from_bytes(8),
940            I128 => Size::from_bytes(16),
941        }
942    }
943
944    /// Gets the Integer type from an IntegerType.
945    pub fn from_attr<C: HasDataLayout>(cx: &C, ity: IntegerType) -> Integer {
946        let dl = cx.data_layout();
947
948        match ity {
949            IntegerType::Pointer(_) => dl.ptr_sized_integer(),
950            IntegerType::Fixed(x, _) => x,
951        }
952    }
953
954    pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAlign {
955        use Integer::*;
956        let dl = cx.data_layout();
957
958        match self {
959            I8 => dl.i8_align,
960            I16 => dl.i16_align,
961            I32 => dl.i32_align,
962            I64 => dl.i64_align,
963            I128 => dl.i128_align,
964        }
965    }
966
967    /// Returns the largest signed value that can be represented by this Integer.
968    #[inline]
969    pub fn signed_max(self) -> i128 {
970        use Integer::*;
971        match self {
972            I8 => i8::MAX as i128,
973            I16 => i16::MAX as i128,
974            I32 => i32::MAX as i128,
975            I64 => i64::MAX as i128,
976            I128 => i128::MAX,
977        }
978    }
979
980    /// Finds the smallest Integer type which can represent the signed value.
981    #[inline]
982    pub fn fit_signed(x: i128) -> Integer {
983        use Integer::*;
984        match x {
985            -0x0000_0000_0000_0080..=0x0000_0000_0000_007f => I8,
986            -0x0000_0000_0000_8000..=0x0000_0000_0000_7fff => I16,
987            -0x0000_0000_8000_0000..=0x0000_0000_7fff_ffff => I32,
988            -0x8000_0000_0000_0000..=0x7fff_ffff_ffff_ffff => I64,
989            _ => I128,
990        }
991    }
992
993    /// Finds the smallest Integer type which can represent the unsigned value.
994    #[inline]
995    pub fn fit_unsigned(x: u128) -> Integer {
996        use Integer::*;
997        match x {
998            0..=0x0000_0000_0000_00ff => I8,
999            0..=0x0000_0000_0000_ffff => I16,
1000            0..=0x0000_0000_ffff_ffff => I32,
1001            0..=0xffff_ffff_ffff_ffff => I64,
1002            _ => I128,
1003        }
1004    }
1005
1006    /// Finds the smallest integer with the given alignment.
1007    pub fn for_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Option<Integer> {
1008        use Integer::*;
1009        let dl = cx.data_layout();
1010
1011        [I8, I16, I32, I64, I128].into_iter().find(|&candidate| {
1012            wanted == candidate.align(dl).abi && wanted.bytes() == candidate.size().bytes()
1013        })
1014    }
1015
1016    /// Find the largest integer with the given alignment or less.
1017    pub fn approximate_align<C: HasDataLayout>(cx: &C, wanted: Align) -> Integer {
1018        use Integer::*;
1019        let dl = cx.data_layout();
1020
1021        // FIXME(eddyb) maybe include I128 in the future, when it works everywhere.
1022        for candidate in [I64, I32, I16] {
1023            if wanted >= candidate.align(dl).abi && wanted.bytes() >= candidate.size().bytes() {
1024                return candidate;
1025            }
1026        }
1027        I8
1028    }
1029
1030    // FIXME(eddyb) consolidate this and other methods that find the appropriate
1031    // `Integer` given some requirements.
1032    #[inline]
1033    pub fn from_size(size: Size) -> Result<Self, String> {
1034        match size.bits() {
1035            8 => Ok(Integer::I8),
1036            16 => Ok(Integer::I16),
1037            32 => Ok(Integer::I32),
1038            64 => Ok(Integer::I64),
1039            128 => Ok(Integer::I128),
1040            _ => Err(format!("rust does not support integers with {} bits", size.bits())),
1041        }
1042    }
1043}
1044
1045/// Floating-point types.
1046#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
1047#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1048pub enum Float {
1049    F16,
1050    F32,
1051    F64,
1052    F128,
1053}
1054
1055impl Float {
1056    pub fn size(self) -> Size {
1057        use Float::*;
1058
1059        match self {
1060            F16 => Size::from_bits(16),
1061            F32 => Size::from_bits(32),
1062            F64 => Size::from_bits(64),
1063            F128 => Size::from_bits(128),
1064        }
1065    }
1066
1067    pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAlign {
1068        use Float::*;
1069        let dl = cx.data_layout();
1070
1071        match self {
1072            F16 => dl.f16_align,
1073            F32 => dl.f32_align,
1074            F64 => dl.f64_align,
1075            F128 => dl.f128_align,
1076        }
1077    }
1078}
1079
1080/// Fundamental unit of memory access and layout.
1081#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
1082#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1083pub enum Primitive {
1084    /// The `bool` is the signedness of the `Integer` type.
1085    ///
1086    /// One would think we would not care about such details this low down,
1087    /// but some ABIs are described in terms of C types and ISAs where the
1088    /// integer arithmetic is done on {sign,zero}-extended registers, e.g.
1089    /// a negative integer passed by zero-extension will appear positive in
1090    /// the callee, and most operations on it will produce the wrong values.
1091    Int(Integer, bool),
1092    Float(Float),
1093    Pointer(AddressSpace),
1094}
1095
1096impl Primitive {
1097    pub fn size<C: HasDataLayout>(self, cx: &C) -> Size {
1098        use Primitive::*;
1099        let dl = cx.data_layout();
1100
1101        match self {
1102            Int(i, _) => i.size(),
1103            Float(f) => f.size(),
1104            // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
1105            // different address spaces can have different sizes
1106            // (but TargetDataLayout doesn't currently parse that part of the DL string)
1107            Pointer(_) => dl.pointer_size,
1108        }
1109    }
1110
1111    pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAlign {
1112        use Primitive::*;
1113        let dl = cx.data_layout();
1114
1115        match self {
1116            Int(i, _) => i.align(dl),
1117            Float(f) => f.align(dl),
1118            // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
1119            // different address spaces can have different alignments
1120            // (but TargetDataLayout doesn't currently parse that part of the DL string)
1121            Pointer(_) => dl.pointer_align,
1122        }
1123    }
1124}
1125
1126/// Inclusive wrap-around range of valid values, that is, if
1127/// start > end, it represents `start..=MAX`, followed by `0..=end`.
1128///
1129/// That is, for an i8 primitive, a range of `254..=2` means following
1130/// sequence:
1131///
1132///    254 (-2), 255 (-1), 0, 1, 2
1133///
1134/// This is intended specifically to mirror LLVM’s `!range` metadata semantics.
1135#[derive(Clone, Copy, PartialEq, Eq, Hash)]
1136#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1137pub struct WrappingRange {
1138    pub start: u128,
1139    pub end: u128,
1140}
1141
1142impl WrappingRange {
1143    pub fn full(size: Size) -> Self {
1144        Self { start: 0, end: size.unsigned_int_max() }
1145    }
1146
1147    /// Returns `true` if `v` is contained in the range.
1148    #[inline(always)]
1149    pub fn contains(&self, v: u128) -> bool {
1150        if self.start <= self.end {
1151            self.start <= v && v <= self.end
1152        } else {
1153            self.start <= v || v <= self.end
1154        }
1155    }
1156
1157    /// Returns `self` with replaced `start`
1158    #[inline(always)]
1159    fn with_start(mut self, start: u128) -> Self {
1160        self.start = start;
1161        self
1162    }
1163
1164    /// Returns `self` with replaced `end`
1165    #[inline(always)]
1166    fn with_end(mut self, end: u128) -> Self {
1167        self.end = end;
1168        self
1169    }
1170
1171    /// Returns `true` if `size` completely fills the range.
1172    #[inline]
1173    fn is_full_for(&self, size: Size) -> bool {
1174        let max_value = size.unsigned_int_max();
1175        debug_assert!(self.start <= max_value && self.end <= max_value);
1176        self.start == (self.end.wrapping_add(1) & max_value)
1177    }
1178}
1179
1180impl fmt::Debug for WrappingRange {
1181    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1182        if self.start > self.end {
1183            write!(fmt, "(..={}) | ({}..)", self.end, self.start)?;
1184        } else {
1185            write!(fmt, "{}..={}", self.start, self.end)?;
1186        }
1187        Ok(())
1188    }
1189}
1190
1191/// Information about one scalar component of a Rust type.
1192#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1193#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1194pub enum Scalar {
1195    Initialized {
1196        value: Primitive,
1197
1198        // FIXME(eddyb) always use the shortest range, e.g., by finding
1199        // the largest space between two consecutive valid values and
1200        // taking everything else as the (shortest) valid range.
1201        valid_range: WrappingRange,
1202    },
1203    Union {
1204        /// Even for unions, we need to use the correct registers for the kind of
1205        /// values inside the union, so we keep the `Primitive` type around. We
1206        /// also use it to compute the size of the scalar.
1207        /// However, unions never have niches and even allow undef,
1208        /// so there is no `valid_range`.
1209        value: Primitive,
1210    },
1211}
1212
1213impl Scalar {
1214    #[inline]
1215    pub fn is_bool(&self) -> bool {
1216        use Integer::*;
1217        matches!(
1218            self,
1219            Scalar::Initialized {
1220                value: Primitive::Int(I8, false),
1221                valid_range: WrappingRange { start: 0, end: 1 }
1222            }
1223        )
1224    }
1225
1226    /// Get the primitive representation of this type, ignoring the valid range and whether the
1227    /// value is allowed to be undefined (due to being a union).
1228    pub fn primitive(&self) -> Primitive {
1229        match *self {
1230            Scalar::Initialized { value, .. } | Scalar::Union { value } => value,
1231        }
1232    }
1233
1234    pub fn align(self, cx: &impl HasDataLayout) -> AbiAlign {
1235        self.primitive().align(cx)
1236    }
1237
1238    pub fn size(self, cx: &impl HasDataLayout) -> Size {
1239        self.primitive().size(cx)
1240    }
1241
1242    #[inline]
1243    pub fn to_union(&self) -> Self {
1244        Self::Union { value: self.primitive() }
1245    }
1246
1247    #[inline]
1248    pub fn valid_range(&self, cx: &impl HasDataLayout) -> WrappingRange {
1249        match *self {
1250            Scalar::Initialized { valid_range, .. } => valid_range,
1251            Scalar::Union { value } => WrappingRange::full(value.size(cx)),
1252        }
1253    }
1254
1255    #[inline]
1256    /// Allows the caller to mutate the valid range. This operation will panic if attempted on a
1257    /// union.
1258    pub fn valid_range_mut(&mut self) -> &mut WrappingRange {
1259        match self {
1260            Scalar::Initialized { valid_range, .. } => valid_range,
1261            Scalar::Union { .. } => panic!("cannot change the valid range of a union"),
1262        }
1263    }
1264
1265    /// Returns `true` if all possible numbers are valid, i.e `valid_range` covers the whole
1266    /// layout.
1267    #[inline]
1268    pub fn is_always_valid<C: HasDataLayout>(&self, cx: &C) -> bool {
1269        match *self {
1270            Scalar::Initialized { valid_range, .. } => valid_range.is_full_for(self.size(cx)),
1271            Scalar::Union { .. } => true,
1272        }
1273    }
1274
1275    /// Returns `true` if this type can be left uninit.
1276    #[inline]
1277    pub fn is_uninit_valid(&self) -> bool {
1278        match *self {
1279            Scalar::Initialized { .. } => false,
1280            Scalar::Union { .. } => true,
1281        }
1282    }
1283
1284    /// Returns `true` if this is a signed integer scalar
1285    #[inline]
1286    pub fn is_signed(&self) -> bool {
1287        match self.primitive() {
1288            Primitive::Int(_, signed) => signed,
1289            _ => false,
1290        }
1291    }
1292}
1293
1294// NOTE: This struct is generic over the FieldIdx for rust-analyzer usage.
1295/// Describes how the fields of a type are located in memory.
1296#[derive(PartialEq, Eq, Hash, Clone, Debug)]
1297#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1298pub enum FieldsShape<FieldIdx: Idx> {
1299    /// Scalar primitives and `!`, which never have fields.
1300    Primitive,
1301
1302    /// All fields start at no offset. The `usize` is the field count.
1303    Union(NonZeroUsize),
1304
1305    /// Array/vector-like placement, with all fields of identical types.
1306    Array { stride: Size, count: u64 },
1307
1308    /// Struct-like placement, with precomputed offsets.
1309    ///
1310    /// Fields are guaranteed to not overlap, but note that gaps
1311    /// before, between and after all the fields are NOT always
1312    /// padding, and as such their contents may not be discarded.
1313    /// For example, enum variants leave a gap at the start,
1314    /// where the discriminant field in the enum layout goes.
1315    Arbitrary {
1316        /// Offsets for the first byte of each field,
1317        /// ordered to match the source definition order.
1318        /// This vector does not go in increasing order.
1319        // FIXME(eddyb) use small vector optimization for the common case.
1320        offsets: IndexVec<FieldIdx, Size>,
1321
1322        /// Maps source order field indices to memory order indices,
1323        /// depending on how the fields were reordered (if at all).
1324        /// This is a permutation, with both the source order and the
1325        /// memory order using the same (0..n) index ranges.
1326        ///
1327        /// Note that during computation of `memory_index`, sometimes
1328        /// it is easier to operate on the inverse mapping (that is,
1329        /// from memory order to source order), and that is usually
1330        /// named `inverse_memory_index`.
1331        ///
1332        // FIXME(eddyb) build a better abstraction for permutations, if possible.
1333        // FIXME(camlorn) also consider small vector optimization here.
1334        memory_index: IndexVec<FieldIdx, u32>,
1335    },
1336}
1337
1338impl<FieldIdx: Idx> FieldsShape<FieldIdx> {
1339    #[inline]
1340    pub fn count(&self) -> usize {
1341        match *self {
1342            FieldsShape::Primitive => 0,
1343            FieldsShape::Union(count) => count.get(),
1344            FieldsShape::Array { count, .. } => count.try_into().unwrap(),
1345            FieldsShape::Arbitrary { ref offsets, .. } => offsets.len(),
1346        }
1347    }
1348
1349    #[inline]
1350    pub fn offset(&self, i: usize) -> Size {
1351        match *self {
1352            FieldsShape::Primitive => {
1353                unreachable!("FieldsShape::offset: `Primitive`s have no fields")
1354            }
1355            FieldsShape::Union(count) => {
1356                assert!(i < count.get(), "tried to access field {i} of union with {count} fields");
1357                Size::ZERO
1358            }
1359            FieldsShape::Array { stride, count } => {
1360                let i = u64::try_from(i).unwrap();
1361                assert!(i < count, "tried to access field {i} of array with {count} fields");
1362                stride * i
1363            }
1364            FieldsShape::Arbitrary { ref offsets, .. } => offsets[FieldIdx::new(i)],
1365        }
1366    }
1367
1368    #[inline]
1369    pub fn memory_index(&self, i: usize) -> usize {
1370        match *self {
1371            FieldsShape::Primitive => {
1372                unreachable!("FieldsShape::memory_index: `Primitive`s have no fields")
1373            }
1374            FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
1375            FieldsShape::Arbitrary { ref memory_index, .. } => {
1376                memory_index[FieldIdx::new(i)].try_into().unwrap()
1377            }
1378        }
1379    }
1380
1381    /// Gets source indices of the fields by increasing offsets.
1382    #[inline]
1383    pub fn index_by_increasing_offset(&self) -> impl ExactSizeIterator<Item = usize> {
1384        let mut inverse_small = [0u8; 64];
1385        let mut inverse_big = IndexVec::new();
1386        let use_small = self.count() <= inverse_small.len();
1387
1388        // We have to write this logic twice in order to keep the array small.
1389        if let FieldsShape::Arbitrary { ref memory_index, .. } = *self {
1390            if use_small {
1391                for (field_idx, &mem_idx) in memory_index.iter_enumerated() {
1392                    inverse_small[mem_idx as usize] = field_idx.index() as u8;
1393                }
1394            } else {
1395                inverse_big = memory_index.invert_bijective_mapping();
1396            }
1397        }
1398
1399        // Primitives don't really have fields in the way that structs do,
1400        // but having this return an empty iterator for them is unhelpful
1401        // since that makes them look kinda like ZSTs, which they're not.
1402        let pseudofield_count = if let FieldsShape::Primitive = self { 1 } else { self.count() };
1403
1404        (0..pseudofield_count).map(move |i| match *self {
1405            FieldsShape::Primitive | FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
1406            FieldsShape::Arbitrary { .. } => {
1407                if use_small {
1408                    inverse_small[i] as usize
1409                } else {
1410                    inverse_big[i as u32].index()
1411                }
1412            }
1413        })
1414    }
1415}
1416
1417/// An identifier that specifies the address space that some operation
1418/// should operate on. Special address spaces have an effect on code generation,
1419/// depending on the target and the address spaces it implements.
1420#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1421#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1422pub struct AddressSpace(pub u32);
1423
1424impl AddressSpace {
1425    /// The default address space, corresponding to data space.
1426    pub const DATA: Self = AddressSpace(0);
1427}
1428
1429/// The way we represent values to the backend
1430///
1431/// Previously this was conflated with the "ABI" a type is given, as in the platform-specific ABI.
1432/// In reality, this implies little about that, but is mostly used to describe the syntactic form
1433/// emitted for the backend, as most backends handle SSA values and blobs of memory differently.
1434/// The psABI may need consideration in doing so, but this enum does not constitute a promise for
1435/// how the value will be lowered to the calling convention, in itself.
1436///
1437/// Generally, a codegen backend will prefer to handle smaller values as a scalar or short vector,
1438/// and larger values will usually prefer to be represented as memory.
1439#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1440#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1441pub enum BackendRepr {
1442    Scalar(Scalar),
1443    ScalarPair(Scalar, Scalar),
1444    SimdVector {
1445        element: Scalar,
1446        count: u64,
1447    },
1448    // FIXME: I sometimes use memory, sometimes use an IR aggregate!
1449    Memory {
1450        /// If true, the size is exact, otherwise it's only a lower bound.
1451        sized: bool,
1452    },
1453}
1454
1455impl BackendRepr {
1456    /// Returns `true` if the layout corresponds to an unsized type.
1457    #[inline]
1458    pub fn is_unsized(&self) -> bool {
1459        match *self {
1460            BackendRepr::Scalar(_)
1461            | BackendRepr::ScalarPair(..)
1462            | BackendRepr::SimdVector { .. } => false,
1463            BackendRepr::Memory { sized } => !sized,
1464        }
1465    }
1466
1467    #[inline]
1468    pub fn is_sized(&self) -> bool {
1469        !self.is_unsized()
1470    }
1471
1472    /// Returns `true` if this is a single signed integer scalar.
1473    /// Sanity check: panics if this is not a scalar type (see PR #70189).
1474    #[inline]
1475    pub fn is_signed(&self) -> bool {
1476        match self {
1477            BackendRepr::Scalar(scal) => scal.is_signed(),
1478            _ => panic!("`is_signed` on non-scalar ABI {self:?}"),
1479        }
1480    }
1481
1482    /// Returns `true` if this is a scalar type
1483    #[inline]
1484    pub fn is_scalar(&self) -> bool {
1485        matches!(*self, BackendRepr::Scalar(_))
1486    }
1487
1488    /// Returns `true` if this is a bool
1489    #[inline]
1490    pub fn is_bool(&self) -> bool {
1491        matches!(*self, BackendRepr::Scalar(s) if s.is_bool())
1492    }
1493
1494    /// The psABI alignment for a `Scalar` or `ScalarPair`
1495    ///
1496    /// `None` for other variants.
1497    pub fn scalar_align<C: HasDataLayout>(&self, cx: &C) -> Option<Align> {
1498        match *self {
1499            BackendRepr::Scalar(s) => Some(s.align(cx).abi),
1500            BackendRepr::ScalarPair(s1, s2) => Some(s1.align(cx).max(s2.align(cx)).abi),
1501            // The align of a Vector can vary in surprising ways
1502            BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None,
1503        }
1504    }
1505
1506    /// The psABI size for a `Scalar` or `ScalarPair`
1507    ///
1508    /// `None` for other variants
1509    pub fn scalar_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
1510        match *self {
1511            // No padding in scalars.
1512            BackendRepr::Scalar(s) => Some(s.size(cx)),
1513            // May have some padding between the pair.
1514            BackendRepr::ScalarPair(s1, s2) => {
1515                let field2_offset = s1.size(cx).align_to(s2.align(cx).abi);
1516                let size = (field2_offset + s2.size(cx)).align_to(
1517                    self.scalar_align(cx)
1518                        // We absolutely must have an answer here or everything is FUBAR.
1519                        .unwrap(),
1520                );
1521                Some(size)
1522            }
1523            // The size of a Vector can vary in surprising ways
1524            BackendRepr::SimdVector { .. } | BackendRepr::Memory { .. } => None,
1525        }
1526    }
1527
1528    /// Discard validity range information and allow undef.
1529    pub fn to_union(&self) -> Self {
1530        match *self {
1531            BackendRepr::Scalar(s) => BackendRepr::Scalar(s.to_union()),
1532            BackendRepr::ScalarPair(s1, s2) => {
1533                BackendRepr::ScalarPair(s1.to_union(), s2.to_union())
1534            }
1535            BackendRepr::SimdVector { element, count } => {
1536                BackendRepr::SimdVector { element: element.to_union(), count }
1537            }
1538            BackendRepr::Memory { .. } => BackendRepr::Memory { sized: true },
1539        }
1540    }
1541
1542    pub fn eq_up_to_validity(&self, other: &Self) -> bool {
1543        match (self, other) {
1544            // Scalar, Vector, ScalarPair have `Scalar` in them where we ignore validity ranges.
1545            // We do *not* ignore the sign since it matters for some ABIs (e.g. s390x).
1546            (BackendRepr::Scalar(l), BackendRepr::Scalar(r)) => l.primitive() == r.primitive(),
1547            (
1548                BackendRepr::SimdVector { element: element_l, count: count_l },
1549                BackendRepr::SimdVector { element: element_r, count: count_r },
1550            ) => element_l.primitive() == element_r.primitive() && count_l == count_r,
1551            (BackendRepr::ScalarPair(l1, l2), BackendRepr::ScalarPair(r1, r2)) => {
1552                l1.primitive() == r1.primitive() && l2.primitive() == r2.primitive()
1553            }
1554            // Everything else must be strictly identical.
1555            _ => self == other,
1556        }
1557    }
1558}
1559
1560// NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage.
1561#[derive(PartialEq, Eq, Hash, Clone, Debug)]
1562#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1563pub enum Variants<FieldIdx: Idx, VariantIdx: Idx> {
1564    /// A type with no valid variants. Must be uninhabited.
1565    Empty,
1566
1567    /// Single enum variants, structs/tuples, unions, and all non-ADTs.
1568    Single {
1569        /// Always `0` for types that cannot have multiple variants.
1570        index: VariantIdx,
1571    },
1572
1573    /// Enum-likes with more than one variant: each variant comes with
1574    /// a *discriminant* (usually the same as the variant index but the user can
1575    /// assign explicit discriminant values). That discriminant is encoded
1576    /// as a *tag* on the machine. The layout of each variant is
1577    /// a struct, and they all have space reserved for the tag.
1578    /// For enums, the tag is the sole field of the layout.
1579    Multiple {
1580        tag: Scalar,
1581        tag_encoding: TagEncoding<VariantIdx>,
1582        tag_field: FieldIdx,
1583        variants: IndexVec<VariantIdx, LayoutData<FieldIdx, VariantIdx>>,
1584    },
1585}
1586
1587// NOTE: This struct is generic over the VariantIdx for rust-analyzer usage.
1588#[derive(PartialEq, Eq, Hash, Clone, Debug)]
1589#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1590pub enum TagEncoding<VariantIdx: Idx> {
1591    /// The tag directly stores the discriminant, but possibly with a smaller layout
1592    /// (so converting the tag to the discriminant can require sign extension).
1593    Direct,
1594
1595    /// Niche (values invalid for a type) encoding the discriminant:
1596    /// Discriminant and variant index coincide.
1597    /// The variant `untagged_variant` contains a niche at an arbitrary
1598    /// offset (field `tag_field` of the enum), which for a variant with
1599    /// discriminant `d` is set to
1600    /// `(d - niche_variants.start).wrapping_add(niche_start)`
1601    /// (this is wrapping arithmetic using the type of the niche field).
1602    ///
1603    /// For example, `Option<(usize, &T)>`  is represented such that
1604    /// `None` has a null pointer for the second tuple field, and
1605    /// `Some` is the identity function (with a non-null reference).
1606    ///
1607    /// Other variants that are not `untagged_variant` and that are outside the `niche_variants`
1608    /// range cannot be represented; they must be uninhabited.
1609    Niche {
1610        untagged_variant: VariantIdx,
1611        /// This range *may* contain `untagged_variant`; that is then just a "dead value" and
1612        /// not used to encode anything.
1613        niche_variants: RangeInclusive<VariantIdx>,
1614        /// This is inbounds of the type of the niche field
1615        /// (not sign-extended, i.e., all bits beyond the niche field size are 0).
1616        niche_start: u128,
1617    },
1618}
1619
1620#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
1621#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1622pub struct Niche {
1623    pub offset: Size,
1624    pub value: Primitive,
1625    pub valid_range: WrappingRange,
1626}
1627
1628impl Niche {
1629    pub fn from_scalar<C: HasDataLayout>(cx: &C, offset: Size, scalar: Scalar) -> Option<Self> {
1630        let Scalar::Initialized { value, valid_range } = scalar else { return None };
1631        let niche = Niche { offset, value, valid_range };
1632        if niche.available(cx) > 0 { Some(niche) } else { None }
1633    }
1634
1635    pub fn available<C: HasDataLayout>(&self, cx: &C) -> u128 {
1636        let Self { value, valid_range: v, .. } = *self;
1637        let size = value.size(cx);
1638        assert!(size.bits() <= 128);
1639        let max_value = size.unsigned_int_max();
1640
1641        // Find out how many values are outside the valid range.
1642        let niche = v.end.wrapping_add(1)..v.start;
1643        niche.end.wrapping_sub(niche.start) & max_value
1644    }
1645
1646    pub fn reserve<C: HasDataLayout>(&self, cx: &C, count: u128) -> Option<(u128, Scalar)> {
1647        assert!(count > 0);
1648
1649        let Self { value, valid_range: v, .. } = *self;
1650        let size = value.size(cx);
1651        assert!(size.bits() <= 128);
1652        let max_value = size.unsigned_int_max();
1653
1654        let niche = v.end.wrapping_add(1)..v.start;
1655        let available = niche.end.wrapping_sub(niche.start) & max_value;
1656        if count > available {
1657            return None;
1658        }
1659
1660        // Extend the range of valid values being reserved by moving either `v.start` or `v.end`
1661        // bound. Given an eventual `Option<T>`, we try to maximize the chance for `None` to occupy
1662        // the niche of zero. This is accomplished by preferring enums with 2 variants(`count==1`)
1663        // and always taking the shortest path to niche zero. Having `None` in niche zero can
1664        // enable some special optimizations.
1665        //
1666        // Bound selection criteria:
1667        // 1. Select closest to zero given wrapping semantics.
1668        // 2. Avoid moving past zero if possible.
1669        //
1670        // In practice this means that enums with `count > 1` are unlikely to claim niche zero,
1671        // since they have to fit perfectly. If niche zero is already reserved, the selection of
1672        // bounds are of little interest.
1673        let move_start = |v: WrappingRange| {
1674            let start = v.start.wrapping_sub(count) & max_value;
1675            Some((start, Scalar::Initialized { value, valid_range: v.with_start(start) }))
1676        };
1677        let move_end = |v: WrappingRange| {
1678            let start = v.end.wrapping_add(1) & max_value;
1679            let end = v.end.wrapping_add(count) & max_value;
1680            Some((start, Scalar::Initialized { value, valid_range: v.with_end(end) }))
1681        };
1682        let distance_end_zero = max_value - v.end;
1683        if v.start > v.end {
1684            // zero is unavailable because wrapping occurs
1685            move_end(v)
1686        } else if v.start <= distance_end_zero {
1687            if count <= v.start {
1688                move_start(v)
1689            } else {
1690                // moved past zero, use other bound
1691                move_end(v)
1692            }
1693        } else {
1694            let end = v.end.wrapping_add(count) & max_value;
1695            let overshot_zero = (1..=v.end).contains(&end);
1696            if overshot_zero {
1697                // moved past zero, use other bound
1698                move_start(v)
1699            } else {
1700                move_end(v)
1701            }
1702        }
1703    }
1704}
1705
1706// NOTE: This struct is generic over the FieldIdx and VariantIdx for rust-analyzer usage.
1707#[derive(PartialEq, Eq, Hash, Clone)]
1708#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
1709pub struct LayoutData<FieldIdx: Idx, VariantIdx: Idx> {
1710    /// Says where the fields are located within the layout.
1711    pub fields: FieldsShape<FieldIdx>,
1712
1713    /// Encodes information about multi-variant layouts.
1714    /// Even with `Multiple` variants, a layout still has its own fields! Those are then
1715    /// shared between all variants. One of them will be the discriminant,
1716    /// but e.g. coroutines can have more.
1717    ///
1718    /// To access all fields of this layout, both `fields` and the fields of the active variant
1719    /// must be taken into account.
1720    pub variants: Variants<FieldIdx, VariantIdx>,
1721
1722    /// The `backend_repr` defines how this data will be represented to the codegen backend,
1723    /// and encodes value restrictions via `valid_range`.
1724    ///
1725    /// Note that this is entirely orthogonal to the recursive structure defined by
1726    /// `variants` and `fields`; for example, `ManuallyDrop<Result<isize, isize>>` has
1727    /// `IrForm::ScalarPair`! So, even with non-`Memory` `backend_repr`, `fields` and `variants`
1728    /// have to be taken into account to find all fields of this layout.
1729    pub backend_repr: BackendRepr,
1730
1731    /// The leaf scalar with the largest number of invalid values
1732    /// (i.e. outside of its `valid_range`), if it exists.
1733    pub largest_niche: Option<Niche>,
1734    /// Is this type known to be uninhabted?
1735    ///
1736    /// This is separate from BackendRepr because uninhabited return types can affect ABI,
1737    /// especially in the case of by-pointer struct returns, which allocate stack even when unused.
1738    pub uninhabited: bool,
1739
1740    pub align: AbiAlign,
1741    pub size: Size,
1742
1743    /// The largest alignment explicitly requested with `repr(align)` on this type or any field.
1744    /// Only used on i686-windows, where the argument passing ABI is different when alignment is
1745    /// requested, even if the requested alignment is equal to the natural alignment.
1746    pub max_repr_align: Option<Align>,
1747
1748    /// The alignment the type would have, ignoring any `repr(align)` but including `repr(packed)`.
1749    /// Only used on aarch64-linux, where the argument passing ABI ignores the requested alignment
1750    /// in some cases.
1751    pub unadjusted_abi_align: Align,
1752
1753    /// The randomization seed based on this type's own repr and its fields.
1754    ///
1755    /// Since randomization is toggled on a per-crate basis even crates that do not have randomization
1756    /// enabled should still calculate a seed so that downstream uses can use it to distinguish different
1757    /// types.
1758    ///
1759    /// For every T and U for which we do not guarantee that a repr(Rust) `Foo<T>` can be coerced or
1760    /// transmuted to `Foo<U>` we aim to create probalistically distinct seeds so that Foo can choose
1761    /// to reorder its fields based on that information. The current implementation is a conservative
1762    /// approximation of this goal.
1763    pub randomization_seed: Hash64,
1764}
1765
1766impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
1767    /// Returns `true` if this is an aggregate type (including a ScalarPair!)
1768    pub fn is_aggregate(&self) -> bool {
1769        match self.backend_repr {
1770            BackendRepr::Scalar(_) | BackendRepr::SimdVector { .. } => false,
1771            BackendRepr::ScalarPair(..) | BackendRepr::Memory { .. } => true,
1772        }
1773    }
1774
1775    /// Returns `true` if this is an uninhabited type
1776    pub fn is_uninhabited(&self) -> bool {
1777        self.uninhabited
1778    }
1779}
1780
1781impl<FieldIdx: Idx, VariantIdx: Idx> fmt::Debug for LayoutData<FieldIdx, VariantIdx>
1782where
1783    FieldsShape<FieldIdx>: fmt::Debug,
1784    Variants<FieldIdx, VariantIdx>: fmt::Debug,
1785{
1786    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1787        // This is how `Layout` used to print before it become
1788        // `Interned<LayoutData>`. We print it like this to avoid having to update
1789        // expected output in a lot of tests.
1790        let LayoutData {
1791            size,
1792            align,
1793            backend_repr,
1794            fields,
1795            largest_niche,
1796            uninhabited,
1797            variants,
1798            max_repr_align,
1799            unadjusted_abi_align,
1800            randomization_seed,
1801        } = self;
1802        f.debug_struct("Layout")
1803            .field("size", size)
1804            .field("align", align)
1805            .field("backend_repr", backend_repr)
1806            .field("fields", fields)
1807            .field("largest_niche", largest_niche)
1808            .field("uninhabited", uninhabited)
1809            .field("variants", variants)
1810            .field("max_repr_align", max_repr_align)
1811            .field("unadjusted_abi_align", unadjusted_abi_align)
1812            .field("randomization_seed", randomization_seed)
1813            .finish()
1814    }
1815}
1816
1817#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1818pub enum PointerKind {
1819    /// Shared reference. `frozen` indicates the absence of any `UnsafeCell`.
1820    SharedRef { frozen: bool },
1821    /// Mutable reference. `unpin` indicates the absence of any pinned data.
1822    MutableRef { unpin: bool },
1823    /// Box. `unpin` indicates the absence of any pinned data. `global` indicates whether this box
1824    /// uses the global allocator or a custom one.
1825    Box { unpin: bool, global: bool },
1826}
1827
1828/// Encodes extra information we have about a pointer.
1829/// Note that this information is advisory only, and backends are free to ignore it:
1830/// if the information is wrong, that can cause UB, but if the information is absent,
1831/// that must always be okay.
1832#[derive(Copy, Clone, Debug)]
1833pub struct PointeeInfo {
1834    /// If this is `None`, then this is a raw pointer, so size and alignment are not guaranteed to
1835    /// be reliable.
1836    pub safe: Option<PointerKind>,
1837    /// If `safe` is `Some`, then the pointer is either null or dereferenceable for this many bytes.
1838    /// On a function argument, "dereferenceable" here means "dereferenceable for the entire duration
1839    /// of this function call", i.e. it is UB for the memory that this pointer points to be freed
1840    /// while this function is still running.
1841    /// The size can be zero if the pointer is not dereferenceable.
1842    pub size: Size,
1843    /// If `safe` is `Some`, then the pointer is aligned as indicated.
1844    pub align: Align,
1845}
1846
1847impl<FieldIdx: Idx, VariantIdx: Idx> LayoutData<FieldIdx, VariantIdx> {
1848    /// Returns `true` if the layout corresponds to an unsized type.
1849    #[inline]
1850    pub fn is_unsized(&self) -> bool {
1851        self.backend_repr.is_unsized()
1852    }
1853
1854    #[inline]
1855    pub fn is_sized(&self) -> bool {
1856        self.backend_repr.is_sized()
1857    }
1858
1859    /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
1860    pub fn is_1zst(&self) -> bool {
1861        self.is_sized() && self.size.bytes() == 0 && self.align.abi.bytes() == 1
1862    }
1863
1864    /// Returns `true` if the type is a ZST and not unsized.
1865    ///
1866    /// Note that this does *not* imply that the type is irrelevant for layout! It can still have
1867    /// non-trivial alignment constraints. You probably want to use `is_1zst` instead.
1868    pub fn is_zst(&self) -> bool {
1869        match self.backend_repr {
1870            BackendRepr::Scalar(_)
1871            | BackendRepr::ScalarPair(..)
1872            | BackendRepr::SimdVector { .. } => false,
1873            BackendRepr::Memory { sized } => sized && self.size.bytes() == 0,
1874        }
1875    }
1876
1877    /// Checks if these two `Layout` are equal enough to be considered "the same for all function
1878    /// call ABIs". Note however that real ABIs depend on more details that are not reflected in the
1879    /// `Layout`; the `PassMode` need to be compared as well. Also note that we assume
1880    /// aggregates are passed via `PassMode::Indirect` or `PassMode::Cast`; more strict
1881    /// checks would otherwise be required.
1882    pub fn eq_abi(&self, other: &Self) -> bool {
1883        // The one thing that we are not capturing here is that for unsized types, the metadata must
1884        // also have the same ABI, and moreover that the same metadata leads to the same size. The
1885        // 2nd point is quite hard to check though.
1886        self.size == other.size
1887            && self.is_sized() == other.is_sized()
1888            && self.backend_repr.eq_up_to_validity(&other.backend_repr)
1889            && self.backend_repr.is_bool() == other.backend_repr.is_bool()
1890            && self.align.abi == other.align.abi
1891            && self.max_repr_align == other.max_repr_align
1892            && self.unadjusted_abi_align == other.unadjusted_abi_align
1893    }
1894}
1895
1896#[derive(Copy, Clone, Debug)]
1897pub enum StructKind {
1898    /// A tuple, closure, or univariant which cannot be coerced to unsized.
1899    AlwaysSized,
1900    /// A univariant, the last field of which may be coerced to unsized.
1901    MaybeUnsized,
1902    /// A univariant, but with a prefix of an arbitrary size & alignment (e.g., enum tag).
1903    Prefixed(Size, Align),
1904}
1905
1906#[derive(Clone, Debug)]
1907pub enum AbiFromStrErr {
1908    /// not a known ABI
1909    Unknown,
1910    /// no "-unwind" variant can be used here
1911    NoExplicitUnwind,
1912}