]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_target/src/spec/abi.rs
Rollup merge of #99216 - duarten:master, r=joshtriplett
[rust.git] / compiler / rustc_target / src / spec / abi.rs
1 use std::fmt;
2
3 use rustc_macros::HashStable_Generic;
4 use rustc_span::symbol::sym;
5 use rustc_span::{Span, Symbol};
6
7 #[cfg(test)]
8 mod tests;
9
10 #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
11 #[derive(HashStable_Generic, Encodable, Decodable)]
12 pub enum Abi {
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.
16     Rust,
17     C { unwind: bool },
18     Cdecl { unwind: bool },
19     Stdcall { unwind: bool },
20     Fastcall { unwind: bool },
21     Vectorcall { unwind: bool },
22     Thiscall { unwind: bool },
23     Aapcs { unwind: bool },
24     Win64 { unwind: bool },
25     SysV64 { unwind: bool },
26     PtxKernel,
27     Msp430Interrupt,
28     X86Interrupt,
29     AmdGpuKernel,
30     EfiApi,
31     AvrInterrupt,
32     AvrNonBlockingInterrupt,
33     CCmseNonSecureCall,
34     Wasm,
35     System { unwind: bool },
36     RustIntrinsic,
37     RustCall,
38     PlatformIntrinsic,
39     Unadjusted,
40     RustCold,
41 }
42
43 #[derive(Copy, Clone)]
44 pub struct AbiData {
45     abi: Abi,
46
47     /// Name of this ABI as we like it called.
48     name: &'static str,
49 }
50
51 #[allow(non_upper_case_globals)]
52 const AbiDatas: &[AbiData] = &[
53     AbiData { abi: Abi::Rust, name: "Rust" },
54     AbiData { abi: Abi::C { unwind: false }, name: "C" },
55     AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" },
56     AbiData { abi: Abi::Cdecl { unwind: false }, name: "cdecl" },
57     AbiData { abi: Abi::Cdecl { unwind: true }, name: "cdecl-unwind" },
58     AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall" },
59     AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind" },
60     AbiData { abi: Abi::Fastcall { unwind: false }, name: "fastcall" },
61     AbiData { abi: Abi::Fastcall { unwind: true }, name: "fastcall-unwind" },
62     AbiData { abi: Abi::Vectorcall { unwind: false }, name: "vectorcall" },
63     AbiData { abi: Abi::Vectorcall { unwind: true }, name: "vectorcall-unwind" },
64     AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall" },
65     AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind" },
66     AbiData { abi: Abi::Aapcs { unwind: false }, name: "aapcs" },
67     AbiData { abi: Abi::Aapcs { unwind: true }, name: "aapcs-unwind" },
68     AbiData { abi: Abi::Win64 { unwind: false }, name: "win64" },
69     AbiData { abi: Abi::Win64 { unwind: true }, name: "win64-unwind" },
70     AbiData { abi: Abi::SysV64 { unwind: false }, name: "sysv64" },
71     AbiData { abi: Abi::SysV64 { unwind: true }, name: "sysv64-unwind" },
72     AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" },
73     AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" },
74     AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" },
75     AbiData { abi: Abi::AmdGpuKernel, name: "amdgpu-kernel" },
76     AbiData { abi: Abi::EfiApi, name: "efiapi" },
77     AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" },
78     AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" },
79     AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" },
80     AbiData { abi: Abi::Wasm, name: "wasm" },
81     AbiData { abi: Abi::System { unwind: false }, name: "system" },
82     AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" },
83     AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" },
84     AbiData { abi: Abi::RustCall, name: "rust-call" },
85     AbiData { abi: Abi::PlatformIntrinsic, name: "platform-intrinsic" },
86     AbiData { abi: Abi::Unadjusted, name: "unadjusted" },
87     AbiData { abi: Abi::RustCold, name: "rust-cold" },
88 ];
89
90 /// Returns the ABI with the given name (if any).
91 pub fn lookup(name: &str) -> Option<Abi> {
92     AbiDatas.iter().find(|abi_data| name == abi_data.name).map(|&x| x.abi)
93 }
94
95 pub fn all_names() -> Vec<&'static str> {
96     AbiDatas.iter().map(|d| d.name).collect()
97 }
98
99 pub fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> {
100     AbiDatas
101         .iter()
102         .map(|d| d.name)
103         .filter(|name| is_enabled(features, span, name).is_ok())
104         .collect()
105 }
106
107 pub enum AbiDisabled {
108     Unstable { feature: Symbol, explain: &'static str },
109     Unrecognized,
110 }
111
112 fn gate_feature_post(
113     features: &rustc_feature::Features,
114     feature: Symbol,
115     span: Span,
116     explain: &'static str,
117 ) -> Result<(), AbiDisabled> {
118     if !features.enabled(feature) && !span.allows_unstable(feature) {
119         Err(AbiDisabled::Unstable { feature, explain })
120     } else {
121         Ok(())
122     }
123 }
124
125 pub fn is_enabled(
126     features: &rustc_feature::Features,
127     span: Span,
128     name: &str,
129 ) -> Result<(), AbiDisabled> {
130     match name {
131         // Stable
132         "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
133         | "system" => Ok(()),
134         "rust-intrinsic" => {
135             gate_feature_post(features, sym::intrinsics, span, "intrinsics are subject to change")
136         }
137         "platform-intrinsic" => gate_feature_post(
138             features,
139             sym::platform_intrinsics,
140             span,
141             "platform intrinsics are experimental and possibly buggy",
142         ),
143         "vectorcall" => gate_feature_post(
144             features,
145             sym::abi_vectorcall,
146             span,
147             "vectorcall is experimental and subject to change",
148         ),
149         "thiscall" => gate_feature_post(
150             features,
151             sym::abi_thiscall,
152             span,
153             "thiscall is experimental and subject to change",
154         ),
155         "rust-call" => gate_feature_post(
156             features,
157             sym::unboxed_closures,
158             span,
159             "rust-call ABI is subject to change",
160         ),
161         "rust-cold" => gate_feature_post(
162             features,
163             sym::rust_cold_cc,
164             span,
165             "rust-cold is experimental and subject to change",
166         ),
167         "ptx-kernel" => gate_feature_post(
168             features,
169             sym::abi_ptx,
170             span,
171             "PTX ABIs are experimental and subject to change",
172         ),
173         "unadjusted" => gate_feature_post(
174             features,
175             sym::abi_unadjusted,
176             span,
177             "unadjusted ABI is an implementation detail and perma-unstable",
178         ),
179         "msp430-interrupt" => gate_feature_post(
180             features,
181             sym::abi_msp430_interrupt,
182             span,
183             "msp430-interrupt ABI is experimental and subject to change",
184         ),
185         "x86-interrupt" => gate_feature_post(
186             features,
187             sym::abi_x86_interrupt,
188             span,
189             "x86-interrupt ABI is experimental and subject to change",
190         ),
191         "amdgpu-kernel" => gate_feature_post(
192             features,
193             sym::abi_amdgpu_kernel,
194             span,
195             "amdgpu-kernel ABI is experimental and subject to change",
196         ),
197         "avr-interrupt" | "avr-non-blocking-interrupt" => gate_feature_post(
198             features,
199             sym::abi_avr_interrupt,
200             span,
201             "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
202         ),
203         "efiapi" => gate_feature_post(
204             features,
205             sym::abi_efiapi,
206             span,
207             "efiapi ABI is experimental and subject to change",
208         ),
209         "C-cmse-nonsecure-call" => gate_feature_post(
210             features,
211             sym::abi_c_cmse_nonsecure_call,
212             span,
213             "C-cmse-nonsecure-call ABI is experimental and subject to change",
214         ),
215         "C-unwind" => gate_feature_post(
216             features,
217             sym::c_unwind,
218             span,
219             "C-unwind ABI is experimental and subject to change",
220         ),
221         "stdcall-unwind" => gate_feature_post(
222             features,
223             sym::c_unwind,
224             span,
225             "stdcall-unwind ABI is experimental and subject to change",
226         ),
227         "system-unwind" => gate_feature_post(
228             features,
229             sym::c_unwind,
230             span,
231             "system-unwind ABI is experimental and subject to change",
232         ),
233         "thiscall-unwind" => gate_feature_post(
234             features,
235             sym::c_unwind,
236             span,
237             "thiscall-unwind ABI is experimental and subject to change",
238         ),
239         "cdecl-unwind" => gate_feature_post(
240             features,
241             sym::c_unwind,
242             span,
243             "cdecl-unwind ABI is experimental and subject to change",
244         ),
245         "fastcall-unwind" => gate_feature_post(
246             features,
247             sym::c_unwind,
248             span,
249             "fastcall-unwind ABI is experimental and subject to change",
250         ),
251         "vectorcall-unwind" => gate_feature_post(
252             features,
253             sym::c_unwind,
254             span,
255             "vectorcall-unwind ABI is experimental and subject to change",
256         ),
257         "aapcs-unwind" => gate_feature_post(
258             features,
259             sym::c_unwind,
260             span,
261             "aapcs-unwind ABI is experimental and subject to change",
262         ),
263         "win64-unwind" => gate_feature_post(
264             features,
265             sym::c_unwind,
266             span,
267             "win64-unwind ABI is experimental and subject to change",
268         ),
269         "sysv64-unwind" => gate_feature_post(
270             features,
271             sym::c_unwind,
272             span,
273             "sysv64-unwind ABI is experimental and subject to change",
274         ),
275         "wasm" => gate_feature_post(
276             features,
277             sym::wasm_abi,
278             span,
279             "wasm ABI is experimental and subject to change",
280         ),
281         _ => Err(AbiDisabled::Unrecognized),
282     }
283 }
284
285 impl Abi {
286     /// Default ABI chosen for `extern fn` declarations without an explicit ABI.
287     pub const FALLBACK: Abi = Abi::C { unwind: false };
288
289     #[inline]
290     pub fn index(self) -> usize {
291         // N.B., this ordering MUST match the AbiDatas array above.
292         // (This is ensured by the test indices_are_correct().)
293         use Abi::*;
294         let i = match self {
295             // Cross-platform ABIs
296             Rust => 0,
297             C { unwind: false } => 1,
298             C { unwind: true } => 2,
299             // Platform-specific ABIs
300             Cdecl { unwind: false } => 3,
301             Cdecl { unwind: true } => 4,
302             Stdcall { unwind: false } => 5,
303             Stdcall { unwind: true } => 6,
304             Fastcall { unwind: false } => 7,
305             Fastcall { unwind: true } => 8,
306             Vectorcall { unwind: false } => 9,
307             Vectorcall { unwind: true } => 10,
308             Thiscall { unwind: false } => 11,
309             Thiscall { unwind: true } => 12,
310             Aapcs { unwind: false } => 13,
311             Aapcs { unwind: true } => 14,
312             Win64 { unwind: false } => 15,
313             Win64 { unwind: true } => 16,
314             SysV64 { unwind: false } => 17,
315             SysV64 { unwind: true } => 18,
316             PtxKernel => 19,
317             Msp430Interrupt => 20,
318             X86Interrupt => 21,
319             AmdGpuKernel => 22,
320             EfiApi => 23,
321             AvrInterrupt => 24,
322             AvrNonBlockingInterrupt => 25,
323             CCmseNonSecureCall => 26,
324             Wasm => 27,
325             // Cross-platform ABIs
326             System { unwind: false } => 28,
327             System { unwind: true } => 29,
328             RustIntrinsic => 30,
329             RustCall => 31,
330             PlatformIntrinsic => 32,
331             Unadjusted => 33,
332             RustCold => 34,
333         };
334         debug_assert!(
335             AbiDatas
336                 .iter()
337                 .enumerate()
338                 .find(|(_, AbiData { abi, .. })| *abi == self)
339                 .map(|(index, _)| index)
340                 .expect("abi variant has associated data")
341                 == i,
342             "Abi index did not match `AbiDatas` ordering"
343         );
344         i
345     }
346
347     #[inline]
348     pub fn data(self) -> &'static AbiData {
349         &AbiDatas[self.index()]
350     }
351
352     pub fn name(self) -> &'static str {
353         self.data().name
354     }
355 }
356
357 impl fmt::Display for Abi {
358     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
359         match self {
360             abi => write!(f, "\"{}\"", abi.name()),
361         }
362     }
363 }