Skip to main content

rustc_abi/
extern_abi.rs

1use std::cmp::Ordering;
2use std::fmt;
3use std::hash::{Hash, Hasher};
4
5#[cfg(feature = "nightly")]
6use rustc_data_structures::stable_hash::{StableHash, StableHashCtxt, StableHasher, StableOrd};
7#[cfg(feature = "nightly")]
8use rustc_macros::{Decodable, Encodable};
9#[cfg(feature = "nightly")]
10use rustc_span::Symbol;
11
12use crate::AbiFromStrErr;
13
14#[cfg(test)]
15mod tests;
16
17/// ABI we expect to see within `extern "{abi}"`
18#[derive(#[automatically_derived]
impl ::core::clone::Clone for ExternAbi {
    #[inline]
    fn clone(&self) -> ExternAbi {
        let _: ::core::clone::AssertParamIsClone<bool>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for ExternAbi { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for ExternAbi {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            ExternAbi::C { unwind: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f, "C",
                    "unwind", &__self_0),
            ExternAbi::System { unwind: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "System", "unwind", &__self_0),
            ExternAbi::Rust => ::core::fmt::Formatter::write_str(f, "Rust"),
            ExternAbi::RustCall =>
                ::core::fmt::Formatter::write_str(f, "RustCall"),
            ExternAbi::RustCold =>
                ::core::fmt::Formatter::write_str(f, "RustCold"),
            ExternAbi::RustInvalid =>
                ::core::fmt::Formatter::write_str(f, "RustInvalid"),
            ExternAbi::RustPreserveNone =>
                ::core::fmt::Formatter::write_str(f, "RustPreserveNone"),
            ExternAbi::RustTail =>
                ::core::fmt::Formatter::write_str(f, "RustTail"),
            ExternAbi::Unadjusted =>
                ::core::fmt::Formatter::write_str(f, "Unadjusted"),
            ExternAbi::Custom =>
                ::core::fmt::Formatter::write_str(f, "Custom"),
            ExternAbi::EfiApi =>
                ::core::fmt::Formatter::write_str(f, "EfiApi"),
            ExternAbi::Swift => ::core::fmt::Formatter::write_str(f, "Swift"),
            ExternAbi::Aapcs { unwind: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f, "Aapcs",
                    "unwind", &__self_0),
            ExternAbi::CmseNonSecureCall =>
                ::core::fmt::Formatter::write_str(f, "CmseNonSecureCall"),
            ExternAbi::CmseNonSecureEntry =>
                ::core::fmt::Formatter::write_str(f, "CmseNonSecureEntry"),
            ExternAbi::GpuKernel =>
                ::core::fmt::Formatter::write_str(f, "GpuKernel"),
            ExternAbi::PtxKernel =>
                ::core::fmt::Formatter::write_str(f, "PtxKernel"),
            ExternAbi::AvrInterrupt =>
                ::core::fmt::Formatter::write_str(f, "AvrInterrupt"),
            ExternAbi::AvrNonBlockingInterrupt =>
                ::core::fmt::Formatter::write_str(f,
                    "AvrNonBlockingInterrupt"),
            ExternAbi::Msp430Interrupt =>
                ::core::fmt::Formatter::write_str(f, "Msp430Interrupt"),
            ExternAbi::RiscvInterruptM =>
                ::core::fmt::Formatter::write_str(f, "RiscvInterruptM"),
            ExternAbi::RiscvInterruptS =>
                ::core::fmt::Formatter::write_str(f, "RiscvInterruptS"),
            ExternAbi::X86Interrupt =>
                ::core::fmt::Formatter::write_str(f, "X86Interrupt"),
            ExternAbi::Cdecl { unwind: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f, "Cdecl",
                    "unwind", &__self_0),
            ExternAbi::Stdcall { unwind: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "Stdcall", "unwind", &__self_0),
            ExternAbi::Fastcall { unwind: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "Fastcall", "unwind", &__self_0),
            ExternAbi::Thiscall { unwind: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "Thiscall", "unwind", &__self_0),
            ExternAbi::Vectorcall { unwind: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "Vectorcall", "unwind", &__self_0),
            ExternAbi::SysV64 { unwind: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "SysV64", "unwind", &__self_0),
            ExternAbi::Win64 { unwind: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f, "Win64",
                    "unwind", &__self_0),
        }
    }
}Debug)]
19#[cfg_attr(feature = "nightly", derive(const _: () =
    {
        impl<__E: ::rustc_span::SpanEncoder> ::rustc_serialize::Encodable<__E>
            for ExternAbi {
            fn encode(&self, __encoder: &mut __E) {
                let disc =
                    match *self {
                        ExternAbi::C { unwind: ref __binding_0 } => { 0usize }
                        ExternAbi::System { unwind: ref __binding_0 } => { 1usize }
                        ExternAbi::Rust => { 2usize }
                        ExternAbi::RustCall => { 3usize }
                        ExternAbi::RustCold => { 4usize }
                        ExternAbi::RustInvalid => { 5usize }
                        ExternAbi::RustPreserveNone => { 6usize }
                        ExternAbi::RustTail => { 7usize }
                        ExternAbi::Unadjusted => { 8usize }
                        ExternAbi::Custom => { 9usize }
                        ExternAbi::EfiApi => { 10usize }
                        ExternAbi::Swift => { 11usize }
                        ExternAbi::Aapcs { unwind: ref __binding_0 } => { 12usize }
                        ExternAbi::CmseNonSecureCall => { 13usize }
                        ExternAbi::CmseNonSecureEntry => { 14usize }
                        ExternAbi::GpuKernel => { 15usize }
                        ExternAbi::PtxKernel => { 16usize }
                        ExternAbi::AvrInterrupt => { 17usize }
                        ExternAbi::AvrNonBlockingInterrupt => { 18usize }
                        ExternAbi::Msp430Interrupt => { 19usize }
                        ExternAbi::RiscvInterruptM => { 20usize }
                        ExternAbi::RiscvInterruptS => { 21usize }
                        ExternAbi::X86Interrupt => { 22usize }
                        ExternAbi::Cdecl { unwind: ref __binding_0 } => { 23usize }
                        ExternAbi::Stdcall { unwind: ref __binding_0 } => {
                            24usize
                        }
                        ExternAbi::Fastcall { unwind: ref __binding_0 } => {
                            25usize
                        }
                        ExternAbi::Thiscall { unwind: ref __binding_0 } => {
                            26usize
                        }
                        ExternAbi::Vectorcall { unwind: ref __binding_0 } => {
                            27usize
                        }
                        ExternAbi::SysV64 { unwind: ref __binding_0 } => { 28usize }
                        ExternAbi::Win64 { unwind: ref __binding_0 } => { 29usize }
                    };
                ::rustc_serialize::Encoder::emit_u8(__encoder, disc as u8);
                match *self {
                    ExternAbi::C { unwind: ref __binding_0 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    ExternAbi::System { unwind: ref __binding_0 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    ExternAbi::Rust => {}
                    ExternAbi::RustCall => {}
                    ExternAbi::RustCold => {}
                    ExternAbi::RustInvalid => {}
                    ExternAbi::RustPreserveNone => {}
                    ExternAbi::RustTail => {}
                    ExternAbi::Unadjusted => {}
                    ExternAbi::Custom => {}
                    ExternAbi::EfiApi => {}
                    ExternAbi::Swift => {}
                    ExternAbi::Aapcs { unwind: ref __binding_0 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    ExternAbi::CmseNonSecureCall => {}
                    ExternAbi::CmseNonSecureEntry => {}
                    ExternAbi::GpuKernel => {}
                    ExternAbi::PtxKernel => {}
                    ExternAbi::AvrInterrupt => {}
                    ExternAbi::AvrNonBlockingInterrupt => {}
                    ExternAbi::Msp430Interrupt => {}
                    ExternAbi::RiscvInterruptM => {}
                    ExternAbi::RiscvInterruptS => {}
                    ExternAbi::X86Interrupt => {}
                    ExternAbi::Cdecl { unwind: ref __binding_0 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    ExternAbi::Stdcall { unwind: ref __binding_0 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    ExternAbi::Fastcall { unwind: ref __binding_0 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    ExternAbi::Thiscall { unwind: ref __binding_0 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    ExternAbi::Vectorcall { unwind: ref __binding_0 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    ExternAbi::SysV64 { unwind: ref __binding_0 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                    ExternAbi::Win64 { unwind: ref __binding_0 } => {
                        ::rustc_serialize::Encodable::<__E>::encode(__binding_0,
                            __encoder);
                    }
                }
            }
        }
    };Encodable, const _: () =
    {
        impl<__D: ::rustc_span::SpanDecoder> ::rustc_serialize::Decodable<__D>
            for ExternAbi {
            fn decode(__decoder: &mut __D) -> Self {
                match ::rustc_serialize::Decoder::read_u8(__decoder) as usize
                    {
                    0usize => {
                        ExternAbi::C {
                            unwind: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    1usize => {
                        ExternAbi::System {
                            unwind: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    2usize => { ExternAbi::Rust }
                    3usize => { ExternAbi::RustCall }
                    4usize => { ExternAbi::RustCold }
                    5usize => { ExternAbi::RustInvalid }
                    6usize => { ExternAbi::RustPreserveNone }
                    7usize => { ExternAbi::RustTail }
                    8usize => { ExternAbi::Unadjusted }
                    9usize => { ExternAbi::Custom }
                    10usize => { ExternAbi::EfiApi }
                    11usize => { ExternAbi::Swift }
                    12usize => {
                        ExternAbi::Aapcs {
                            unwind: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    13usize => { ExternAbi::CmseNonSecureCall }
                    14usize => { ExternAbi::CmseNonSecureEntry }
                    15usize => { ExternAbi::GpuKernel }
                    16usize => { ExternAbi::PtxKernel }
                    17usize => { ExternAbi::AvrInterrupt }
                    18usize => { ExternAbi::AvrNonBlockingInterrupt }
                    19usize => { ExternAbi::Msp430Interrupt }
                    20usize => { ExternAbi::RiscvInterruptM }
                    21usize => { ExternAbi::RiscvInterruptS }
                    22usize => { ExternAbi::X86Interrupt }
                    23usize => {
                        ExternAbi::Cdecl {
                            unwind: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    24usize => {
                        ExternAbi::Stdcall {
                            unwind: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    25usize => {
                        ExternAbi::Fastcall {
                            unwind: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    26usize => {
                        ExternAbi::Thiscall {
                            unwind: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    27usize => {
                        ExternAbi::Vectorcall {
                            unwind: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    28usize => {
                        ExternAbi::SysV64 {
                            unwind: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    29usize => {
                        ExternAbi::Win64 {
                            unwind: ::rustc_serialize::Decodable::decode(__decoder),
                        }
                    }
                    n => {
                        ::core::panicking::panic_fmt(format_args!("invalid enum variant tag while decoding `ExternAbi`, expected 0..30, actual {0}",
                                n));
                    }
                }
            }
        }
    };Decodable))]
20pub enum ExternAbi {
21    /* universal */
22    /// presumed C ABI for the platform
23    C {
24        unwind: bool,
25    },
26    /// ABI of the "system" interface, e.g. the Win32 API, always "aliasing"
27    System {
28        unwind: bool,
29    },
30
31    /// that's us!
32    Rust,
33    /// the mostly-unused `unboxed_closures` ABI, effectively now an impl detail unless someone
34    /// puts in the work to make it viable again... but would we need a special ABI?
35    RustCall,
36    /// For things unlikely to be called, where reducing register pressure in
37    /// `extern "Rust"` callers is worth paying extra cost in the callee.
38    /// Stronger than just `#[cold]` because `fn` pointers might be incompatible.
39    RustCold,
40
41    /// An always-invalid ABI that's used to test "this ABI is not supported by this platform"
42    /// in a platform-agnostic way.
43    RustInvalid,
44
45    /// Preserves no registers.
46    ///
47    /// Note, that this ABI is not stable in the registers it uses, is intended as an optimization
48    /// and may fall-back to a more conservative calling convention if the backend does not support
49    /// forcing callers to save all registers.
50    RustPreserveNone,
51
52    /// Ensures that calls in tail position can always be optimized into a jump.
53    ///
54    /// This ABI is not stable, and relies on LLVM implementation details.
55    RustTail,
56
57    /// Unstable impl detail that directly uses Rust types to describe the ABI to LLVM.
58    /// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
59    Unadjusted,
60
61    /// An ABI that rustc does not know how to call or define. Functions with this ABI can
62    /// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only
63    /// be called from inline assembly.
64    Custom,
65
66    /// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias
67    /// and only valid on platforms that have a UEFI standard
68    EfiApi,
69
70    /// Swift's calling convention, used to interoperate with Swift code without
71    /// going through C as an intermediary.
72    Swift,
73
74    /* arm */
75    /// Arm Architecture Procedure Call Standard, sometimes `ExternAbi::C` is an alias for this
76    Aapcs {
77        unwind: bool,
78    },
79    /// extremely constrained barely-C ABI for TrustZone
80    CmseNonSecureCall,
81    /// extremely constrained barely-C ABI for TrustZone
82    CmseNonSecureEntry,
83
84    /* gpu */
85    /// An entry-point function called by the GPU's host
86    GpuKernel,
87    /// An entry-point function called by the GPU's host
88    // FIXME: why do we have two of these?
89    PtxKernel,
90
91    /* interrupt */
92    AvrInterrupt,
93    AvrNonBlockingInterrupt,
94    Msp430Interrupt,
95    RiscvInterruptM,
96    RiscvInterruptS,
97    X86Interrupt,
98
99    /* x86 */
100    /// `ExternAbi::C` but spelled funny because x86
101    Cdecl {
102        unwind: bool,
103    },
104    /// gnu-stdcall on "unix" and win-stdcall on "windows"
105    Stdcall {
106        unwind: bool,
107    },
108    /// gnu-fastcall on "unix" and win-fastcall on "windows"
109    Fastcall {
110        unwind: bool,
111    },
112    /// windows C++ ABI
113    Thiscall {
114        unwind: bool,
115    },
116    /// uses AVX and stuff
117    Vectorcall {
118        unwind: bool,
119    },
120
121    /* x86_64 */
122    SysV64 {
123        unwind: bool,
124    },
125    Win64 {
126        unwind: bool,
127    },
128}
129
130macro_rules! abi_impls {
131    ($e_name:ident = {
132        $($variant:ident $({ unwind: $uw:literal })? =><= $tok:literal,)*
133    }) => {
134        impl $e_name {
135            pub const ALL_VARIANTS: &[Self] = &[
136                $($e_name::$variant $({ unwind: $uw })*,)*
137            ];
138            pub const fn as_str(&self) -> &'static str {
139                match self {
140                    $($e_name::$variant $( { unwind: $uw } )* => $tok,)*
141                }
142            }
143            // FIXME(FnSigKind): when PartialEq is stably const, use it instead
144            const fn internal_const_eq(&self, other: &Self) -> bool {
145                match (self, other) {
146                    $( ( $e_name::$variant $( { unwind: $uw } )* , $e_name::$variant $( { unwind: $uw } )* ) => true,)*
147                    _ => false,
148                }
149            }
150            // ALL_VARIANTS.iter().position(|v| v == self), but const
151            pub const fn as_packed(&self) -> u8 {
152                let mut index = 0;
153                while index < $e_name::ALL_VARIANTS.len() {
154                    if self.internal_const_eq(&$e_name::ALL_VARIANTS[index]) {
155                        return index as u8;
156                    }
157                    index += 1;
158                }
159                panic!("unreachable: invalid ExternAbi variant");
160            }
161            pub const fn from_packed(index: u8) -> Self {
162                let index = index as usize;
163                assert!(index < $e_name::ALL_VARIANTS.len(), "invalid ExternAbi index");
164                $e_name::ALL_VARIANTS[index]
165            }
166        }
167
168        impl ::core::str::FromStr for $e_name {
169            type Err = AbiFromStrErr;
170            fn from_str(s: &str) -> Result<$e_name, Self::Err> {
171                match s {
172                    $($tok => Ok($e_name::$variant $({ unwind: $uw })*),)*
173                    _ => Err(AbiFromStrErr::Unknown),
174                }
175            }
176        }
177    }
178}
179
180impl ExternAbi {
    pub const ALL_VARIANTS: &[Self] =
        &[ExternAbi::C { unwind: false }, ExternAbi::C { unwind: true },
                    ExternAbi::Rust, ExternAbi::Swift,
                    ExternAbi::Aapcs { unwind: false },
                    ExternAbi::Aapcs { unwind: true }, ExternAbi::AvrInterrupt,
                    ExternAbi::AvrNonBlockingInterrupt,
                    ExternAbi::Cdecl { unwind: false },
                    ExternAbi::Cdecl { unwind: true },
                    ExternAbi::CmseNonSecureCall, ExternAbi::CmseNonSecureEntry,
                    ExternAbi::Custom, ExternAbi::EfiApi,
                    ExternAbi::Fastcall { unwind: false },
                    ExternAbi::Fastcall { unwind: true }, ExternAbi::GpuKernel,
                    ExternAbi::Msp430Interrupt, ExternAbi::PtxKernel,
                    ExternAbi::RiscvInterruptM, ExternAbi::RiscvInterruptS,
                    ExternAbi::RustCall, ExternAbi::RustCold,
                    ExternAbi::RustInvalid, ExternAbi::RustPreserveNone,
                    ExternAbi::Stdcall { unwind: false },
                    ExternAbi::Stdcall { unwind: true },
                    ExternAbi::System { unwind: false },
                    ExternAbi::System { unwind: true },
                    ExternAbi::SysV64 { unwind: false },
                    ExternAbi::SysV64 { unwind: true }, ExternAbi::RustTail,
                    ExternAbi::Thiscall { unwind: false },
                    ExternAbi::Thiscall { unwind: true }, ExternAbi::Unadjusted,
                    ExternAbi::Vectorcall { unwind: false },
                    ExternAbi::Vectorcall { unwind: true },
                    ExternAbi::Win64 { unwind: false },
                    ExternAbi::Win64 { unwind: true }, ExternAbi::X86Interrupt];
    pub const fn as_str(&self) -> &'static str {
        match self {
            ExternAbi::C { unwind: false } => "C",
            ExternAbi::C { unwind: true } => "C-unwind",
            ExternAbi::Rust => "Rust",
            ExternAbi::Swift => "Swift",
            ExternAbi::Aapcs { unwind: false } => "aapcs",
            ExternAbi::Aapcs { unwind: true } => "aapcs-unwind",
            ExternAbi::AvrInterrupt => "avr-interrupt",
            ExternAbi::AvrNonBlockingInterrupt =>
                "avr-non-blocking-interrupt",
            ExternAbi::Cdecl { unwind: false } => "cdecl",
            ExternAbi::Cdecl { unwind: true } => "cdecl-unwind",
            ExternAbi::CmseNonSecureCall => "cmse-nonsecure-call",
            ExternAbi::CmseNonSecureEntry => "cmse-nonsecure-entry",
            ExternAbi::Custom => "custom",
            ExternAbi::EfiApi => "efiapi",
            ExternAbi::Fastcall { unwind: false } => "fastcall",
            ExternAbi::Fastcall { unwind: true } => "fastcall-unwind",
            ExternAbi::GpuKernel => "gpu-kernel",
            ExternAbi::Msp430Interrupt => "msp430-interrupt",
            ExternAbi::PtxKernel => "ptx-kernel",
            ExternAbi::RiscvInterruptM => "riscv-interrupt-m",
            ExternAbi::RiscvInterruptS => "riscv-interrupt-s",
            ExternAbi::RustCall => "rust-call",
            ExternAbi::RustCold => "rust-cold",
            ExternAbi::RustInvalid => "rust-invalid",
            ExternAbi::RustPreserveNone => "rust-preserve-none",
            ExternAbi::Stdcall { unwind: false } => "stdcall",
            ExternAbi::Stdcall { unwind: true } => "stdcall-unwind",
            ExternAbi::System { unwind: false } => "system",
            ExternAbi::System { unwind: true } => "system-unwind",
            ExternAbi::SysV64 { unwind: false } => "sysv64",
            ExternAbi::SysV64 { unwind: true } => "sysv64-unwind",
            ExternAbi::RustTail => "tail",
            ExternAbi::Thiscall { unwind: false } => "thiscall",
            ExternAbi::Thiscall { unwind: true } => "thiscall-unwind",
            ExternAbi::Unadjusted => "unadjusted",
            ExternAbi::Vectorcall { unwind: false } => "vectorcall",
            ExternAbi::Vectorcall { unwind: true } => "vectorcall-unwind",
            ExternAbi::Win64 { unwind: false } => "win64",
            ExternAbi::Win64 { unwind: true } => "win64-unwind",
            ExternAbi::X86Interrupt => "x86-interrupt",
        }
    }
    const fn internal_const_eq(&self, other: &Self) -> bool {
        match (self, other) {
            (ExternAbi::C { unwind: false }, ExternAbi::C { unwind: false })
                => true,
            (ExternAbi::C { unwind: true }, ExternAbi::C { unwind: true }) =>
                true,
            (ExternAbi::Rust, ExternAbi::Rust) => true,
            (ExternAbi::Swift, ExternAbi::Swift) => true,
            (ExternAbi::Aapcs { unwind: false }, ExternAbi::Aapcs {
                unwind: false }) => true,
            (ExternAbi::Aapcs { unwind: true }, ExternAbi::Aapcs {
                unwind: true }) => true,
            (ExternAbi::AvrInterrupt, ExternAbi::AvrInterrupt) => true,
            (ExternAbi::AvrNonBlockingInterrupt,
                ExternAbi::AvrNonBlockingInterrupt) => true,
            (ExternAbi::Cdecl { unwind: false }, ExternAbi::Cdecl {
                unwind: false }) => true,
            (ExternAbi::Cdecl { unwind: true }, ExternAbi::Cdecl {
                unwind: true }) => true,
            (ExternAbi::CmseNonSecureCall, ExternAbi::CmseNonSecureCall) =>
                true,
            (ExternAbi::CmseNonSecureEntry, ExternAbi::CmseNonSecureEntry) =>
                true,
            (ExternAbi::Custom, ExternAbi::Custom) => true,
            (ExternAbi::EfiApi, ExternAbi::EfiApi) => true,
            (ExternAbi::Fastcall { unwind: false }, ExternAbi::Fastcall {
                unwind: false }) => true,
            (ExternAbi::Fastcall { unwind: true }, ExternAbi::Fastcall {
                unwind: true }) => true,
            (ExternAbi::GpuKernel, ExternAbi::GpuKernel) => true,
            (ExternAbi::Msp430Interrupt, ExternAbi::Msp430Interrupt) => true,
            (ExternAbi::PtxKernel, ExternAbi::PtxKernel) => true,
            (ExternAbi::RiscvInterruptM, ExternAbi::RiscvInterruptM) => true,
            (ExternAbi::RiscvInterruptS, ExternAbi::RiscvInterruptS) => true,
            (ExternAbi::RustCall, ExternAbi::RustCall) => true,
            (ExternAbi::RustCold, ExternAbi::RustCold) => true,
            (ExternAbi::RustInvalid, ExternAbi::RustInvalid) => true,
            (ExternAbi::RustPreserveNone, ExternAbi::RustPreserveNone) =>
                true,
            (ExternAbi::Stdcall { unwind: false }, ExternAbi::Stdcall {
                unwind: false }) => true,
            (ExternAbi::Stdcall { unwind: true }, ExternAbi::Stdcall {
                unwind: true }) => true,
            (ExternAbi::System { unwind: false }, ExternAbi::System {
                unwind: false }) => true,
            (ExternAbi::System { unwind: true }, ExternAbi::System {
                unwind: true }) => true,
            (ExternAbi::SysV64 { unwind: false }, ExternAbi::SysV64 {
                unwind: false }) => true,
            (ExternAbi::SysV64 { unwind: true }, ExternAbi::SysV64 {
                unwind: true }) => true,
            (ExternAbi::RustTail, ExternAbi::RustTail) => true,
            (ExternAbi::Thiscall { unwind: false }, ExternAbi::Thiscall {
                unwind: false }) => true,
            (ExternAbi::Thiscall { unwind: true }, ExternAbi::Thiscall {
                unwind: true }) => true,
            (ExternAbi::Unadjusted, ExternAbi::Unadjusted) => true,
            (ExternAbi::Vectorcall { unwind: false }, ExternAbi::Vectorcall {
                unwind: false }) => true,
            (ExternAbi::Vectorcall { unwind: true }, ExternAbi::Vectorcall {
                unwind: true }) => true,
            (ExternAbi::Win64 { unwind: false }, ExternAbi::Win64 {
                unwind: false }) => true,
            (ExternAbi::Win64 { unwind: true }, ExternAbi::Win64 {
                unwind: true }) => true,
            (ExternAbi::X86Interrupt, ExternAbi::X86Interrupt) => true,
            _ => false,
        }
    }
    pub const fn as_packed(&self) -> u8 {
        let mut index = 0;
        while index < ExternAbi::ALL_VARIANTS.len() {
            if self.internal_const_eq(&ExternAbi::ALL_VARIANTS[index]) {
                return index as u8;
            }
            index += 1;
        }
        {
            ::core::panicking::panic_fmt(format_args!("unreachable: invalid ExternAbi variant"));
        };
    }
    pub const fn from_packed(index: u8) -> Self {
        let index = index as usize;
        if !(index < ExternAbi::ALL_VARIANTS.len()) {
            {
                ::core::panicking::panic_fmt(format_args!("invalid ExternAbi index"));
            }
        };
        ExternAbi::ALL_VARIANTS[index]
    }
}
impl ::core::str::FromStr for ExternAbi {
    type Err = AbiFromStrErr;
    fn from_str(s: &str) -> Result<ExternAbi, Self::Err> {
        match s {
            "C" => Ok(ExternAbi::C { unwind: false }),
            "C-unwind" => Ok(ExternAbi::C { unwind: true }),
            "Rust" => Ok(ExternAbi::Rust),
            "Swift" => Ok(ExternAbi::Swift),
            "aapcs" => Ok(ExternAbi::Aapcs { unwind: false }),
            "aapcs-unwind" => Ok(ExternAbi::Aapcs { unwind: true }),
            "avr-interrupt" => Ok(ExternAbi::AvrInterrupt),
            "avr-non-blocking-interrupt" =>
                Ok(ExternAbi::AvrNonBlockingInterrupt),
            "cdecl" => Ok(ExternAbi::Cdecl { unwind: false }),
            "cdecl-unwind" => Ok(ExternAbi::Cdecl { unwind: true }),
            "cmse-nonsecure-call" => Ok(ExternAbi::CmseNonSecureCall),
            "cmse-nonsecure-entry" => Ok(ExternAbi::CmseNonSecureEntry),
            "custom" => Ok(ExternAbi::Custom),
            "efiapi" => Ok(ExternAbi::EfiApi),
            "fastcall" => Ok(ExternAbi::Fastcall { unwind: false }),
            "fastcall-unwind" => Ok(ExternAbi::Fastcall { unwind: true }),
            "gpu-kernel" => Ok(ExternAbi::GpuKernel),
            "msp430-interrupt" => Ok(ExternAbi::Msp430Interrupt),
            "ptx-kernel" => Ok(ExternAbi::PtxKernel),
            "riscv-interrupt-m" => Ok(ExternAbi::RiscvInterruptM),
            "riscv-interrupt-s" => Ok(ExternAbi::RiscvInterruptS),
            "rust-call" => Ok(ExternAbi::RustCall),
            "rust-cold" => Ok(ExternAbi::RustCold),
            "rust-invalid" => Ok(ExternAbi::RustInvalid),
            "rust-preserve-none" => Ok(ExternAbi::RustPreserveNone),
            "stdcall" => Ok(ExternAbi::Stdcall { unwind: false }),
            "stdcall-unwind" => Ok(ExternAbi::Stdcall { unwind: true }),
            "system" => Ok(ExternAbi::System { unwind: false }),
            "system-unwind" => Ok(ExternAbi::System { unwind: true }),
            "sysv64" => Ok(ExternAbi::SysV64 { unwind: false }),
            "sysv64-unwind" => Ok(ExternAbi::SysV64 { unwind: true }),
            "tail" => Ok(ExternAbi::RustTail),
            "thiscall" => Ok(ExternAbi::Thiscall { unwind: false }),
            "thiscall-unwind" => Ok(ExternAbi::Thiscall { unwind: true }),
            "unadjusted" => Ok(ExternAbi::Unadjusted),
            "vectorcall" => Ok(ExternAbi::Vectorcall { unwind: false }),
            "vectorcall-unwind" => Ok(ExternAbi::Vectorcall { unwind: true }),
            "win64" => Ok(ExternAbi::Win64 { unwind: false }),
            "win64-unwind" => Ok(ExternAbi::Win64 { unwind: true }),
            "x86-interrupt" => Ok(ExternAbi::X86Interrupt),
            _ => Err(AbiFromStrErr::Unknown),
        }
    }
}abi_impls! {
181    ExternAbi = {
182            C { unwind: false } =><= "C",
183            C { unwind: true } =><= "C-unwind",
184            Rust =><= "Rust",
185            Swift =><= "Swift",
186            Aapcs { unwind: false } =><= "aapcs",
187            Aapcs { unwind: true } =><= "aapcs-unwind",
188            AvrInterrupt =><= "avr-interrupt",
189            AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
190            Cdecl { unwind: false } =><= "cdecl",
191            Cdecl { unwind: true } =><= "cdecl-unwind",
192            CmseNonSecureCall =><= "cmse-nonsecure-call",
193            CmseNonSecureEntry =><= "cmse-nonsecure-entry",
194            Custom =><= "custom",
195            EfiApi =><= "efiapi",
196            Fastcall { unwind: false } =><= "fastcall",
197            Fastcall { unwind: true } =><= "fastcall-unwind",
198            GpuKernel =><= "gpu-kernel",
199            Msp430Interrupt =><= "msp430-interrupt",
200            PtxKernel =><= "ptx-kernel",
201            RiscvInterruptM =><= "riscv-interrupt-m",
202            RiscvInterruptS =><= "riscv-interrupt-s",
203            RustCall =><= "rust-call",
204            RustCold =><= "rust-cold",
205            RustInvalid =><= "rust-invalid",
206            RustPreserveNone =><= "rust-preserve-none",
207            Stdcall { unwind: false } =><= "stdcall",
208            Stdcall { unwind: true } =><= "stdcall-unwind",
209            System { unwind: false } =><= "system",
210            System { unwind: true } =><= "system-unwind",
211            SysV64 { unwind: false } =><= "sysv64",
212            SysV64 { unwind: true } =><= "sysv64-unwind",
213            RustTail =><= "tail",
214            Thiscall { unwind: false } =><= "thiscall",
215            Thiscall { unwind: true } =><= "thiscall-unwind",
216            Unadjusted =><= "unadjusted",
217            Vectorcall { unwind: false } =><= "vectorcall",
218            Vectorcall { unwind: true } =><= "vectorcall-unwind",
219            Win64 { unwind: false } =><= "win64",
220            Win64 { unwind: true } =><= "win64-unwind",
221            X86Interrupt =><= "x86-interrupt",
222    }
223}
224
225impl Ord for ExternAbi {
226    fn cmp(&self, rhs: &Self) -> Ordering {
227        self.as_str().cmp(rhs.as_str())
228    }
229}
230
231impl PartialOrd for ExternAbi {
232    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
233        Some(self.cmp(rhs))
234    }
235}
236
237impl PartialEq for ExternAbi {
238    fn eq(&self, rhs: &Self) -> bool {
239        self.cmp(rhs) == Ordering::Equal
240    }
241}
242
243impl Eq for ExternAbi {}
244
245impl Hash for ExternAbi {
246    fn hash<H: Hasher>(&self, state: &mut H) {
247        self.as_str().hash(state);
248        // double-assurance of a prefix breaker
249        u32::from_be_bytes(*b"ABI\0").hash(state);
250    }
251}
252
253#[cfg(feature = "nightly")]
254impl StableHash for ExternAbi {
255    #[inline]
256    fn stable_hash<Hcx: StableHashCtxt>(&self, _: &mut Hcx, hasher: &mut StableHasher) {
257        Hash::hash(self, hasher);
258    }
259}
260
261#[cfg(feature = "nightly")]
262impl StableOrd for ExternAbi {
263    const CAN_USE_UNSTABLE_SORT: bool = true;
264
265    // because each ABI is hashed like a string, there is no possible instability
266    const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
267}
268
269#[cfg(feature = "nightly")]
270impl ::rustc_error_messages::IntoDiagArg for ExternAbi {
    fn into_diag_arg(self, path: &mut Option<std::path::PathBuf>)
        -> ::rustc_error_messages::DiagArgValue {
        self.to_string().into_diag_arg(path)
    }
}rustc_error_messages::into_diag_arg_using_display!(ExternAbi);
271
272#[cfg(feature = "nightly")]
273#[derive(#[automatically_derived]
impl ::core::fmt::Debug for CVariadicStatus {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            CVariadicStatus::NotSupported =>
                ::core::fmt::Formatter::write_str(f, "NotSupported"),
            CVariadicStatus::Stable =>
                ::core::fmt::Formatter::write_str(f, "Stable"),
            CVariadicStatus::Unstable { feature: __self_0 } =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "Unstable", "feature", &__self_0),
        }
    }
}Debug)]
274pub enum CVariadicStatus {
275    NotSupported,
276    Stable,
277    Unstable { feature: Symbol },
278}
279
280impl ExternAbi {
281    /// An ABI "like Rust"
282    ///
283    /// These ABIs are fully controlled by the Rust compiler, which means they
284    /// - support unwinding with `-Cpanic=unwind`, unlike `extern "C"`
285    /// - often diverge from the C ABI
286    /// - are subject to change between compiler versions
287    pub fn is_rustic_abi(self) -> bool {
288        use ExternAbi::*;
289        #[allow(non_exhaustive_omitted_patterns)] match self {
    Rust | RustCall | RustCold | RustPreserveNone | RustTail => true,
    _ => false,
}matches!(self, Rust | RustCall | RustCold | RustPreserveNone | RustTail)
290    }
291
292    /// Returns whether the ABI supports C variadics. This only controls whether we allow *imports*
293    /// of such functions via `extern` blocks; there's a separate check during AST construction
294    /// guarding *definitions* of variadic functions.
295    #[cfg(feature = "nightly")]
296    pub fn supports_c_variadic(self) -> CVariadicStatus {
297        // * C and Cdecl obviously support varargs.
298        // * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
299        // * EfiApi is based on Win64 or C, so it also supports it.
300        // * System automatically falls back to C when used with variadics, therefore supports it.
301        //
302        // * Stdcall does not, because it would be impossible for the callee to clean
303        //   up the arguments. (callee doesn't know how many arguments are there)
304        // * Same for Fastcall, Vectorcall and Thiscall.
305        // * Other calling conventions are related to hardware or the compiler itself.
306        //
307        // All of the supported ones must have a test in `tests/codegen/cffi/c-variadic-ffi.rs`.
308        match self {
309            Self::C { .. }
310            | Self::Cdecl { .. }
311            | Self::Aapcs { .. }
312            | Self::Win64 { .. }
313            | Self::SysV64 { .. }
314            | Self::EfiApi
315            | Self::System { .. } => CVariadicStatus::Stable,
316            _ => CVariadicStatus::NotSupported,
317        }
318    }
319
320    /// Returns whether the ABI supports guaranteed tail calls.
321    #[cfg(feature = "nightly")]
322    pub fn supports_guaranteed_tail_call(self) -> bool {
323        match self {
324            Self::CmseNonSecureCall | Self::CmseNonSecureEntry => {
325                // See https://godbolt.org/z/9jhdeqErv. The CMSE calling conventions clear registers
326                // before returning, and hence cannot guarantee a tail call.
327                false
328            }
329            Self::AvrInterrupt
330            | Self::AvrNonBlockingInterrupt
331            | Self::Msp430Interrupt
332            | Self::RiscvInterruptM
333            | Self::RiscvInterruptS
334            | Self::X86Interrupt => {
335                // See https://godbolt.org/z/Edfjnxxcq. Interrupts cannot be called directly.
336                false
337            }
338            Self::GpuKernel | Self::PtxKernel => {
339                // See https://godbolt.org/z/jq5TE5jK1.
340                false
341            }
342            Self::Custom => {
343                // This ABI does not support calls at all (except via assembly).
344                false
345            }
346            Self::C { .. }
347            | Self::System { .. }
348            | Self::Rust
349            | Self::RustCall
350            | Self::RustCold
351            | Self::RustInvalid
352            | Self::Unadjusted
353            | Self::EfiApi
354            | Self::Aapcs { .. }
355            | Self::Cdecl { .. }
356            | Self::Stdcall { .. }
357            | Self::Fastcall { .. }
358            | Self::Thiscall { .. }
359            | Self::Vectorcall { .. }
360            | Self::SysV64 { .. }
361            | Self::Win64 { .. }
362            | Self::RustPreserveNone
363            | Self::RustTail
364            | Self::Swift => true,
365        }
366    }
367}
368
369pub fn all_names() -> Vec<&'static str> {
370    ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect()
371}
372
373impl ExternAbi {
374    /// Default ABI chosen for `extern fn` declarations without an explicit ABI.
375    pub const FALLBACK: ExternAbi = ExternAbi::C { unwind: false };
376
377    pub fn name(self) -> &'static str {
378        self.as_str()
379    }
380}
381
382impl fmt::Display for ExternAbi {
383    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
384        f.write_fmt(format_args!("\"{0}\"", self.as_str()))write!(f, "\"{}\"", self.as_str())
385    }
386}