1+ use std:: cmp:: Ordering ;
12use std:: fmt;
3+ use std:: hash:: { Hash , Hasher } ;
24
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 } ;
49
510#[ cfg( test) ]
611mod tests;
712
813use ExternAbi as Abi ;
914
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 ) ) ]
1217pub enum ExternAbi {
1318 // Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the
1419 // hashing tests. These are used in many places, so giving them stable values reduces test
@@ -68,7 +73,124 @@ pub enum ExternAbi {
6873 RiscvInterruptS ,
6974}
7075
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 {
72194 pub fn supports_varargs ( self ) -> bool {
73195 // * C and Cdecl obviously support varargs.
74196 // * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
@@ -92,144 +214,21 @@ impl Abi {
92214 }
93215}
94216
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-
154217pub 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 ( )
156219}
157220
158- impl Abi {
221+ impl ExternAbi {
159222 /// Default ABI chosen for `extern fn` declarations without an explicit ABI.
160223 pub const FALLBACK : Abi = Abi :: C { unwind : false } ;
161224
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-
226225 pub fn name ( self ) -> & ' static str {
227- self . data ( ) . name
226+ self . as_str ( )
228227 }
229228}
230229
231- impl fmt:: Display for Abi {
230+ impl fmt:: Display for ExternAbi {
232231 fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
233- write ! ( f, "\" {}\" " , self . name ( ) )
232+ write ! ( f, "\" {}\" " , self . as_str ( ) )
234233 }
235234}
0 commit comments