| use std::fmt; | |
| use rustc_abi::ExternAbi; | |
| use rustc_feature::Features; | |
| use rustc_session::Session; | |
| use rustc_session::parse::feature_err; | |
| use rustc_span::symbol::sym; | |
| use rustc_span::{Span, Symbol}; | |
| pub(crate) fn enabled_names(features: &rustc_feature::Features, span: Span) -> Vec<&'static str> { | |
| ExternAbi::ALL_VARIANTS | |
| .into_iter() | |
| .filter(|abi| extern_abi_enabled(features, span, **abi).is_ok()) | |
| .map(|abi| abi.as_str()) | |
| .collect() | |
| } | |
| pub(crate) fn extern_abi_enabled( | |
| features: &rustc_feature::Features, | |
| span: Span, | |
| abi: ExternAbi, | |
| ) -> Result<(), UnstableAbi> { | |
| extern_abi_stability(abi).or_else(|unstable @ UnstableAbi { feature, .. }| { | |
| if features.enabled(feature) || span.allows_unstable(feature) { | |
| Ok(()) | |
| } else { | |
| Err(unstable) | |
| } | |
| }) | |
| } | |
| pub(crate) fn gate_unstable_abi(sess: &Session, features: &Features, span: Span, abi: ExternAbi) { | |
| match extern_abi_enabled(features, span, abi) { | |
| Ok(_) => (), | |
| Err(unstable_abi) => { | |
| let explain = unstable_abi.to_string(); | |
| feature_err(sess, unstable_abi.feature, span, explain).emit(); | |
| } | |
| } | |
| } | |
| pub struct UnstableAbi { | |
| abi: ExternAbi, | |
| feature: Symbol, | |
| explain: GateReason, | |
| } | |
| enum GateReason { | |
| Experimental, | |
| ImplDetail, | |
| } | |
| impl fmt::Display for UnstableAbi { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| let Self { abi, .. } = self; | |
| match self.explain { | |
| GateReason::Experimental => { | |
| write!(f, "the extern {abi} ABI is experimental and subject to change") | |
| } | |
| GateReason::ImplDetail => { | |
| write!(f, "the extern {abi} ABI is an implementation detail and perma-unstable") | |
| } | |
| } | |
| } | |
| } | |
| pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> { | |
| match abi { | |
| // stable ABIs | |
| ExternAbi::Rust | |
| | ExternAbi::C { .. } | |
| | ExternAbi::Cdecl { .. } | |
| | ExternAbi::Stdcall { .. } | |
| | ExternAbi::Fastcall { .. } | |
| | ExternAbi::Thiscall { .. } | |
| | ExternAbi::Aapcs { .. } | |
| | ExternAbi::Win64 { .. } | |
| | ExternAbi::SysV64 { .. } | |
| | ExternAbi::System { .. } | |
| | ExternAbi::EfiApi => Ok(()), | |
| ExternAbi::Unadjusted => { | |
| Err(UnstableAbi { abi, feature: sym::abi_unadjusted, explain: GateReason::ImplDetail }) | |
| } | |
| // experimental | |
| ExternAbi::Vectorcall { .. } => Err(UnstableAbi { | |
| abi, | |
| feature: sym::abi_vectorcall, | |
| explain: GateReason::Experimental, | |
| }), | |
| ExternAbi::RustCall => Err(UnstableAbi { | |
| abi, | |
| feature: sym::unboxed_closures, | |
| explain: GateReason::Experimental, | |
| }), | |
| ExternAbi::RustCold => { | |
| Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental }) | |
| } | |
| ExternAbi::RustPreserveNone => Err(UnstableAbi { | |
| abi, | |
| feature: sym::rust_preserve_none_cc, | |
| explain: GateReason::Experimental, | |
| }), | |
| ExternAbi::RustInvalid => { | |
| Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail }) | |
| } | |
| ExternAbi::GpuKernel => Err(UnstableAbi { | |
| abi, | |
| feature: sym::abi_gpu_kernel, | |
| explain: GateReason::Experimental, | |
| }), | |
| ExternAbi::PtxKernel => { | |
| Err(UnstableAbi { abi, feature: sym::abi_ptx, explain: GateReason::Experimental }) | |
| } | |
| ExternAbi::Msp430Interrupt => Err(UnstableAbi { | |
| abi, | |
| feature: sym::abi_msp430_interrupt, | |
| explain: GateReason::Experimental, | |
| }), | |
| ExternAbi::X86Interrupt => Err(UnstableAbi { | |
| abi, | |
| feature: sym::abi_x86_interrupt, | |
| explain: GateReason::Experimental, | |
| }), | |
| ExternAbi::AvrInterrupt | ExternAbi::AvrNonBlockingInterrupt => Err(UnstableAbi { | |
| abi, | |
| feature: sym::abi_avr_interrupt, | |
| explain: GateReason::Experimental, | |
| }), | |
| ExternAbi::RiscvInterruptM | ExternAbi::RiscvInterruptS => Err(UnstableAbi { | |
| abi, | |
| feature: sym::abi_riscv_interrupt, | |
| explain: GateReason::Experimental, | |
| }), | |
| ExternAbi::CmseNonSecureCall => Err(UnstableAbi { | |
| abi, | |
| feature: sym::abi_cmse_nonsecure_call, | |
| explain: GateReason::Experimental, | |
| }), | |
| ExternAbi::CmseNonSecureEntry => Err(UnstableAbi { | |
| abi, | |
| feature: sym::cmse_nonsecure_entry, | |
| explain: GateReason::Experimental, | |
| }), | |
| ExternAbi::Custom => { | |
| Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental }) | |
| } | |
| } | |
| } |