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_hasher::{HashStable, StableHasher, StableOrd};
7#[cfg(feature = "nightly")]
8use rustc_macros::{Decodable, Encodable};
9
10#[cfg(test)]
11mod tests;
12
13use ExternAbi as Abi;
14
15#[derive(Clone, Copy, Debug)]
16#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))]
17pub enum ExternAbi {
18    // Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the
19    // hashing tests. These are used in many places, so giving them stable values reduces test
20    // churn. The specific values are meaningless.
21    Rust,
22    C {
23        unwind: bool,
24    },
25    Cdecl {
26        unwind: bool,
27    },
28    Stdcall {
29        unwind: bool,
30    },
31    Fastcall {
32        unwind: bool,
33    },
34    Vectorcall {
35        unwind: bool,
36    },
37    Thiscall {
38        unwind: bool,
39    },
40    Aapcs {
41        unwind: bool,
42    },
43    Win64 {
44        unwind: bool,
45    },
46    SysV64 {
47        unwind: bool,
48    },
49    PtxKernel,
50    Msp430Interrupt,
51    X86Interrupt,
52    /// An entry-point function called by the GPU's host
53    // FIXME: should not be callable from Rust on GPU targets, is for host's use only
54    GpuKernel,
55    EfiApi,
56    AvrInterrupt,
57    AvrNonBlockingInterrupt,
58    CCmseNonSecureCall,
59    CCmseNonSecureEntry,
60    System {
61        unwind: bool,
62    },
63    RustIntrinsic,
64    RustCall,
65    /// *Not* a stable ABI, just directly use the Rust types to describe the ABI for LLVM. Even
66    /// normally ABI-compatible Rust types can become ABI-incompatible with this ABI!
67    Unadjusted,
68    /// For things unlikely to be called, where reducing register pressure in
69    /// `extern "Rust"` callers is worth paying extra cost in the callee.
70    /// Stronger than just `#[cold]` because `fn` pointers might be incompatible.
71    RustCold,
72    RiscvInterruptM,
73    RiscvInterruptS,
74}
75
76macro_rules! abi_impls {
77    ($e_name:ident = {
78        $($variant:ident $({ unwind: $uw:literal })? =><= $tok:literal,)*
79    }) => {
80        impl $e_name {
81            pub const ALL_VARIANTS: &[Self] = &[
82                $($e_name::$variant $({ unwind: $uw })*,)*
83            ];
84            pub const fn as_str(&self) -> &'static str {
85                match self {
86                    $($e_name::$variant $( { unwind: $uw } )* => $tok,)*
87                }
88            }
89        }
90
91        impl ::core::str::FromStr for $e_name {
92            type Err = AbiFromStrErr;
93            fn from_str(s: &str) -> Result<$e_name, Self::Err> {
94                match s {
95                    $($tok => Ok($e_name::$variant $({ unwind: $uw })*),)*
96                    _ => Err(AbiFromStrErr::Unknown),
97                }
98            }
99        }
100    }
101}
102
103#[derive(Debug)]
104pub enum AbiFromStrErr {
105    Unknown,
106}
107
108abi_impls! {
109    ExternAbi = {
110            C { unwind: false } =><= "C",
111            CCmseNonSecureCall =><= "C-cmse-nonsecure-call",
112            CCmseNonSecureEntry =><= "C-cmse-nonsecure-entry",
113            C { unwind: true } =><= "C-unwind",
114            Rust =><= "Rust",
115            Aapcs { unwind: false } =><= "aapcs",
116            Aapcs { unwind: true } =><= "aapcs-unwind",
117            AvrInterrupt =><= "avr-interrupt",
118            AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
119            Cdecl { unwind: false } =><= "cdecl",
120            Cdecl { unwind: true } =><= "cdecl-unwind",
121            EfiApi =><= "efiapi",
122            Fastcall { unwind: false } =><= "fastcall",
123            Fastcall { unwind: true } =><= "fastcall-unwind",
124            GpuKernel =><= "gpu-kernel",
125            Msp430Interrupt =><= "msp430-interrupt",
126            PtxKernel =><= "ptx-kernel",
127            RiscvInterruptM =><= "riscv-interrupt-m",
128            RiscvInterruptS =><= "riscv-interrupt-s",
129            RustCall =><= "rust-call",
130            RustCold =><= "rust-cold",
131            RustIntrinsic =><= "rust-intrinsic",
132            Stdcall { unwind: false } =><= "stdcall",
133            Stdcall { unwind: true } =><= "stdcall-unwind",
134            System { unwind: false } =><= "system",
135            System { unwind: true } =><= "system-unwind",
136            SysV64 { unwind: false } =><= "sysv64",
137            SysV64 { unwind: true } =><= "sysv64-unwind",
138            Thiscall { unwind: false } =><= "thiscall",
139            Thiscall { unwind: true } =><= "thiscall-unwind",
140            Unadjusted =><= "unadjusted",
141            Vectorcall { unwind: false } =><= "vectorcall",
142            Vectorcall { unwind: true } =><= "vectorcall-unwind",
143            Win64 { unwind: false } =><= "win64",
144            Win64 { unwind: true } =><= "win64-unwind",
145            X86Interrupt =><= "x86-interrupt",
146    }
147}
148
149impl Ord for ExternAbi {
150    fn cmp(&self, rhs: &Self) -> Ordering {
151        self.as_str().cmp(rhs.as_str())
152    }
153}
154
155impl PartialOrd for ExternAbi {
156    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
157        Some(self.cmp(rhs))
158    }
159}
160
161impl PartialEq for ExternAbi {
162    fn eq(&self, rhs: &Self) -> bool {
163        self.cmp(rhs) == Ordering::Equal
164    }
165}
166
167impl Eq for ExternAbi {}
168
169impl Hash for ExternAbi {
170    fn hash<H: Hasher>(&self, state: &mut H) {
171        self.as_str().hash(state);
172        // double-assurance of a prefix breaker
173        u32::from_be_bytes(*b"ABI\0").hash(state);
174    }
175}
176
177#[cfg(feature = "nightly")]
178impl<C> HashStable<C> for ExternAbi {
179    #[inline]
180    fn hash_stable(&self, _: &mut C, hasher: &mut StableHasher) {
181        Hash::hash(self, hasher);
182    }
183}
184
185#[cfg(feature = "nightly")]
186impl StableOrd for ExternAbi {
187    const CAN_USE_UNSTABLE_SORT: bool = true;
188
189    // because each ABI is hashed like a string, there is no possible instability
190    const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
191}
192
193impl ExternAbi {
194    /// An ABI "like Rust"
195    ///
196    /// These ABIs are fully controlled by the Rust compiler, which means they
197    /// - support unwinding with `-Cpanic=unwind`, unlike `extern "C"`
198    /// - often diverge from the C ABI
199    /// - are subject to change between compiler versions
200    pub fn is_rustic_abi(self) -> bool {
201        use ExternAbi::*;
202        matches!(self, Rust | RustCall | RustIntrinsic | RustCold)
203    }
204
205    pub fn supports_varargs(self) -> bool {
206        // * C and Cdecl obviously support varargs.
207        // * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
208        // * EfiApi is based on Win64 or C, so it also supports it.
209        //
210        // * Stdcall does not, because it would be impossible for the callee to clean
211        //   up the arguments. (callee doesn't know how many arguments are there)
212        // * Same for Fastcall, Vectorcall and Thiscall.
213        // * Other calling conventions are related to hardware or the compiler itself.
214        match self {
215            Self::C { .. }
216            | Self::Cdecl { .. }
217            | Self::Aapcs { .. }
218            | Self::Win64 { .. }
219            | Self::SysV64 { .. }
220            | Self::EfiApi => true,
221            _ => false,
222        }
223    }
224}
225
226pub fn all_names() -> Vec<&'static str> {
227    ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect()
228}
229
230impl ExternAbi {
231    /// Default ABI chosen for `extern fn` declarations without an explicit ABI.
232    pub const FALLBACK: Abi = Abi::C { unwind: false };
233
234    pub fn name(self) -> &'static str {
235        self.as_str()
236    }
237}
238
239impl fmt::Display for ExternAbi {
240    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241        write!(f, "\"{}\"", self.as_str())
242    }
243}