Skip to content
/ rust Public
forked from rust-lang/rust

Commit 3f50076

Browse files
compiler: gate extern "{abi}" in ast_lowering
By moving this stability check into AST lowering, we effectively make it impossible to accidentally miss, as it must happen to generate HIR. Also, we put the ABI-stability code next to code that actually uses it! This allows code that wants to reason about backend ABI implementations to stop worrying about high-level concerns like syntax stability, while still leaving it as the authority on what ABIs actually exist. It also makes it easy to refactor things to have more consistent errors. For now, we only apply this to generalize the existing messages a bit.
1 parent 124cc92 commit 3f50076

File tree

13 files changed

+186
-158
lines changed

13 files changed

+186
-158
lines changed

Cargo.lock

+1-1
Original file line numberDiff line numberDiff line change
@@ -3336,7 +3336,6 @@ dependencies = [
33363336
"rand 0.8.5",
33373337
"rand_xoshiro",
33383338
"rustc_data_structures",
3339-
"rustc_feature",
33403339
"rustc_index",
33413340
"rustc_macros",
33423341
"rustc_serialize",
@@ -3398,6 +3397,7 @@ dependencies = [
33983397
"rustc_ast_pretty",
33993398
"rustc_data_structures",
34003399
"rustc_errors",
3400+
"rustc_feature",
34013401
"rustc_fluent_macro",
34023402
"rustc_hir",
34033403
"rustc_index",

compiler/rustc_abi/Cargo.toml

-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ bitflags = "2.4.1"
99
rand = { version = "0.8.4", default-features = false, optional = true }
1010
rand_xoshiro = { version = "0.6.0", optional = true }
1111
rustc_data_structures = { path = "../rustc_data_structures", optional = true }
12-
rustc_feature = { path = "../rustc_feature", optional = true }
1312
rustc_index = { path = "../rustc_index", default-features = false }
1413
rustc_macros = { path = "../rustc_macros", optional = true }
1514
rustc_serialize = { path = "../rustc_serialize", optional = true }
@@ -24,7 +23,6 @@ default = ["nightly", "randomize"]
2423
# without depending on rustc_data_structures, rustc_macros and rustc_serialize
2524
nightly = [
2625
"dep:rustc_data_structures",
27-
"dep:rustc_feature",
2826
"dep:rustc_macros",
2927
"dep:rustc_serialize",
3028
"dep:rustc_span",

compiler/rustc_abi/src/callconv.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#[cfg(feature = "nightly")]
2-
use crate::{BackendRepr, FieldsShape, TyAbiInterface, TyAndLayout};
3-
use crate::{Primitive, Size, Variants};
2+
use crate::{BackendRepr, FieldsShape, Primitive, Size, TyAbiInterface, TyAndLayout, Variants};
43

54
mod reg;
65

compiler/rustc_abi/src/extern_abi.rs

+3-102
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::fmt;
22

33
use rustc_macros::{Decodable, Encodable, HashStable_Generic};
4-
use rustc_span::{Span, Symbol, sym};
54

65
#[cfg(test)]
76
mod tests;
@@ -95,14 +94,14 @@ impl Abi {
9594

9695
#[derive(Copy, Clone)]
9796
pub struct AbiData {
98-
abi: Abi,
97+
pub abi: Abi,
9998

10099
/// Name of this ABI as we like it called.
101-
name: &'static str,
100+
pub name: &'static str,
102101
}
103102

104103
#[allow(non_upper_case_globals)]
105-
const AbiDatas: &[AbiData] = &[
104+
pub const AbiDatas: &[AbiData] = &[
106105
AbiData { abi: Abi::Rust, name: "Rust" },
107106
AbiData { abi: Abi::C { unwind: false }, name: "C" },
108107
AbiData { abi: Abi::C { unwind: true }, name: "C-unwind" },
@@ -169,104 +168,6 @@ pub fn all_names() -> Vec<&'static str> {
169168
AbiDatas.iter().map(|d| d.name).collect()
170169
}
171170

172-
pub fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> {
173-
AbiDatas
174-
.iter()
175-
.map(|d| d.name)
176-
.filter(|name| is_enabled(features, span, name).is_ok())
177-
.collect()
178-
}
179-
180-
pub enum AbiDisabled {
181-
Unstable { feature: Symbol, explain: &'static str },
182-
Unrecognized,
183-
}
184-
185-
pub fn is_enabled(
186-
features: &rustc_feature::Features,
187-
span: Span,
188-
name: &str,
189-
) -> Result<(), AbiDisabled> {
190-
let s = is_stable(name);
191-
if let Err(AbiDisabled::Unstable { feature, .. }) = s {
192-
if features.enabled(feature) || span.allows_unstable(feature) {
193-
return Ok(());
194-
}
195-
}
196-
s
197-
}
198-
199-
/// Returns whether the ABI is stable to use.
200-
///
201-
/// Note that there is a separate check determining whether the ABI is even supported
202-
/// on the current target; see `fn is_abi_supported` in `rustc_target::spec`.
203-
pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
204-
match name {
205-
// Stable
206-
"Rust" | "C" | "C-unwind" | "cdecl" | "cdecl-unwind" | "stdcall" | "stdcall-unwind"
207-
| "fastcall" | "fastcall-unwind" | "aapcs" | "aapcs-unwind" | "win64" | "win64-unwind"
208-
| "sysv64" | "sysv64-unwind" | "system" | "system-unwind" | "efiapi" | "thiscall"
209-
| "thiscall-unwind" => Ok(()),
210-
"rust-intrinsic" => Err(AbiDisabled::Unstable {
211-
feature: sym::intrinsics,
212-
explain: "intrinsics are subject to change",
213-
}),
214-
"vectorcall" => Err(AbiDisabled::Unstable {
215-
feature: sym::abi_vectorcall,
216-
explain: "vectorcall is experimental and subject to change",
217-
}),
218-
"vectorcall-unwind" => Err(AbiDisabled::Unstable {
219-
feature: sym::abi_vectorcall,
220-
explain: "vectorcall-unwind ABI is experimental and subject to change",
221-
}),
222-
"rust-call" => Err(AbiDisabled::Unstable {
223-
feature: sym::unboxed_closures,
224-
explain: "rust-call ABI is subject to change",
225-
}),
226-
"rust-cold" => Err(AbiDisabled::Unstable {
227-
feature: sym::rust_cold_cc,
228-
explain: "rust-cold is experimental and subject to change",
229-
}),
230-
"ptx-kernel" => Err(AbiDisabled::Unstable {
231-
feature: sym::abi_ptx,
232-
explain: "PTX ABIs are experimental and subject to change",
233-
}),
234-
"unadjusted" => Err(AbiDisabled::Unstable {
235-
feature: sym::abi_unadjusted,
236-
explain: "unadjusted ABI is an implementation detail and perma-unstable",
237-
}),
238-
"msp430-interrupt" => Err(AbiDisabled::Unstable {
239-
feature: sym::abi_msp430_interrupt,
240-
explain: "msp430-interrupt ABI is experimental and subject to change",
241-
}),
242-
"x86-interrupt" => Err(AbiDisabled::Unstable {
243-
feature: sym::abi_x86_interrupt,
244-
explain: "x86-interrupt ABI is experimental and subject to change",
245-
}),
246-
"gpu-kernel" => Err(AbiDisabled::Unstable {
247-
feature: sym::abi_gpu_kernel,
248-
explain: "gpu-kernel ABI is experimental and subject to change",
249-
}),
250-
"avr-interrupt" | "avr-non-blocking-interrupt" => Err(AbiDisabled::Unstable {
251-
feature: sym::abi_avr_interrupt,
252-
explain: "avr-interrupt and avr-non-blocking-interrupt ABIs are experimental and subject to change",
253-
}),
254-
"riscv-interrupt-m" | "riscv-interrupt-s" => Err(AbiDisabled::Unstable {
255-
feature: sym::abi_riscv_interrupt,
256-
explain: "riscv-interrupt ABIs are experimental and subject to change",
257-
}),
258-
"C-cmse-nonsecure-call" => Err(AbiDisabled::Unstable {
259-
feature: sym::abi_c_cmse_nonsecure_call,
260-
explain: "C-cmse-nonsecure-call ABI is experimental and subject to change",
261-
}),
262-
"C-cmse-nonsecure-entry" => Err(AbiDisabled::Unstable {
263-
feature: sym::cmse_nonsecure_entry,
264-
explain: "C-cmse-nonsecure-entry ABI is experimental and subject to change",
265-
}),
266-
_ => Err(AbiDisabled::Unrecognized),
267-
}
268-
}
269-
270171
impl Abi {
271172
/// Default ABI chosen for `extern fn` declarations without an explicit ABI.
272173
pub const FALLBACK: Abi = Abi::C { unwind: false };

compiler/rustc_abi/src/lib.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,7 @@ mod extern_abi;
6666

6767
pub use callconv::{Heterogeneous, HomogeneousAggregate, Reg, RegKind};
6868
#[cfg(feature = "nightly")]
69-
pub use extern_abi::{
70-
AbiDisabled, AbiUnsupported, ExternAbi, all_names, enabled_names, is_enabled, is_stable, lookup,
71-
};
69+
pub use extern_abi::{AbiDatas, AbiUnsupported, ExternAbi, all_names, lookup};
7270
#[cfg(feature = "nightly")]
7371
pub use layout::{FIRST_VARIANT, FieldIdx, Layout, TyAbiInterface, TyAndLayout, VariantIdx};
7472
pub use layout::{LayoutCalculator, LayoutCalculatorError};

compiler/rustc_ast_lowering/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ rustc_ast = { path = "../rustc_ast" }
1313
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
1414
rustc_data_structures = { path = "../rustc_data_structures" }
1515
rustc_errors = { path = "../rustc_errors" }
16+
rustc_feature = { path = "../rustc_feature" }
1617
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
1718
rustc_hir = { path = "../rustc_hir" }
1819
rustc_index = { path = "../rustc_index" }

compiler/rustc_ast_lowering/src/item.rs

+11-5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use super::errors::{
2020
InvalidAbi, InvalidAbiReason, InvalidAbiSuggestion, MisplacedRelaxTraitBound,
2121
TupleStructWithDefault,
2222
};
23+
use super::stability::{enabled_names, gate_unstable_abi};
2324
use super::{
2425
AstOwner, FnDeclKind, ImplTraitContext, ImplTraitPosition, LoweringContext, ParamMode,
2526
ResolverAstLoweringExt,
@@ -1479,11 +1480,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
14791480
}
14801481
}
14811482

1482-
pub(super) fn lower_abi(&mut self, abi: StrLit) -> ExternAbi {
1483-
rustc_abi::lookup(abi.symbol_unescaped.as_str()).unwrap_or_else(|err| {
1484-
self.error_on_invalid_abi(abi, err);
1483+
pub(super) fn lower_abi(&mut self, abi_str: StrLit) -> ExternAbi {
1484+
let ast::StrLit { symbol_unescaped, span, .. } = abi_str;
1485+
let extern_abi = rustc_abi::lookup(symbol_unescaped.as_str()).unwrap_or_else(|err| {
1486+
self.error_on_invalid_abi(abi_str, err);
14851487
ExternAbi::Rust
1486-
})
1488+
});
1489+
let sess = self.tcx.sess;
1490+
let features = self.tcx.features();
1491+
gate_unstable_abi(sess, features, span, extern_abi);
1492+
extern_abi
14871493
}
14881494

14891495
pub(super) fn lower_extern(&mut self, ext: Extern) -> ExternAbi {
@@ -1495,7 +1501,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
14951501
}
14961502

14971503
fn error_on_invalid_abi(&self, abi: StrLit, err: rustc_abi::AbiUnsupported) {
1498-
let abi_names = rustc_abi::enabled_names(self.tcx.features(), abi.span)
1504+
let abi_names = enabled_names(self.tcx.features(), abi.span)
14991505
.iter()
15001506
.map(|s| Symbol::intern(s))
15011507
.collect::<Vec<_>>();

compiler/rustc_ast_lowering/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ mod index;
8484
mod item;
8585
mod pat;
8686
mod path;
87+
mod stability;
8788

8889
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
8990

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
use std::fmt;
2+
3+
use rustc_abi::ExternAbi;
4+
use rustc_feature::Features;
5+
use rustc_session::Session;
6+
use rustc_session::parse::feature_err;
7+
use rustc_span::symbol::sym;
8+
use rustc_span::{Span, Symbol};
9+
10+
pub(crate) fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> {
11+
rustc_abi::AbiDatas
12+
.iter()
13+
.filter(|data| extern_abi_enabled(features, span, data.abi).is_ok())
14+
.map(|d| d.name)
15+
.collect()
16+
}
17+
18+
pub(crate) fn extern_abi_enabled(
19+
features: &rustc_feature::Features,
20+
span: Span,
21+
abi: ExternAbi,
22+
) -> Result<(), UnstableAbi> {
23+
extern_abi_stability(abi).or_else(|unstable @ UnstableAbi { feature, .. }| {
24+
if features.enabled(feature) || span.allows_unstable(feature) {
25+
Ok(())
26+
} else {
27+
Err(unstable)
28+
}
29+
})
30+
}
31+
32+
#[allow(rustc::untranslatable_diagnostic)]
33+
pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) {
34+
match extern_abi_enabled(features, span, abi) {
35+
Ok(_) => (),
36+
Err(unstable_abi) => {
37+
let explain = unstable_abi.to_string();
38+
feature_err(sess, unstable_abi.feature, span, explain).emit();
39+
}
40+
}
41+
}
42+
43+
pub(crate) struct UnstableAbi {
44+
abi: ExternAbi,
45+
feature: Symbol,
46+
explain: GateReason,
47+
}
48+
49+
enum GateReason {
50+
Experimental,
51+
ImplDetail,
52+
}
53+
54+
impl fmt::Display for UnstableAbi {
55+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56+
let Self { abi, .. } = self;
57+
let name = abi.to_string();
58+
let name = name.trim_matches('"');
59+
match self.explain {
60+
GateReason::Experimental => {
61+
write!(f, r#"the extern "{name}" ABI is experimental and subject to change"#)
62+
}
63+
GateReason::ImplDetail => {
64+
write!(
65+
f,
66+
r#"the extern "{name}" ABI is an implementation detail and perma-unstable"#
67+
)
68+
}
69+
}
70+
}
71+
}
72+
73+
pub(crate) fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
74+
match abi {
75+
// stable ABIs
76+
ExternAbi::Rust
77+
| ExternAbi::C { .. }
78+
| ExternAbi::Cdecl { .. }
79+
| ExternAbi::Stdcall { .. }
80+
| ExternAbi::Fastcall { .. }
81+
| ExternAbi::Thiscall { .. }
82+
| ExternAbi::Aapcs { .. }
83+
| ExternAbi::Win64 { .. }
84+
| ExternAbi::SysV64 { .. }
85+
| ExternAbi::System { .. }
86+
| ExternAbi::EfiApi => Ok(()),
87+
// implementation details
88+
ExternAbi::RustIntrinsic => {
89+
Err(UnstableAbi { abi, feature: sym::intrinsics, explain: GateReason::ImplDetail })
90+
}
91+
ExternAbi::Unadjusted => {
92+
Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail })
93+
}
94+
// experimental
95+
ExternAbi::Vectorcall { .. } => Err(UnstableAbi {
96+
abi,
97+
feature: sym::abi_vectorcall,
98+
explain: GateReason::Experimental,
99+
}),
100+
ExternAbi::RustCall => Err(UnstableAbi {
101+
abi,
102+
feature: sym::unboxed_closures,
103+
explain: GateReason::Experimental,
104+
}),
105+
ExternAbi::RustCold => {
106+
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
107+
}
108+
ExternAbi::GpuKernel => Err(UnstableAbi {
109+
abi,
110+
feature: sym::abi_gpu_kernel,
111+
explain: GateReason::Experimental,
112+
}),
113+
ExternAbi::PtxKernel => {
114+
Err(UnstableAbi { abi, feature: sym::abi_ptx, explain: GateReason::Experimental })
115+
}
116+
ExternAbi::Msp430Interrupt => Err(UnstableAbi {
117+
abi,
118+
feature: sym::abi_msp430_interrupt,
119+
explain: GateReason::Experimental,
120+
}),
121+
ExternAbi::X86Interrupt => Err(UnstableAbi {
122+
abi,
123+
feature: sym::abi_x86_interrupt,
124+
explain: GateReason::Experimental,
125+
}),
126+
ExternAbi::AvrInterrupt | ExternAbi::AvrNonBlockingInterrupt => Err(UnstableAbi {
127+
abi,
128+
feature: sym::abi_avr_interrupt,
129+
explain: GateReason::Experimental,
130+
}),
131+
ExternAbi::RiscvInterruptM | ExternAbi::RiscvInterruptS => Err(UnstableAbi {
132+
abi,
133+
feature: sym::abi_riscv_interrupt,
134+
explain: GateReason::Experimental,
135+
}),
136+
ExternAbi::CCmseNonSecureCall => Err(UnstableAbi {
137+
abi,
138+
feature: sym::abi_c_cmse_nonsecure_call,
139+
explain: GateReason::Experimental,
140+
}),
141+
ExternAbi::CCmseNonSecureEntry => Err(UnstableAbi {
142+
abi,
143+
feature: sym::cmse_nonsecure_entry,
144+
explain: GateReason::Experimental,
145+
}),
146+
}
147+
}

0 commit comments

Comments
 (0)