Skip to content

Commit 8abff35

Browse files
compiler: compare and hash ExternAbi like its string
Directly map each ExternAbi variant to its string and back again. This has a few advantages: - By making the ABIs compare equal to their strings, we can easily lexicographically sort them and use that sorted slice at runtime. - We no longer need a workaround to make sure the hashes remain stable, as they already naturally are (by being the hashes of unique strings). - The compiler can carry around less &str wide pointers
1 parent 038c183 commit 8abff35

File tree

6 files changed

+144
-25
lines changed

6 files changed

+144
-25
lines changed

compiler/rustc_abi/src/extern_abi.rs

+129-12
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
1+
use std::cmp::Ordering;
12
use std::fmt;
3+
use std::hash::{Hash, Hasher};
4+
use std::str::FromStr;
25

36
#[cfg(feature = "nightly")]
4-
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
7+
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableOrd};
8+
#[cfg(feature = "nightly")]
9+
use rustc_macros::{Decodable, Encodable};
510

611
#[cfg(test)]
712
mod tests;
813

914
use ExternAbi as Abi;
1015

11-
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug)]
12-
#[cfg_attr(feature = "nightly", derive(HashStable_Generic, Encodable, Decodable))]
16+
#[derive(Clone, Copy, Debug)]
17+
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable))]
1318
pub enum ExternAbi {
1419
// Some of the ABIs come first because every time we add a new ABI, we have to re-bless all the
1520
// hashing tests. These are used in many places, so giving them stable values reduces test
@@ -69,7 +74,123 @@ pub enum ExternAbi {
6974
RiscvInterruptS,
7075
}
7176

72-
impl Abi {
77+
macro_rules! abi_impls {
78+
($e_name:ident = {
79+
$($variant:ident $({ unwind: $uw:literal })? =><= $tok:literal,)*
80+
}) => {
81+
impl $e_name {
82+
pub const ALL_VARIANTS: &[Self] = &[
83+
$($e_name::$variant $({ unwind: $uw })*,)*
84+
];
85+
pub const fn as_str(&self) -> &'static str {
86+
match self {
87+
$($e_name::$variant $( { unwind: $uw } )* => $tok,)*
88+
}
89+
}
90+
}
91+
92+
impl ::core::str::FromStr for $e_name {
93+
type Err = AbiFromStrErr;
94+
fn from_str(s: &str) -> Result<$e_name, Self::Err> {
95+
match s {
96+
$($tok => Ok($e_name::$variant $({ unwind: $uw })*),)*
97+
_ => Err(AbiFromStrErr::Unknown),
98+
}
99+
}
100+
}
101+
}
102+
}
103+
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 {
73194
pub fn supports_varargs(self) -> bool {
74195
// * C and Cdecl obviously support varargs.
75196
// * C can be based on Aapcs, SysV64 or Win64, so they must support varargs.
@@ -145,15 +266,11 @@ pub const AbiDatas: &[AbiData] = &[
145266
pub struct AbiUnsupported {}
146267
/// Returns the ABI with the given name (if any).
147268
pub fn lookup(name: &str) -> Result<Abi, AbiUnsupported> {
148-
AbiDatas
149-
.iter()
150-
.find(|abi_data| name == abi_data.name)
151-
.map(|&x| x.abi)
152-
.ok_or_else(|| AbiUnsupported {})
269+
ExternAbi::from_str(name).map_err(|_| AbiUnsupported {})
153270
}
154271

155272
pub fn all_names() -> Vec<&'static str> {
156-
AbiDatas.iter().map(|d| d.name).collect()
273+
ExternAbi::ALL_VARIANTS.iter().map(|abi| abi.as_str()).collect()
157274
}
158275

159276
impl Abi {
@@ -229,8 +346,8 @@ impl Abi {
229346
}
230347
}
231348

232-
impl fmt::Display for Abi {
349+
impl fmt::Display for ExternAbi {
233350
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234-
write!(f, "\"{}\"", self.name())
351+
write!(f, "\"{}\"", self.as_str())
235352
}
236353
}

compiler/rustc_abi/src/extern_abi/tests.rs

+8
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,11 @@ fn indices_are_correct() {
2727
assert_eq!(i, abi_data.abi.index());
2828
}
2929
}
30+
31+
#[test]
32+
fn guarantee_lexicographic_ordering() {
33+
let abis = ExternAbi::ALL_VARIANTS;
34+
let mut sorted_abis = abis.to_vec();
35+
sorted_abis.sort_unstable();
36+
assert_eq!(abis, sorted_abis);
37+
}

compiler/rustc_ast_lowering/src/stability.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,12 @@ enum GateReason {
5454
impl fmt::Display for UnstableAbi {
5555
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5656
let Self { abi, .. } = self;
57-
let name = abi.to_string();
58-
let name = name.trim_matches('"');
5957
match self.explain {
6058
GateReason::Experimental => {
61-
write!(f, r#"the extern "{name}" ABI is experimental and subject to change"#)
59+
write!(f, "the extern {abi} ABI is experimental and subject to change")
6260
}
6361
GateReason::ImplDetail => {
64-
write!(
65-
f,
66-
r#"the extern "{name}" ABI is an implementation detail and perma-unstable"#
67-
)
62+
write!(f, "the extern {abi} ABI is an implementation detail and perma-unstable")
6863
}
6964
}
7065
}

compiler/rustc_driver_impl/src/lib.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -747,8 +747,7 @@ fn print_crate_info(
747747
}
748748
}
749749
CallingConventions => {
750-
let mut calling_conventions = rustc_abi::all_names();
751-
calling_conventions.sort_unstable();
750+
let calling_conventions = rustc_abi::all_names();
752751
println_info!("{}", calling_conventions.join("\n"));
753752
}
754753
RelocationModels

tests/ui/symbol-names/basic.legacy.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: symbol-name(_ZN5basic4main17h144191e1523a280eE)
1+
error: symbol-name(_ZN5basic4main17hc88b9d80a69d119aE)
22
--> $DIR/basic.rs:8:1
33
|
44
LL | #[rustc_symbol_name]
55
| ^^^^^^^^^^^^^^^^^^^^
66

7-
error: demangling(basic::main::h144191e1523a280e)
7+
error: demangling(basic::main::hc88b9d80a69d119a)
88
--> $DIR/basic.rs:8:1
99
|
1010
LL | #[rustc_symbol_name]

tests/ui/symbol-names/issue-60925.legacy.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
1-
error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h71f988fda3b6b180E)
1+
error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17hbddb77d6f71afb32E)
22
--> $DIR/issue-60925.rs:21:9
33
|
44
LL | #[rustc_symbol_name]
55
| ^^^^^^^^^^^^^^^^^^^^
66

7-
error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h71f988fda3b6b180)
7+
error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::hbddb77d6f71afb32)
88
--> $DIR/issue-60925.rs:21:9
99
|
1010
LL | #[rustc_symbol_name]

0 commit comments

Comments
 (0)