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#[cfg(feature = "nightly")]
10use rustc_span::Symbol;
11
12use crate::AbiFromStrErr;
13
14#[cfg(test)]
15mod tests;
16
17#[derive(Clone, Copy, Debug)]
19#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))]
20pub enum ExternAbi {
21 C {
24 unwind: bool,
25 },
26 System {
28 unwind: bool,
29 },
30
31 Rust,
33 RustCall,
36 RustCold,
40
41 RustInvalid,
44
45 Unadjusted,
48
49 Custom,
53
54 EfiApi,
57
58 Aapcs {
61 unwind: bool,
62 },
63 CmseNonSecureCall,
65 CmseNonSecureEntry,
67
68 GpuKernel,
72 PtxKernel,
75
76 AvrInterrupt,
78 AvrNonBlockingInterrupt,
79 Msp430Interrupt,
80 RiscvInterruptM,
81 RiscvInterruptS,
82 X86Interrupt,
83
84 Cdecl {
87 unwind: bool,
88 },
89 Stdcall {
91 unwind: bool,
92 },
93 Fastcall {
95 unwind: bool,
96 },
97 Thiscall {
99 unwind: bool,
100 },
101 Vectorcall {
103 unwind: bool,
104 },
105
106 SysV64 {
108 unwind: bool,
109 },
110 Win64 {
111 unwind: bool,
112 },
113}
114
115macro_rules! abi_impls {
116 ($e_name:ident = {
117 $($variant:ident $({ unwind: $uw:literal })? =><= $tok:literal,)*
118 }) => {
119 impl $e_name {
120 pub const ALL_VARIANTS: &[Self] = &[
121 $($e_name::$variant $({ unwind: $uw })*,)*
122 ];
123 pub const fn as_str(&self) -> &'static str {
124 match self {
125 $($e_name::$variant $( { unwind: $uw } )* => $tok,)*
126 }
127 }
128 }
129
130 impl ::core::str::FromStr for $e_name {
131 type Err = AbiFromStrErr;
132 fn from_str(s: &str) -> Result<$e_name, Self::Err> {
133 match s {
134 $($tok => Ok($e_name::$variant $({ unwind: $uw })*),)*
135 _ => Err(AbiFromStrErr::Unknown),
136 }
137 }
138 }
139 }
140}
141
142abi_impls! {
143 ExternAbi = {
144 C { unwind: false } =><= "C",
145 C { unwind: true } =><= "C-unwind",
146 Rust =><= "Rust",
147 Aapcs { unwind: false } =><= "aapcs",
148 Aapcs { unwind: true } =><= "aapcs-unwind",
149 AvrInterrupt =><= "avr-interrupt",
150 AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
151 Cdecl { unwind: false } =><= "cdecl",
152 Cdecl { unwind: true } =><= "cdecl-unwind",
153 CmseNonSecureCall =><= "cmse-nonsecure-call",
154 CmseNonSecureEntry =><= "cmse-nonsecure-entry",
155 Custom =><= "custom",
156 EfiApi =><= "efiapi",
157 Fastcall { unwind: false } =><= "fastcall",
158 Fastcall { unwind: true } =><= "fastcall-unwind",
159 GpuKernel =><= "gpu-kernel",
160 Msp430Interrupt =><= "msp430-interrupt",
161 PtxKernel =><= "ptx-kernel",
162 RiscvInterruptM =><= "riscv-interrupt-m",
163 RiscvInterruptS =><= "riscv-interrupt-s",
164 RustCall =><= "rust-call",
165 RustCold =><= "rust-cold",
166 RustInvalid =><= "rust-invalid",
167 Stdcall { unwind: false } =><= "stdcall",
168 Stdcall { unwind: true } =><= "stdcall-unwind",
169 System { unwind: false } =><= "system",
170 System { unwind: true } =><= "system-unwind",
171 SysV64 { unwind: false } =><= "sysv64",
172 SysV64 { unwind: true } =><= "sysv64-unwind",
173 Thiscall { unwind: false } =><= "thiscall",
174 Thiscall { unwind: true } =><= "thiscall-unwind",
175 Unadjusted =><= "unadjusted",
176 Vectorcall { unwind: false } =><= "vectorcall",
177 Vectorcall { unwind: true } =><= "vectorcall-unwind",
178 Win64 { unwind: false } =><= "win64",
179 Win64 { unwind: true } =><= "win64-unwind",
180 X86Interrupt =><= "x86-interrupt",
181 }
182}
183
184impl Ord for ExternAbi {
185 fn cmp(&self, rhs: &Self) -> Ordering {
186 self.as_str().cmp(rhs.as_str())
187 }
188}
189
190impl PartialOrd for ExternAbi {
191 fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
192 Some(self.cmp(rhs))
193 }
194}
195
196impl PartialEq for ExternAbi {
197 fn eq(&self, rhs: &Self) -> bool {
198 self.cmp(rhs) == Ordering::Equal
199 }
200}
201
202impl Eq for ExternAbi {}
203
204impl Hash for ExternAbi {
205 fn hash<H: Hasher>(&self, state: &mut H) {
206 self.as_str().hash(state);
207 u32::from_be_bytes(*b"ABI\0").hash(state);
209 }
210}
211
212#[cfg(feature = "nightly")]
213impl<C> HashStable<C> for ExternAbi {
214 #[inline]
215 fn hash_stable(&self, _: &mut C, hasher: &mut StableHasher) {
216 Hash::hash(self, hasher);
217 }
218}
219
220#[cfg(feature = "nightly")]
221impl StableOrd for ExternAbi {
222 const CAN_USE_UNSTABLE_SORT: bool = true;
223
224 const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
226}
227
228#[cfg(feature = "nightly")]
229rustc_error_messages::into_diag_arg_using_display!(ExternAbi);
230
231#[cfg(feature = "nightly")]
232pub enum CVariadicStatus {
233 NotSupported,
234 Stable,
235 Unstable { feature: Symbol },
236}
237
238impl ExternAbi {
239 pub fn is_rustic_abi(self) -> bool {
246 use ExternAbi::*;
247 matches!(self, Rust | RustCall | RustCold)
248 }
249
250 #[cfg(feature = "nightly")]
254 pub fn supports_c_variadic(self) -> CVariadicStatus {
255 match self {
267 Self::C { .. }
268 | Self::Cdecl { .. }
269 | Self::Aapcs { .. }
270 | Self::Win64 { .. }
271 | Self::SysV64 { .. }
272 | Self::EfiApi => CVariadicStatus::Stable,
273 Self::System { .. } => {
274 CVariadicStatus::Unstable { feature: rustc_span::sym::extern_system_varargs }
275 }
276 _ => CVariadicStatus::NotSupported,
277 }
278 }
279}
280
281pub fn all_names() -> Vec<&'static str> {
282 ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect()
283}
284
285impl ExternAbi {
286 pub const FALLBACK: ExternAbi = ExternAbi::C { unwind: false };
288
289 pub fn name(self) -> &'static str {
290 self.as_str()
291 }
292}
293
294impl fmt::Display for ExternAbi {
295 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296 write!(f, "\"{}\"", self.as_str())
297 }
298}