|
1 | | -use core::{ |
2 | | - fmt::{self, Debug, Display}, |
3 | | - str::FromStr, |
4 | | -}; |
5 | | - |
6 | | -/// The ABI or calling convention of a function pointer. |
7 | | -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] |
8 | | -// from https://github.com/rust-lang/rust/blob/4fa80a5e733e2202d7ca4c203c2fdfda41cfe7dc/compiler/rustc_abi/src/extern_abi.rs#L21 |
9 | | -pub enum Abi { |
10 | | - /* universal */ |
11 | | - /// This is the same as `extern fn foo()`; whatever the default your C compiler supports. |
12 | | - C { |
13 | | - /// Whether unwinding across this ABI boundary is allowed (`*-unwind`). |
14 | | - unwind: bool, |
15 | | - }, |
16 | | - /// Usually the same as [`extern "C"`](Abi::C), except on Win32, in which case it's |
17 | | - /// [`"stdcall"`](Abi::Stdcall), or what you should use to link to the Windows API itself. |
18 | | - System { |
19 | | - /// Whether unwinding across this ABI boundary is allowed (`*-unwind`). |
20 | | - unwind: bool, |
21 | | - }, |
22 | | - |
23 | | - /// The default ABI when you write a normal `fn foo()` in any Rust code. |
24 | | - Rust, |
25 | | - |
26 | | - /* arm */ |
27 | | - /// The default for ARM. |
28 | | - Aapcs { |
29 | | - /// Whether unwinding across this ABI boundary is allowed (`*-unwind`). |
30 | | - unwind: bool, |
31 | | - }, |
32 | | - |
33 | | - /* x86 */ |
34 | | - /// The default for `x86_32` C code. |
35 | | - Cdecl { |
36 | | - /// Whether unwinding across this ABI boundary is allowed (`*-unwind`). |
37 | | - unwind: bool, |
38 | | - }, |
39 | | - /// The default for the Win32 API on `x86_32`. |
40 | | - Stdcall { |
41 | | - /// Whether unwinding across this ABI boundary is allowed (`*-unwind`). |
42 | | - unwind: bool, |
43 | | - }, |
44 | | - /// The `fastcall` ABI. |
45 | | - Fastcall { |
46 | | - /// Whether unwinding across this ABI boundary is allowed (`*-unwind`). |
47 | | - unwind: bool, |
48 | | - }, |
49 | | - /// The Windows C++ ABI. |
50 | | - Thiscall { |
51 | | - /// Whether unwinding across this ABI boundary is allowed (`*-unwind`). |
52 | | - unwind: bool, |
53 | | - }, |
54 | | - /// The `vectorcall` ABI. |
55 | | - Vectorcall { |
56 | | - /// Whether unwinding across this ABI boundary is allowed (`*-unwind`). |
57 | | - unwind: bool, |
58 | | - }, |
59 | | - |
60 | | - /* x86_64 */ |
61 | | - /// The default for C code on non-Windows `x86_64`. |
62 | | - SysV64 { |
63 | | - /// Whether unwinding across this ABI boundary is allowed (`*-unwind`). |
64 | | - unwind: bool, |
65 | | - }, |
66 | | - /// The default for C code on `x86_64` Windows. |
67 | | - Win64 { |
68 | | - /// Whether unwinding across this ABI boundary is allowed (`*-unwind`). |
69 | | - unwind: bool, |
70 | | - }, |
| 1 | +use crate::AbiValue; |
| 2 | + |
| 3 | +/// Type-level marker trait for function ABI. |
| 4 | +/// |
| 5 | +/// Types implementing this trait represent a specific `extern "..."` ABI. |
| 6 | +/// |
| 7 | +/// See [`Abi`] for the runtime representation. |
| 8 | +pub trait Abi { |
| 9 | + /// The exact ABI string used in `extern "..."`. |
| 10 | + const STR: &'static str; |
| 11 | + |
| 12 | + /// The runtime [`Abi`] that represent this marker type. |
| 13 | + const VALUE: AbiValue; |
| 14 | + |
| 15 | + /// The runtime [`Abi`] that represent this marker type. |
| 16 | + const ALLOWS_UNWIND: bool = Self::VALUE.allows_unwind(); |
71 | 17 | } |
72 | 18 |
|
73 | | -impl Abi { |
74 | | - /// Returns whether unwinding after a panic is allowed inside the called function. |
75 | | - #[must_use] |
76 | | - pub const fn allows_unwind(&self) -> bool { |
77 | | - match *self { |
78 | | - Abi::Rust => true, |
79 | | - Abi::C { unwind } |
80 | | - | Abi::System { unwind } |
81 | | - | Abi::Aapcs { unwind } |
82 | | - | Abi::Cdecl { unwind } |
83 | | - | Abi::Stdcall { unwind } |
84 | | - | Abi::Fastcall { unwind } |
85 | | - | Abi::Thiscall { unwind } |
86 | | - | Abi::Vectorcall { unwind } |
87 | | - | Abi::SysV64 { unwind } |
88 | | - | Abi::Win64 { unwind } => unwind, |
| 19 | +/// Helper macro to implement [`Abi`]. |
| 20 | +macro_rules! define_abi_marker { |
| 21 | + ($name:ident, $lit:literal) => { |
| 22 | + #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
| 23 | + #[doc = "Type-level marker for the `"] |
| 24 | + #[doc = $lit] |
| 25 | + #[doc = "` ABI."] |
| 26 | + pub struct $name; |
| 27 | + |
| 28 | + impl Abi for $name { |
| 29 | + const STR: &'static str = $lit; |
| 30 | + const VALUE: AbiValue = AbiValue::from_str_const($lit).unwrap(); |
89 | 31 | } |
90 | | - } |
91 | | - |
92 | | - /// Canonicalize this ABI for the current target. |
93 | | - /// |
94 | | - /// Maps aliases (e.g. `system`, `cdecl`) to the concrete ABI actually used on |
95 | | - /// the current OS/architecture, following Rust compiler rules. |
96 | | - /// |
97 | | - /// Returns [`None`] if this ABI is not supported on the current target. |
98 | | - #[must_use] |
99 | | - pub fn canonize(self, has_c_varargs: bool) -> Option<Abi> { |
100 | | - // from https://github.com/rust-lang/rust/blob/4fa80a5e733e2202d7ca4c203c2fdfda41cfe7dc/compiler/rustc_target/src/spec/abi_map.rs#L79 |
101 | | - let os_windows = cfg!(target_os = "windows"); |
102 | | - let os_vexos = cfg!(target_os = "vexos"); |
103 | | - |
104 | | - let arch_x86 = cfg!(target_arch = "x86"); |
105 | | - let arch_x86_64 = cfg!(target_arch = "x86_64"); |
106 | | - let arch_arm = cfg!(target_arch = "arm"); |
107 | | - let arch_aarch64 = cfg!(target_arch = "aarch64"); |
108 | | - let arch_arm_any = arch_arm || arch_aarch64; |
109 | | - |
110 | | - #[allow(clippy::match_same_arms)] |
111 | | - let out = match self { |
112 | | - Abi::C { unwind } => Abi::C { unwind }, |
113 | | - Abi::Rust => Abi::Rust, |
114 | | - Abi::System { unwind } if arch_x86 && os_windows && !has_c_varargs => { |
115 | | - Abi::Stdcall { unwind } |
116 | | - } |
117 | | - Abi::System { unwind } if arch_arm && os_vexos => Abi::Aapcs { unwind }, |
118 | | - Abi::System { unwind } => Abi::C { unwind }, |
119 | | - |
120 | | - // arm |
121 | | - Abi::Aapcs { unwind } if arch_arm_any => Abi::Aapcs { unwind }, |
122 | | - Abi::Aapcs { .. } => return None, |
123 | | - |
124 | | - // x86 |
125 | | - Abi::Cdecl { unwind } if arch_x86 => Abi::C { unwind }, |
126 | | - Abi::Cdecl { unwind } => Abi::C { unwind }, |
127 | | - |
128 | | - Abi::Fastcall { unwind } if arch_x86 => Abi::Fastcall { unwind }, |
129 | | - Abi::Fastcall { unwind } if os_windows => Abi::C { unwind }, |
130 | | - Abi::Fastcall { .. } => return None, |
131 | | - |
132 | | - Abi::Stdcall { unwind } if arch_x86 => Abi::Stdcall { unwind }, |
133 | | - Abi::Stdcall { unwind } if os_windows => Abi::C { unwind }, |
134 | | - Abi::Stdcall { .. } => return None, |
135 | | - |
136 | | - Abi::Thiscall { unwind } if arch_x86 => Abi::Thiscall { unwind }, |
137 | | - Abi::Thiscall { .. } => return None, |
138 | | - |
139 | | - Abi::Vectorcall { unwind } if arch_x86 || arch_x86_64 => Abi::Vectorcall { unwind }, |
140 | | - Abi::Vectorcall { .. } => return None, |
141 | | - |
142 | | - Abi::SysV64 { unwind } if arch_x86_64 => Abi::SysV64 { unwind }, |
143 | | - Abi::Win64 { unwind } if arch_x86_64 => Abi::Win64 { unwind }, |
144 | | - Abi::SysV64 { .. } | Abi::Win64 { .. } => return None, |
145 | | - }; |
146 | | - |
147 | | - Some(out) |
148 | | - } |
149 | | -} |
150 | | - |
151 | | -impl Display for Abi { |
152 | | - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
153 | | - write!(f, "{}", self.to_str()) |
154 | | - } |
| 32 | + }; |
155 | 33 | } |
156 | 34 |
|
157 | | -macro_rules! abi_kind_impl { |
158 | | - ( |
159 | | - $t:ty => { |
160 | | - $( |
161 | | - $variant:ident $( { unwind: $uw:literal } )? => $tok:literal, |
162 | | - )* |
163 | | - } |
164 | | - ) => { |
165 | | - impl $t { |
166 | | - /// Returns the string representation of this ABI. |
167 | | - #[must_use] |
168 | | - pub const fn to_str(&self) -> &'static str { |
169 | | - match self { |
170 | | - $( Self::$variant $( { unwind: $uw } )? => $tok, )* |
171 | | - } |
172 | | - } |
| 35 | +// Universal |
| 36 | +define_abi_marker!(C, "C"); |
| 37 | +define_abi_marker!(CUnwind, "C-unwind"); |
| 38 | +define_abi_marker!(System, "system"); |
| 39 | +define_abi_marker!(SystemUnwind, "system-unwind"); |
| 40 | + |
| 41 | +// Rust |
| 42 | +define_abi_marker!(Rust, "Rust"); |
| 43 | + |
| 44 | +// ARM |
| 45 | +define_abi_marker!(Aapcs, "aapcs"); |
| 46 | +define_abi_marker!(AapcsUnwind, "aapcs-unwind"); |
| 47 | + |
| 48 | +// x86 |
| 49 | +define_abi_marker!(Cdecl, "cdecl"); |
| 50 | +define_abi_marker!(CdeclUnwind, "cdecl-unwind"); |
| 51 | +define_abi_marker!(Stdcall, "stdcall"); |
| 52 | +define_abi_marker!(StdcallUnwind, "stdcall-unwind"); |
| 53 | +define_abi_marker!(Fastcall, "fastcall"); |
| 54 | +define_abi_marker!(FastcallUnwind, "fastcall-unwind"); |
| 55 | +define_abi_marker!(Thiscall, "thiscall"); |
| 56 | +define_abi_marker!(ThiscallUnwind, "thiscall-unwind"); |
| 57 | +define_abi_marker!(Vectorcall, "vectorcall"); |
| 58 | +define_abi_marker!(VectorcallUnwind, "vectorcall-unwind"); |
| 59 | + |
| 60 | +// x86_64 |
| 61 | +define_abi_marker!(SysV64, "sysv64"); |
| 62 | +define_abi_marker!(SysV64Unwind, "sysv64-unwind"); |
| 63 | +define_abi_marker!(Win64, "win64"); |
| 64 | +define_abi_marker!(Win64Unwind, "win64-unwind"); |
| 65 | + |
| 66 | +/// Macro to convert an ABI string to the corrsponding [`Abi`] marker type. |
| 67 | +#[macro_export] |
| 68 | +macro_rules! abi { |
| 69 | + // Common |
| 70 | + ("Rust") => { |
| 71 | + $crate::abi::Rust |
| 72 | + }; |
| 73 | + ("C") => { |
| 74 | + $crate::abi::C |
| 75 | + }; |
| 76 | + ("C-unwind") => { |
| 77 | + $crate::abi::CUnwind |
| 78 | + }; |
| 79 | + ("system") => { |
| 80 | + $crate::abi::System |
| 81 | + }; |
| 82 | + ("system-unwind") => { |
| 83 | + $crate::abi::SystemUnwind |
| 84 | + }; |
173 | 85 |
|
174 | | - /// The same as the [`FromStr`] implementation, but (only!) for use in `const` contexts. |
175 | | - #[must_use] |
176 | | - pub const fn from_str_const(conv: &'static str) -> Option<Self> { |
177 | | - $( |
178 | | - if konst::eq_str(conv, $tok) { |
179 | | - return Some(Self::$variant $( { unwind: $uw } )?); |
180 | | - } |
181 | | - )* |
182 | | - None |
183 | | - } |
184 | | - } |
| 86 | + // ARM |
| 87 | + ("aapcs") => { |
| 88 | + $crate::abi::Aapcs |
| 89 | + }; |
| 90 | + ("aapcs-unwind") => { |
| 91 | + $crate::abi::AapcsUnwind |
| 92 | + }; |
185 | 93 |
|
186 | | - impl FromStr for $t { |
187 | | - type Err = (); |
| 94 | + // x86 |
| 95 | + ("cdecl") => { |
| 96 | + $crate::abi::Cdecl |
| 97 | + }; |
| 98 | + ("cdecl-unwind") => { |
| 99 | + $crate::abi::CdeclUnwind |
| 100 | + }; |
| 101 | + ("stdcall") => { |
| 102 | + $crate::abi::Stdcall |
| 103 | + }; |
| 104 | + ("stdcall-unwind") => { |
| 105 | + $crate::abi::StdcallUnwind |
| 106 | + }; |
| 107 | + ("fastcall") => { |
| 108 | + $crate::abi::Fastcall |
| 109 | + }; |
| 110 | + ("fastcall-unwind") => { |
| 111 | + $crate::abi::FastcallUnwind |
| 112 | + }; |
| 113 | + ("thiscall") => { |
| 114 | + $crate::abi::Thiscall |
| 115 | + }; |
| 116 | + ("thiscall-unwind") => { |
| 117 | + $crate::abi::ThiscallUnwind |
| 118 | + }; |
| 119 | + ("vectorcall") => { |
| 120 | + $crate::abi::Vectorcall |
| 121 | + }; |
| 122 | + ("vectorcall-unwind") => { |
| 123 | + $crate::abi::VectorcallUnwind |
| 124 | + }; |
188 | 125 |
|
189 | | - fn from_str(s: &str) -> Result<Self, Self::Err> { |
190 | | - match s { |
191 | | - $( $tok => Ok(Self::$variant $( { unwind: $uw } )?), )* |
192 | | - _ => Err(()), |
193 | | - } |
194 | | - } |
195 | | - } |
| 126 | + // x86_64 |
| 127 | + ("sysv64") => { |
| 128 | + $crate::abi::SysV64 |
| 129 | + }; |
| 130 | + ("sysv64-unwind") => { |
| 131 | + $crate::abi::SysV64Unwind |
| 132 | + }; |
| 133 | + ("win64") => { |
| 134 | + $crate::abi::Win64 |
| 135 | + }; |
| 136 | + ("win64-unwind") => { |
| 137 | + $crate::abi::Win64Unwind |
196 | 138 | }; |
197 | 139 | } |
198 | | - |
199 | | -abi_kind_impl!(Abi => { |
200 | | - Rust => "Rust", |
201 | | - |
202 | | - C { unwind: false } => "C", |
203 | | - C { unwind: true } => "C-unwind", |
204 | | - System { unwind: false } => "system", |
205 | | - System { unwind: true } => "system-unwind", |
206 | | - |
207 | | - Aapcs { unwind: false } => "aapcs", |
208 | | - Aapcs { unwind: true } => "aapcs-unwind", |
209 | | - |
210 | | - Cdecl { unwind: false } => "cdecl", |
211 | | - Cdecl { unwind: true } => "cdecl-unwind", |
212 | | - Stdcall { unwind: false } => "stdcall", |
213 | | - Stdcall { unwind: true } => "stdcall-unwind", |
214 | | - Fastcall { unwind: false } => "fastcall", |
215 | | - Fastcall { unwind: true } => "fastcall-unwind", |
216 | | - Thiscall { unwind: false } => "thiscall", |
217 | | - Thiscall { unwind: true } => "thiscall-unwind", |
218 | | - Vectorcall { unwind: false } => "vectorcall", |
219 | | - Vectorcall { unwind: true } => "vectorcall-unwind", |
220 | | - |
221 | | - SysV64 { unwind: false } => "sysv64", |
222 | | - SysV64 { unwind: true } => "sysv64-unwind", |
223 | | - Win64 { unwind: false } => "win64", |
224 | | - Win64 { unwind: true } => "win64-unwind", |
225 | | -}); |
0 commit comments