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
10use crate::AbiFromStrErr;
11
12#[cfg(test)]
13mod tests;
14
15use ExternAbi as Abi;
16
17#[derive(Clone, Copy, Debug)]
18#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))]
19pub enum ExternAbi {
20 Rust,
24 C {
25 unwind: bool,
26 },
27 Cdecl {
28 unwind: bool,
29 },
30 Stdcall {
31 unwind: bool,
32 },
33 Fastcall {
34 unwind: bool,
35 },
36 Vectorcall {
37 unwind: bool,
38 },
39 Thiscall {
40 unwind: bool,
41 },
42 Aapcs {
43 unwind: bool,
44 },
45 Win64 {
46 unwind: bool,
47 },
48 SysV64 {
49 unwind: bool,
50 },
51 PtxKernel,
52 Msp430Interrupt,
53 X86Interrupt,
54 GpuKernel,
57 EfiApi,
58 AvrInterrupt,
59 AvrNonBlockingInterrupt,
60 CCmseNonSecureCall,
61 CCmseNonSecureEntry,
62 System {
63 unwind: bool,
64 },
65 RustCall,
66 Unadjusted,
69 RustCold,
73 RiscvInterruptM,
74 RiscvInterruptS,
75}
76
77macro_rules! abi_impls {
78 ($e_name:ident = {
79 $($variant:ident $({ unwind: $uw:literal })? =><= $tok:literal,)*
80 }) => {
81 impl $e_name {
82 pub const ALL_VARIANTS: &[Self] = &[
83 $($e_name::$variant $({ unwind: $uw })*,)*
84 ];
85 pub const fn as_str(&self) -> &'static str {
86 match self {
87 $($e_name::$variant $( { unwind: $uw } )* => $tok,)*
88 }
89 }
90 }
91
92 impl ::core::str::FromStr for $e_name {
93 type Err = AbiFromStrErr;
94 fn from_str(s: &str) -> Result<$e_name, Self::Err> {
95 match s {
96 $($tok => Ok($e_name::$variant $({ unwind: $uw })*),)*
97 _ => Err(AbiFromStrErr::Unknown),
98 }
99 }
100 }
101 }
102}
103
104abi_impls! {
105 ExternAbi = {
106 C { unwind: false } =><= "C",
107 CCmseNonSecureCall =><= "C-cmse-nonsecure-call",
108 CCmseNonSecureEntry =><= "C-cmse-nonsecure-entry",
109 C { unwind: true } =><= "C-unwind",
110 Rust =><= "Rust",
111 Aapcs { unwind: false } =><= "aapcs",
112 Aapcs { unwind: true } =><= "aapcs-unwind",
113 AvrInterrupt =><= "avr-interrupt",
114 AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
115 Cdecl { unwind: false } =><= "cdecl",
116 Cdecl { unwind: true } =><= "cdecl-unwind",
117 EfiApi =><= "efiapi",
118 Fastcall { unwind: false } =><= "fastcall",
119 Fastcall { unwind: true } =><= "fastcall-unwind",
120 GpuKernel =><= "gpu-kernel",
121 Msp430Interrupt =><= "msp430-interrupt",
122 PtxKernel =><= "ptx-kernel",
123 RiscvInterruptM =><= "riscv-interrupt-m",
124 RiscvInterruptS =><= "riscv-interrupt-s",
125 RustCall =><= "rust-call",
126 RustCold =><= "rust-cold",
127 Stdcall { unwind: false } =><= "stdcall",
128 Stdcall { unwind: true } =><= "stdcall-unwind",
129 System { unwind: false } =><= "system",
130 System { unwind: true } =><= "system-unwind",
131 SysV64 { unwind: false } =><= "sysv64",
132 SysV64 { unwind: true } =><= "sysv64-unwind",
133 Thiscall { unwind: false } =><= "thiscall",
134 Thiscall { unwind: true } =><= "thiscall-unwind",
135 Unadjusted =><= "unadjusted",
136 Vectorcall { unwind: false } =><= "vectorcall",
137 Vectorcall { unwind: true } =><= "vectorcall-unwind",
138 Win64 { unwind: false } =><= "win64",
139 Win64 { unwind: true } =><= "win64-unwind",
140 X86Interrupt =><= "x86-interrupt",
141 }
142}
143
144impl Ord for ExternAbi {
145 fn cmp(&self, rhs: &Self) -> Ordering {
146 self.as_str().cmp(rhs.as_str())
147 }
148}
149
150impl PartialOrd for ExternAbi {
151 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
152 Some(self.cmp(rhs))
153 }
154}
155
156impl PartialEq for ExternAbi {
157 fn eq(&self, rhs: &Self) -> bool {
158 self.cmp(rhs) == Ordering::Equal
159 }
160}
161
162impl Eq for ExternAbi {}
163
164impl Hash for ExternAbi {
165 fn hash<H: Hasher>(&self, state: &mut H) {
166 self.as_str().hash(state);
167 u32::from_be_bytes(*b"ABI\0").hash(state);
169 }
170}
171
172#[cfg(feature = "nightly")]
173impl<C> HashStable<C> for ExternAbi {
174 #[inline]
175 fn hash_stable(&self, _: &mut C, hasher: &mut StableHasher) {
176 Hash::hash(self, hasher);
177 }
178}
179
180#[cfg(feature = "nightly")]
181impl StableOrd for ExternAbi {
182 const CAN_USE_UNSTABLE_SORT: bool = true;
183
184 const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
186}
187
188impl ExternAbi {
189 pub fn is_rustic_abi(self) -> bool {
196 use ExternAbi::*;
197 matches!(self, Rust | RustCall | RustCold)
198 }
199
200 pub fn supports_varargs(self) -> bool {
201 match self {
210 Self::C { .. }
211 | Self::Cdecl { .. }
212 | Self::Aapcs { .. }
213 | Self::Win64 { .. }
214 | Self::SysV64 { .. }
215 | Self::EfiApi => true,
216 _ => false,
217 }
218 }
219}
220
221pub fn all_names() -> Vec<&'static str> {
222 ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect()
223}
224
225impl ExternAbi {
226 pub const FALLBACK: Abi = Abi::C { unwind: false };
228
229 pub fn name(self) -> &'static str {
230 self.as_str()
231 }
232}
233
234impl fmt::Display for ExternAbi {
235 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236 write!(f, "\"{}\"", self.as_str())
237 }
238}