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 RustIntrinsic,
64 RustCall,
65 Unadjusted,
68 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 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 const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
191}
192
193impl ExternAbi {
194 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 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 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}