]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_target/src/spec/abi.rs
New upstream version 1.68.2+dfsg1
[rustc.git] / compiler / rustc_target / src / spec / abi.rs
CommitLineData
1a4d82fc
JJ
1use std::fmt;
2
60c5eb7d 3use rustc_macros::HashStable_Generic;
2b03887a
FG
4use rustc_span::symbol::sym;
5use rustc_span::{Span, Symbol};
60c5eb7d 6
416331ca
XL
7#[cfg(test)]
8mod tests;
9
3dfed10e
XL
10#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
11#[derive(HashStable_Generic, Encodable, Decodable)]
223e47cc 12pub enum Abi {
136023e0
XL
13 // Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the
14 // hashing tests. These are used in many places, so giving them stable values reduces test
15 // churn. The specific values are meaningless.
6a06907d
XL
16 Rust,
17 C { unwind: bool },
5099ac24 18 Cdecl { unwind: bool },
6a06907d 19 Stdcall { unwind: bool },
5099ac24
FG
20 Fastcall { unwind: bool },
21 Vectorcall { unwind: bool },
6a06907d 22 Thiscall { unwind: bool },
5099ac24
FG
23 Aapcs { unwind: bool },
24 Win64 { unwind: bool },
25 SysV64 { unwind: bool },
32a655c1
SL
26 PtxKernel,
27 Msp430Interrupt,
8bb4bdeb 28 X86Interrupt,
8faf50e0 29 AmdGpuKernel,
e74abb32 30 EfiApi,
f035d41b
XL
31 AvrInterrupt,
32 AvrNonBlockingInterrupt,
5869c6ff 33 CCmseNonSecureCall,
cdc7bbd5 34 Wasm,
6a06907d 35 System { unwind: bool },
223e47cc 36 RustIntrinsic,
1a4d82fc 37 RustCall,
e9174d1e 38 PlatformIntrinsic,
dfeec247 39 Unadjusted,
923072b8 40 RustCold,
223e47cc
LB
41}
42
487cf647
FG
43impl Abi {
44 pub fn supports_varargs(self) -> bool {
45 // * C and Cdecl obviously support varargs.
46 // * C can be based on SysV64 or Win64, so they must support varargs.
47 // * EfiApi is based on Win64 or C, so it also supports it.
48 //
49 // * Stdcall does not, because it would be impossible for the callee to clean
50 // up the arguments. (callee doesn't know how many arguments are there)
51 // * Same for Fastcall, Vectorcall and Thiscall.
52 // * System can become Stdcall, so is also a no-no.
53 // * Other calling conventions are related to hardware or the compiler itself.
54 match self {
55 Self::C { .. }
56 | Self::Cdecl { .. }
57 | Self::Win64 { .. }
58 | Self::SysV64 { .. }
59 | Self::EfiApi => true,
60 _ => false,
61 }
62 }
63}
64
c34b1796 65#[derive(Copy, Clone)]
1a4d82fc 66pub struct AbiData {
223e47cc
LB
67 abi: Abi,
68
c30ab7b3 69 /// Name of this ABI as we like it called.
223e47cc 70 name: &'static str,
223e47cc
LB
71}
72
1a4d82fc 73#[allow(non_upper_case_globals)]
b7449926 74const AbiDatas: &[AbiData] = &[
136023e0
XL
75 AbiData { abi: Abi::Rust, name: "Rust" },
76 AbiData { abi: Abi::C { unwind: false }, name: "C" },
77 AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" },
5099ac24
FG
78 AbiData { abi: Abi::Cdecl { unwind: false }, name: "cdecl" },
79 AbiData { abi: Abi::Cdecl { unwind: true }, name: "cdecl-unwind" },
136023e0
XL
80 AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall" },
81 AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind" },
5099ac24
FG
82 AbiData { abi: Abi::Fastcall { unwind: false }, name: "fastcall" },
83 AbiData { abi: Abi::Fastcall { unwind: true }, name: "fastcall-unwind" },
84 AbiData { abi: Abi::Vectorcall { unwind: false }, name: "vectorcall" },
85 AbiData { abi: Abi::Vectorcall { unwind: true }, name: "vectorcall-unwind" },
136023e0
XL
86 AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall" },
87 AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind" },
5099ac24
FG
88 AbiData { abi: Abi::Aapcs { unwind: false }, name: "aapcs" },
89 AbiData { abi: Abi::Aapcs { unwind: true }, name: "aapcs-unwind" },
90 AbiData { abi: Abi::Win64 { unwind: false }, name: "win64" },
91 AbiData { abi: Abi::Win64 { unwind: true }, name: "win64-unwind" },
92 AbiData { abi: Abi::SysV64 { unwind: false }, name: "sysv64" },
93 AbiData { abi: Abi::SysV64 { unwind: true }, name: "sysv64-unwind" },
136023e0
XL
94 AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" },
95 AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" },
96 AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" },
97 AbiData { abi: Abi::AmdGpuKernel, name: "amdgpu-kernel" },
98 AbiData { abi: Abi::EfiApi, name: "efiapi" },
99 AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" },
100 AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" },
101 AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" },
102 AbiData { abi: Abi::Wasm, name: "wasm" },
103 AbiData { abi: Abi::System { unwind: false }, name: "system" },
104 AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" },
105 AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" },
106 AbiData { abi: Abi::RustCall, name: "rust-call" },
107 AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" },
108 AbiData { abi: Abi::Unadjusted, name: "unadjusted" },
923072b8 109 AbiData { abi: Abi::RustCold, name: "rust-cold" },
223e47cc
LB
110];
111
1a4d82fc 112/// Returns the ABI with the given name (if any).
223e47cc 113pub fn lookup(name: &str) -> Option<Abi> {
1a4d82fc 114 AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi)
223e47cc
LB
115}
116
1a4d82fc
JJ
117pub fn all_names() -> Vec<&'static str> {
118 AbiDatas.iter().map(|d| d.name).collect()
223e47cc
LB
119}
120
2b03887a
FG
121pub fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> {
122 AbiDatas
123 .iter()
124 .map(|d| d.name)
125 .filter(|name| is_enabled(features, span, name).is_ok())
126 .collect()
127}
128
129pub enum AbiDisabled {
130 Unstable { feature: Symbol, explain: &'static str },
131 Unrecognized,
132}
133
134pub fn is_enabled(
135 features: &rustc_feature::Features,
136 span: Span,
137 name: &str,
138) -> Result<(), AbiDisabled> {
139 let s = is_stable(name);
140 if let Err(AbiDisabled::Unstable { feature, .. }) = s {
141 if features.enabled(feature) || span.allows_unstable(feature) {
142 return Ok(());
143 }
144 }
145 s
146}
147
148pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
149 match name {
150 // Stable
151 "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
9c376795 152 | "system" | "efiapi" => Ok(()),
2b03887a
FG
153 "rust-intrinsic" => Err(AbiDisabled::Unstable {
154 feature: sym::intrinsics,
155 explain: "intrinsics are subject to change",
156 }),
157 "platform-intrinsic" => Err(AbiDisabled::Unstable {
158 feature: sym::platform_intrinsics,
159 explain: "platform intrinsics are experimental and possibly buggy",
160 }),
161 "vectorcall" => Err(AbiDisabled::Unstable {
162 feature: sym::abi_vectorcall,
163 explain: "vectorcall is experimental and subject to change",
164 }),
165 "thiscall" => Err(AbiDisabled::Unstable {
166 feature: sym::abi_thiscall,
167 explain: "thiscall is experimental and subject to change",
168 }),
169 "rust-call" => Err(AbiDisabled::Unstable {
170 feature: sym::unboxed_closures,
171 explain: "rust-call ABI is subject to change",
172 }),
173 "rust-cold" => Err(AbiDisabled::Unstable {
174 feature: sym::rust_cold_cc,
175 explain: "rust-cold is experimental and subject to change",
176 }),
177 "ptx-kernel" => Err(AbiDisabled::Unstable {
178 feature: sym::abi_ptx,
179 explain: "PTX ABIs are experimental and subject to change",
180 }),
181 "unadjusted" => Err(AbiDisabled::Unstable {
182 feature: sym::abi_unadjusted,
183 explain: "unadjusted ABI is an implementation detail and perma-unstable",
184 }),
185 "msp430-interrupt" => Err(AbiDisabled::Unstable {
186 feature: sym::abi_msp430_interrupt,
187 explain: "msp430-interrupt ABI is experimental and subject to change",
188 }),
189 "x86-interrupt" => Err(AbiDisabled::Unstable {
190 feature: sym::abi_x86_interrupt,
191 explain: "x86-interrupt ABI is experimental and subject to change",
192 }),
193 "amdgpu-kernel" => Err(AbiDisabled::Unstable {
194 feature: sym::abi_amdgpu_kernel,
195 explain: "amdgpu-kernel ABI is experimental and subject to change",
196 }),
197 "avr-interrupt" | "avr-non-blocking-interrupt" => Err(AbiDisabled::Unstable {
198 feature: sym::abi_avr_interrupt,
199 explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
200 }),
2b03887a
FG
201 "C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable {
202 feature: sym::abi_c_cmse_nonsecure_call,
203 explain: "C-cmse-nonsecure-call ABI is experimental and subject to change",
204 }),
205 "C-unwind" => Err(AbiDisabled::Unstable {
206 feature: sym::c_unwind,
207 explain: "C-unwind ABI is experimental and subject to change",
208 }),
209 "stdcall-unwind" => Err(AbiDisabled::Unstable {
210 feature: sym::c_unwind,
211 explain: "stdcall-unwind ABI is experimental and subject to change",
212 }),
213 "system-unwind" => Err(AbiDisabled::Unstable {
214 feature: sym::c_unwind,
215 explain: "system-unwind ABI is experimental and subject to change",
216 }),
217 "thiscall-unwind" => Err(AbiDisabled::Unstable {
218 feature: sym::c_unwind,
219 explain: "thiscall-unwind ABI is experimental and subject to change",
220 }),
221 "cdecl-unwind" => Err(AbiDisabled::Unstable {
222 feature: sym::c_unwind,
223 explain: "cdecl-unwind ABI is experimental and subject to change",
224 }),
225 "fastcall-unwind" => Err(AbiDisabled::Unstable {
226 feature: sym::c_unwind,
227 explain: "fastcall-unwind ABI is experimental and subject to change",
228 }),
229 "vectorcall-unwind" => Err(AbiDisabled::Unstable {
230 feature: sym::c_unwind,
231 explain: "vectorcall-unwind ABI is experimental and subject to change",
232 }),
233 "aapcs-unwind" => Err(AbiDisabled::Unstable {
234 feature: sym::c_unwind,
235 explain: "aapcs-unwind ABI is experimental and subject to change",
236 }),
237 "win64-unwind" => Err(AbiDisabled::Unstable {
238 feature: sym::c_unwind,
239 explain: "win64-unwind ABI is experimental and subject to change",
240 }),
241 "sysv64-unwind" => Err(AbiDisabled::Unstable {
242 feature: sym::c_unwind,
243 explain: "sysv64-unwind ABI is experimental and subject to change",
244 }),
245 "wasm" => Err(AbiDisabled::Unstable {
246 feature: sym::wasm_abi,
247 explain: "wasm ABI is experimental and subject to change",
248 }),
249 _ => Err(AbiDisabled::Unrecognized),
250 }
251}
252
970d7e83 253impl Abi {
94222f64
XL
254 /// Default ABI chosen for `extern fn` declarations without an explicit ABI.
255 pub const FALLBACK: Abi = Abi::C { unwind: false };
256
223e47cc 257 #[inline]
b7449926 258 pub fn index(self) -> usize {
6a06907d
XL
259 // N.B., this ordering MUST match the AbiDatas array above.
260 // (This is ensured by the test indices_are_correct().)
261 use Abi::*;
262 let i = match self {
263 // Cross-platform ABIs
264 Rust => 0,
265 C { unwind: false } => 1,
266 C { unwind: true } => 2,
267 // Platform-specific ABIs
5099ac24
FG
268 Cdecl { unwind: false } => 3,
269 Cdecl { unwind: true } => 4,
270 Stdcall { unwind: false } => 5,
271 Stdcall { unwind: true } => 6,
272 Fastcall { unwind: false } => 7,
273 Fastcall { unwind: true } => 8,
274 Vectorcall { unwind: false } => 9,
275 Vectorcall { unwind: true } => 10,
276 Thiscall { unwind: false } => 11,
277 Thiscall { unwind: true } => 12,
278 Aapcs { unwind: false } => 13,
279 Aapcs { unwind: true } => 14,
280 Win64 { unwind: false } => 15,
281 Win64 { unwind: true } => 16,
282 SysV64 { unwind: false } => 17,
283 SysV64 { unwind: true } => 18,
284 PtxKernel => 19,
285 Msp430Interrupt => 20,
286 X86Interrupt => 21,
287 AmdGpuKernel => 22,
288 EfiApi => 23,
289 AvrInterrupt => 24,
290 AvrNonBlockingInterrupt => 25,
291 CCmseNonSecureCall => 26,
292 Wasm => 27,
6a06907d 293 // Cross-platform ABIs
5099ac24
FG
294 System { unwind: false } => 28,
295 System { unwind: true } => 29,
296 RustIntrinsic => 30,
297 RustCall => 31,
298 PlatformIntrinsic => 32,
299 Unadjusted => 33,
923072b8 300 RustCold => 34,
6a06907d
XL
301 };
302 debug_assert!(
303 AbiDatas
304 .iter()
305 .enumerate()
306 .find(|(_, AbiData { abi, .. })| *abi == self)
307 .map(|(index, _)| index)
308 .expect("abi variant has associated data")
309 == i,
310 "Abi index did not match `AbiDatas` ordering"
311 );
312 i
223e47cc
LB
313 }
314
315 #[inline]
b7449926 316 pub fn data(self) -> &'static AbiData {
223e47cc
LB
317 &AbiDatas[self.index()]
318 }
319
b7449926 320 pub fn name(self) -> &'static str {
223e47cc
LB
321 self.data().name
322 }
323}
324
85aaf69f 325impl fmt::Display for Abi {
9fa01778 326 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
6a06907d
XL
327 match self {
328 abi => write!(f, "\"{}\"", abi.name()),
329 }
223e47cc
LB
330 }
331}