1
+ use std::cmp::Ordering;
1
2
use std::fmt;
3
+ use std::hash::{Hash, Hasher};
2
4
3
- use rustc_macros::{Decodable, Encodable, HashStable_Generic};
5
+ #[cfg(feature = "nightly")]
6
+ use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd};
7
+ #[cfg(feature = "nightly")]
8
+ use rustc_macros::{Decodable, Encodable};
4
9
5
10
#[cfg(test)]
6
11
mod tests;
7
12
8
13
use ExternAbi as Abi;
9
14
10
- #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
11
- #[derive(HashStable_Generic, Encodable, Decodable)]
15
+ #[derive(Clone, Copy, Debug)]
16
+ #[cfg_attr(feature = "nightly", derive( Encodable, Decodable) )]
12
17
pub enum ExternAbi {
13
18
// Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the
14
19
// hashing tests. These are used in many places, so giving them stable values reduces test
@@ -68,7 +73,124 @@ pub enum ExternAbi {
68
73
RiscvInterruptS,
69
74
}
70
75
71
- impl Abi {
76
+ macro_rules! abi_impls {
77
+ ($e_name:ident = {
78
+ $($variant:ident $({ unwind: $uw:literal })? =><= $tok:literal,)*
79
+ }) => {
80
+ impl $e_name {
81
+ pub const ALL_VARIANTS: &[Self] = &[
82
+ $($e_name::$variant $({ unwind: $uw })*,)*
83
+ ];
84
+ pub const fn as_str(&self) -> &'static str {
85
+ match self {
86
+ $($e_name::$variant $( { unwind: $uw } )* => $tok,)*
87
+ }
88
+ }
89
+ }
90
+
91
+ impl ::core::str::FromStr for $e_name {
92
+ type Err = AbiFromStrErr;
93
+ fn from_str(s: &str) -> Result<$e_name, Self::Err> {
94
+ match s {
95
+ $($tok => Ok($e_name::$variant $({ unwind: $uw })*),)*
96
+ _ => Err(AbiFromStrErr::Unknown),
97
+ }
98
+ }
99
+ }
100
+ }
101
+ }
102
+
103
+ #[derive(Debug)]
104
+ pub enum AbiFromStrErr {
105
+ Unknown,
106
+ }
107
+
108
+ abi_impls! {
109
+ ExternAbi = {
110
+ C { unwind: false } =><= "C",
111
+ CCmseNonSecureCall =><= "C-cmse-nonsecure-call",
112
+ CCmseNonSecureEntry =><= "C-cmse-nonsecure-entry",
113
+ C { unwind: true } =><= "C-unwind",
114
+ Rust =><= "Rust",
115
+ Aapcs { unwind: false } =><= "aapcs",
116
+ Aapcs { unwind: true } =><= "aapcs-unwind",
117
+ AvrInterrupt =><= "avr-interrupt",
118
+ AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
119
+ Cdecl { unwind: false } =><= "cdecl",
120
+ Cdecl { unwind: true } =><= "cdecl-unwind",
121
+ EfiApi =><= "efiapi",
122
+ Fastcall { unwind: false } =><= "fastcall",
123
+ Fastcall { unwind: true } =><= "fastcall-unwind",
124
+ GpuKernel =><= "gpu-kernel",
125
+ Msp430Interrupt =><= "msp430-interrupt",
126
+ PtxKernel =><= "ptx-kernel",
127
+ RiscvInterruptM =><= "riscv-interrupt-m",
128
+ RiscvInterruptS =><= "riscv-interrupt-s",
129
+ RustCall =><= "rust-call",
130
+ RustCold =><= "rust-cold",
131
+ RustIntrinsic =><= "rust-intrinsic",
132
+ Stdcall { unwind: false } =><= "stdcall",
133
+ Stdcall { unwind: true } =><= "stdcall-unwind",
134
+ System { unwind: false } =><= "system",
135
+ System { unwind: true } =><= "system-unwind",
136
+ SysV64 { unwind: false } =><= "sysv64",
137
+ SysV64 { unwind: true } =><= "sysv64-unwind",
138
+ Thiscall { unwind: false } =><= "thiscall",
139
+ Thiscall { unwind: true } =><= "thiscall-unwind",
140
+ Unadjusted =><= "unadjusted",
141
+ Vectorcall { unwind: false } =><= "vectorcall",
142
+ Vectorcall { unwind: true } =><= "vectorcall-unwind",
143
+ Win64 { unwind: false } =><= "win64",
144
+ Win64 { unwind: true } =><= "win64-unwind",
145
+ X86Interrupt =><= "x86-interrupt",
146
+ }
147
+ }
148
+
149
+ impl Ord for ExternAbi {
150
+ fn cmp(&self, rhs: &Self) -> Ordering {
151
+ self.as_str().cmp(rhs.as_str())
152
+ }
153
+ }
154
+
155
+ impl PartialOrd for ExternAbi {
156
+ fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
157
+ Some(self.cmp(rhs))
158
+ }
159
+ }
160
+
161
+ impl PartialEq for ExternAbi {
162
+ fn eq(&self, rhs: &Self) -> bool {
163
+ self.cmp(rhs) == Ordering::Equal
164
+ }
165
+ }
166
+
167
+ impl Eq for ExternAbi {}
168
+
169
+ impl Hash for ExternAbi {
170
+ fn hash<H: Hasher>(&self, state: &mut H) {
171
+ self.as_str().hash(state);
172
+ // double-assurance of a prefix breaker
173
+ u32::from_be_bytes(*b"ABI\0").hash(state);
174
+ }
175
+ }
176
+
177
+ #[cfg(feature = "nightly")]
178
+ impl<C> HashStable<C> for ExternAbi {
179
+ #[inline]
180
+ fn hash_stable(&self, _: &mut C, hasher: &mut StableHasher) {
181
+ Hash::hash(self, hasher);
182
+ }
183
+ }
184
+
185
+ #[cfg(feature = "nightly")]
186
+ impl StableOrd for ExternAbi {
187
+ const CAN_USE_UNSTABLE_SORT: bool = true;
188
+
189
+ // because each ABI is hashed like a string, there is no possible instability
190
+ const THIS_IMPLEMENTATION_HAS_BEEN_TRIPLE_CHECKED: () = ();
191
+ }
192
+
193
+ impl ExternAbi {
72
194
pub fn supports_varargs(self) -> bool {
73
195
// * C and Cdecl obviously support varargs.
74
196
// * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
@@ -92,144 +214,21 @@ impl Abi {
92
214
}
93
215
}
94
216
95
- #[derive(Copy, Clone)]
96
- pub struct AbiData {
97
- pub abi: Abi,
98
-
99
- /// Name of this ABI as we like it called.
100
- pub name: &'static str,
101
- }
102
-
103
- #[allow(non_upper_case_globals)]
104
- pub const AbiDatas: &[AbiData] = &[
105
- AbiData { abi: Abi::Rust, name: "Rust" },
106
- AbiData { abi: Abi::C { unwind: false }, name: "C" },
107
- AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" },
108
- AbiData { abi: Abi::Cdecl { unwind: false }, name: "cdecl" },
109
- AbiData { abi: Abi::Cdecl { unwind: true }, name: "cdecl-unwind" },
110
- AbiData { abi: Abi::Stdcall { unwind: false }, name: "stdcall" },
111
- AbiData { abi: Abi::Stdcall { unwind: true }, name: "stdcall-unwind" },
112
- AbiData { abi: Abi::Fastcall { unwind: false }, name: "fastcall" },
113
- AbiData { abi: Abi::Fastcall { unwind: true }, name: "fastcall-unwind" },
114
- AbiData { abi: Abi::Vectorcall { unwind: false }, name: "vectorcall" },
115
- AbiData { abi: Abi::Vectorcall { unwind: true }, name: "vectorcall-unwind" },
116
- AbiData { abi: Abi::Thiscall { unwind: false }, name: "thiscall" },
117
- AbiData { abi: Abi::Thiscall { unwind: true }, name: "thiscall-unwind" },
118
- AbiData { abi: Abi::Aapcs { unwind: false }, name: "aapcs" },
119
- AbiData { abi: Abi::Aapcs { unwind: true }, name: "aapcs-unwind" },
120
- AbiData { abi: Abi::Win64 { unwind: false }, name: "win64" },
121
- AbiData { abi: Abi::Win64 { unwind: true }, name: "win64-unwind" },
122
- AbiData { abi: Abi::SysV64 { unwind: false }, name: "sysv64" },
123
- AbiData { abi: Abi::SysV64 { unwind: true }, name: "sysv64-unwind" },
124
- AbiData { abi: Abi::PtxKernel, name: "ptx-kernel" },
125
- AbiData { abi: Abi::Msp430Interrupt, name: "msp430-interrupt" },
126
- AbiData { abi: Abi::X86Interrupt, name: "x86-interrupt" },
127
- AbiData { abi: Abi::GpuKernel, name: "gpu-kernel" },
128
- AbiData { abi: Abi::EfiApi, name: "efiapi" },
129
- AbiData { abi: Abi::AvrInterrupt, name: "avr-interrupt" },
130
- AbiData { abi: Abi::AvrNonBlockingInterrupt, name: "avr-non-blocking-interrupt" },
131
- AbiData { abi: Abi::CCmseNonSecureCall, name: "C-cmse-nonsecure-call" },
132
- AbiData { abi: Abi::CCmseNonSecureEntry, name: "C-cmse-nonsecure-entry" },
133
- AbiData { abi: Abi::System { unwind: false }, name: "system" },
134
- AbiData { abi: Abi::System { unwind: true }, name: "system-unwind" },
135
- AbiData { abi: Abi::RustIntrinsic, name: "rust-intrinsic" },
136
- AbiData { abi: Abi::RustCall, name: "rust-call" },
137
- AbiData { abi: Abi::Unadjusted, name: "unadjusted" },
138
- AbiData { abi: Abi::RustCold, name: "rust-cold" },
139
- AbiData { abi: Abi::RiscvInterruptM, name: "riscv-interrupt-m" },
140
- AbiData { abi: Abi::RiscvInterruptS, name: "riscv-interrupt-s" },
141
- ];
142
-
143
- #[derive(Copy, Clone, Debug)]
144
- pub struct AbiUnsupported {}
145
- /// Returns the ABI with the given name (if any).
146
- pub fn lookup(name: &str) -> Result<Abi, AbiUnsupported> {
147
- AbiDatas
148
- .iter()
149
- .find(|abi_data| name == abi_data.name)
150
- .map(|&x| x.abi)
151
- .ok_or_else(|| AbiUnsupported {})
152
- }
153
-
154
217
pub fn all_names() -> Vec<&'static str> {
155
- AbiDatas .iter().map(|d| d.name ).collect()
218
+ ExternAbi::ALL_VARIANTS .iter().map(|abi| abi.as_str() ).collect()
156
219
}
157
220
158
- impl Abi {
221
+ impl ExternAbi {
159
222
/// Default ABI chosen for `extern fn` declarations without an explicit ABI.
160
223
pub const FALLBACK: Abi = Abi::C { unwind: false };
161
224
162
- #[inline]
163
- pub fn index(self) -> usize {
164
- // N.B., this ordering MUST match the AbiDatas array above.
165
- // (This is ensured by the test indices_are_correct().)
166
- use Abi::*;
167
- let i = match self {
168
- // Cross-platform ABIs
169
- Rust => 0,
170
- C { unwind: false } => 1,
171
- C { unwind: true } => 2,
172
- // Platform-specific ABIs
173
- Cdecl { unwind: false } => 3,
174
- Cdecl { unwind: true } => 4,
175
- Stdcall { unwind: false } => 5,
176
- Stdcall { unwind: true } => 6,
177
- Fastcall { unwind: false } => 7,
178
- Fastcall { unwind: true } => 8,
179
- Vectorcall { unwind: false } => 9,
180
- Vectorcall { unwind: true } => 10,
181
- Thiscall { unwind: false } => 11,
182
- Thiscall { unwind: true } => 12,
183
- Aapcs { unwind: false } => 13,
184
- Aapcs { unwind: true } => 14,
185
- Win64 { unwind: false } => 15,
186
- Win64 { unwind: true } => 16,
187
- SysV64 { unwind: false } => 17,
188
- SysV64 { unwind: true } => 18,
189
- PtxKernel => 19,
190
- Msp430Interrupt => 20,
191
- X86Interrupt => 21,
192
- GpuKernel => 22,
193
- EfiApi => 23,
194
- AvrInterrupt => 24,
195
- AvrNonBlockingInterrupt => 25,
196
- CCmseNonSecureCall => 26,
197
- CCmseNonSecureEntry => 27,
198
- // Cross-platform ABIs
199
- System { unwind: false } => 28,
200
- System { unwind: true } => 29,
201
- RustIntrinsic => 30,
202
- RustCall => 31,
203
- Unadjusted => 32,
204
- RustCold => 33,
205
- RiscvInterruptM => 34,
206
- RiscvInterruptS => 35,
207
- };
208
- debug_assert!(
209
- AbiDatas
210
- .iter()
211
- .enumerate()
212
- .find(|(_, AbiData { abi, .. })| *abi == self)
213
- .map(|(index, _)| index)
214
- .expect("abi variant has associated data")
215
- == i,
216
- "Abi index did not match `AbiDatas` ordering"
217
- );
218
- i
219
- }
220
-
221
- #[inline]
222
- pub fn data(self) -> &'static AbiData {
223
- &AbiDatas[self.index()]
224
- }
225
-
226
225
pub fn name(self) -> &'static str {
227
- self.data().name
226
+ self.as_str()
228
227
}
229
228
}
230
229
231
- impl fmt::Display for Abi {
230
+ impl fmt::Display for ExternAbi {
232
231
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233
- write!(f, "\"{}\"", self.name ())
232
+ write!(f, "\"{}\"", self.as_str ())
234
233
}
235
234
}
0 commit comments