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 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 GpuKernel,
55 EfiApi,
56 AvrInterrupt,
57 AvrNonBlockingInterrupt,
58 CCmseNonSecureCall,
59 CCmseNonSecureEntry,
60 System {
61 unwind: bool,
62 },
63 RustCall,
64 Unadjusted,
67 RustCold,
71 RiscvInterruptM,
72 RiscvInterruptS,
73}
74
75macro_rules! abi_impls {
76 ($e_name:ident = {
77 $($variant:ident $({ unwind: $uw:literal })? =><= $tok:literal,)*
78 }) => {
79 impl $e_name {
80 pub const ALL_VARIANTS: &[Self] = &[
81 $($e_name::$variant $({ unwind: $uw })*,)*
82 ];
83 pub const fn as_str(&self) -> &'static str {
84 match self {
85 $($e_name::$variant $( { unwind: $uw } )* => $tok,)*
86 }
87 }
88 }
89
90 impl ::core::str::FromStr for $e_name {
91 type Err = AbiFromStrErr;
92 fn from_str(s: &str) -> Result<$e_name, Self::Err> {
93 match s {
94 $($tok => Ok($e_name::$variant $({ unwind: $uw })*),)*
95 _ => Err(AbiFromStrErr::Unknown),
96 }
97 }
98 }
99 }
100}
101
102#[derive(Debug)]
103pub enum AbiFromStrErr {
104 Unknown,
105}
106
107abi_impls! {
108 ExternAbi = {
109 C { unwind: false } =><= "C",
110 CCmseNonSecureCall =><= "C-cmse-nonsecure-call",
111 CCmseNonSecureEntry =><= "C-cmse-nonsecure-entry",
112 C { unwind: true } =><= "C-unwind",
113 Rust =><= "Rust",
114 Aapcs { unwind: false } =><= "aapcs",
115 Aapcs { unwind: true } =><= "aapcs-unwind",
116 AvrInterrupt =><= "avr-interrupt",
117 AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
118 Cdecl { unwind: false } =><= "cdecl",
119 Cdecl { unwind: true } =><= "cdecl-unwind",
120 EfiApi =><= "efiapi",
121 Fastcall { unwind: false } =><= "fastcall",
122 Fastcall { unwind: true } =><= "fastcall-unwind",
123 GpuKernel =><= "gpu-kernel",
124 Msp430Interrupt =><= "msp430-interrupt",
125 PtxKernel =><= "ptx-kernel",
126 RiscvInterruptM =><= "riscv-interrupt-m",
127 RiscvInterruptS =><= "riscv-interrupt-s",
128 RustCall =><= "rust-call",
129 RustCold =><= "rust-cold",
130 Stdcall { unwind: false } =><= "stdcall",
131 Stdcall { unwind: true } =><= "stdcall-unwind",
132 System { unwind: false } =><= "system",
133 System { unwind: true } =><= "system-unwind",
134 SysV64 { unwind: false } =><= "sysv64",
135 SysV64 { unwind: true } =><= "sysv64-unwind",
136 Thiscall { unwind: false } =><= "thiscall",
137 Thiscall { unwind: true } =><= "thiscall-unwind",
138 Unadjusted =><= "unadjusted",
139 Vectorcall { unwind: false } =><= "vectorcall",
140 Vectorcall { unwind: true } =><= "vectorcall-unwind",
141 Win64 { unwind: false } =><= "win64",
142 Win64 { unwind: true } =><= "win64-unwind",
143 X86Interrupt =><= "x86-interrupt",
144 }
145}
146
147impl Ord for ExternAbi {
148 fn cmp(&self, rhs: &Self) -> Ordering {
149 self.as_str().cmp(rhs.as_str())
150 }
151}
152
153impl PartialOrd for ExternAbi {
154 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
155 Some(self.cmp(rhs))
156 }
157}
158
159impl PartialEq for ExternAbi {
160 fn eq(&self, rhs: &Self) -> bool {
161 self.cmp(rhs) == Ordering::Equal
162 }
163}
164
165impl Eq for ExternAbi {}
166
167impl Hash for ExternAbi {
168 fn hash<H: Hasher>(&self, state: &mut H) {
169 self.as_str().hash(state);
170 u32::from_be_bytes(*b"ABI\0").hash(state);
172 }
173}
174
175#[cfg(feature = "nightly")]
176impl<C> HashStable<C> for ExternAbi {
177 #[inline]
178 fn hash_stable(&self, _: &mut C, hasher: &mut StableHasher) {
179 Hash::hash(self, hasher);
180 }
181}
182
183#[cfg(feature = "nightly")]
184impl StableOrd for ExternAbi {
185 const CAN_USE_UNSTABLE_SORT: bool = true;
186
187 const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
189}
190
191impl ExternAbi {
192 pub fn is_rustic_abi(self) -> bool {
199 use ExternAbi::*;
200 matches!(self, Rust | RustCall | RustCold)
201 }
202
203 pub fn supports_varargs(self) -> bool {
204 match self {
213 Self::C { .. }
214 | Self::Cdecl { .. }
215 | Self::Aapcs { .. }
216 | Self::Win64 { .. }
217 | Self::SysV64 { .. }
218 | Self::EfiApi => true,
219 _ => false,
220 }
221 }
222}
223
224pub fn all_names() -> Vec<&'static str> {
225 ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect()
226}
227
228impl ExternAbi {
229 pub const FALLBACK: Abi = Abi::C { unwind: false };
231
232 pub fn name(self) -> &'static str {
233 self.as_str()
234 }
235}
236
237impl fmt::Display for ExternAbi {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 write!(f, "\"{}\"", self.as_str())
240 }
241}