rustc_ast_lowering/
stability.rs

1use std::fmt;
2
3use rustc_abi::ExternAbi;
4use rustc_feature::Features;
5use rustc_session::Session;
6use rustc_session::parse::feature_err;
7use rustc_span::symbol::sym;
8use rustc_span::{Span, Symbol};
9
10pub(crate) fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> {
11    ExternAbi::ALL_VARIANTS
12        .into_iter()
13        .filter(|abi| extern_abi_enabled(features, span, **abi).is_ok())
14        .map(|abi| abi.as_str())
15        .collect()
16}
17
18pub(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)]
33pub(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
43pub struct UnstableAbi {
44    abi: ExternAbi,
45    feature: Symbol,
46    explain: GateReason,
47}
48
49enum GateReason {
50    Experimental,
51    ImplDetail,
52}
53
54impl fmt::Display for UnstableAbi {
55    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56        let Self { abi, .. } = self;
57        match self.explain {
58            GateReason::Experimental => {
59                write!(f, "the extern {abi} ABI is experimental and subject to change")
60            }
61            GateReason::ImplDetail => {
62                write!(f, "the extern {abi} ABI is an implementation detail and perma-unstable")
63            }
64        }
65    }
66}
67
68pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
69    match abi {
70        // stable ABIs
71        ExternAbi::Rust
72        | ExternAbi::C { .. }
73        | ExternAbi::Cdecl { .. }
74        | ExternAbi::Stdcall { .. }
75        | ExternAbi::Fastcall { .. }
76        | ExternAbi::Thiscall { .. }
77        | ExternAbi::Aapcs { .. }
78        | ExternAbi::Win64 { .. }
79        | ExternAbi::SysV64 { .. }
80        | ExternAbi::System { .. }
81        | ExternAbi::EfiApi => Ok(()),
82        // implementation details
83        ExternAbi::RustIntrinsic => {
84            Err(UnstableAbi { abi, feature: sym::intrinsics, explain: GateReason::ImplDetail })
85        }
86        ExternAbi::Unadjusted => {
87            Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail })
88        }
89        // experimental
90        ExternAbi::Vectorcall { .. } => Err(UnstableAbi {
91            abi,
92            feature: sym::abi_vectorcall,
93            explain: GateReason::Experimental,
94        }),
95        ExternAbi::RustCall => Err(UnstableAbi {
96            abi,
97            feature: sym::unboxed_closures,
98            explain: GateReason::Experimental,
99        }),
100        ExternAbi::RustCold => {
101            Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
102        }
103        ExternAbi::GpuKernel => Err(UnstableAbi {
104            abi,
105            feature: sym::abi_gpu_kernel,
106            explain: GateReason::Experimental,
107        }),
108        ExternAbi::PtxKernel => {
109            Err(UnstableAbi { abi, feature: sym::abi_ptx, explain: GateReason::Experimental })
110        }
111        ExternAbi::Msp430Interrupt => Err(UnstableAbi {
112            abi,
113            feature: sym::abi_msp430_interrupt,
114            explain: GateReason::Experimental,
115        }),
116        ExternAbi::X86Interrupt => Err(UnstableAbi {
117            abi,
118            feature: sym::abi_x86_interrupt,
119            explain: GateReason::Experimental,
120        }),
121        ExternAbi::AvrInterrupt | ExternAbi::AvrNonBlockingInterrupt => Err(UnstableAbi {
122            abi,
123            feature: sym::abi_avr_interrupt,
124            explain: GateReason::Experimental,
125        }),
126        ExternAbi::RiscvInterruptM | ExternAbi::RiscvInterruptS => Err(UnstableAbi {
127            abi,
128            feature: sym::abi_riscv_interrupt,
129            explain: GateReason::Experimental,
130        }),
131        ExternAbi::CCmseNonSecureCall => Err(UnstableAbi {
132            abi,
133            feature: sym::abi_c_cmse_nonsecure_call,
134            explain: GateReason::Experimental,
135        }),
136        ExternAbi::CCmseNonSecureEntry => Err(UnstableAbi {
137            abi,
138            feature: sym::cmse_nonsecure_entry,
139            explain: GateReason::Experimental,
140        }),
141    }
142}