add extern "custom" functions
This commit is contained in:
parent
0a39445252
commit
5f73ce2b7e
34 changed files with 988 additions and 10 deletions
|
|
@ -28,6 +28,9 @@ pub enum CanonAbi {
|
|||
Rust,
|
||||
RustCold,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define.
|
||||
Custom,
|
||||
|
||||
/// ABIs relevant to 32-bit Arm targets
|
||||
Arm(ArmCall),
|
||||
/// ABI relevant to GPUs: the entry point for a GPU kernel
|
||||
|
|
@ -57,6 +60,7 @@ impl fmt::Display for CanonAbi {
|
|||
CanonAbi::C => ExternAbi::C { unwind: false },
|
||||
CanonAbi::Rust => ExternAbi::Rust,
|
||||
CanonAbi::RustCold => ExternAbi::RustCold,
|
||||
CanonAbi::Custom => ExternAbi::Custom,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
|
||||
ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ pub enum ExternAbi {
|
|||
/// Even normally-compatible Rust types can become ABI-incompatible with this ABI!
|
||||
Unadjusted,
|
||||
|
||||
/// An ABI that rustc does not know how to call or define. Functions with this ABI can
|
||||
/// only be created using `#[naked]` functions or `extern "custom"` blocks, and can only
|
||||
/// be called from inline assembly.
|
||||
Custom,
|
||||
|
||||
/// UEFI ABI, usually an alias of C, but sometimes an arch-specific alias
|
||||
/// and only valid on platforms that have a UEFI standard
|
||||
EfiApi,
|
||||
|
|
@ -141,6 +146,7 @@ abi_impls! {
|
|||
AvrNonBlockingInterrupt =><= "avr-non-blocking-interrupt",
|
||||
Cdecl { unwind: false } =><= "cdecl",
|
||||
Cdecl { unwind: true } =><= "cdecl-unwind",
|
||||
Custom =><= "custom",
|
||||
EfiApi =><= "efiapi",
|
||||
Fastcall { unwind: false } =><= "fastcall",
|
||||
Fastcall { unwind: true } =><= "fastcall-unwind",
|
||||
|
|
|
|||
|
|
@ -3520,6 +3520,38 @@ impl FnHeader {
|
|||
|| matches!(constness, Const::Yes(_))
|
||||
|| !matches!(ext, Extern::None)
|
||||
}
|
||||
|
||||
/// Return a span encompassing the header, or none if all options are default.
|
||||
pub fn span(&self) -> Option<Span> {
|
||||
fn append(a: &mut Option<Span>, b: Span) {
|
||||
*a = match a {
|
||||
None => Some(b),
|
||||
Some(x) => Some(x.to(b)),
|
||||
}
|
||||
}
|
||||
|
||||
let mut full_span = None;
|
||||
|
||||
match self.safety {
|
||||
Safety::Unsafe(span) | Safety::Safe(span) => append(&mut full_span, span),
|
||||
Safety::Default => {}
|
||||
};
|
||||
|
||||
if let Some(coroutine_kind) = self.coroutine_kind {
|
||||
append(&mut full_span, coroutine_kind.span());
|
||||
}
|
||||
|
||||
if let Const::Yes(span) = self.constness {
|
||||
append(&mut full_span, span);
|
||||
}
|
||||
|
||||
match self.ext {
|
||||
Extern::Implicit(span) | Extern::Explicit(_, span) => append(&mut full_span, span),
|
||||
Extern::None => {}
|
||||
}
|
||||
|
||||
full_span
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for FnHeader {
|
||||
|
|
|
|||
|
|
@ -134,5 +134,8 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
|
|||
feature: sym::cmse_nonsecure_entry,
|
||||
explain: GateReason::Experimental,
|
||||
}),
|
||||
ExternAbi::Custom => {
|
||||
Err(UnstableAbi { abi, feature: sym::abi_custom, explain: GateReason::Experimental })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,20 @@
|
|||
ast_passes_abi_custom_coroutine =
|
||||
functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}`
|
||||
.suggestion = remove the `{$coroutine_kind_str}` keyword from this definiton
|
||||
|
||||
ast_passes_abi_custom_invalid_signature =
|
||||
invalid signature for `extern "custom"` function
|
||||
.note = functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
.suggestion = remove the parameters and return type
|
||||
|
||||
ast_passes_abi_custom_safe_foreign_function =
|
||||
foreign functions with the `"custom"` ABI cannot be safe
|
||||
.suggestion = remove the `safe` keyword from this definition
|
||||
|
||||
ast_passes_abi_custom_safe_function =
|
||||
functions with the `"custom"` ABI must be unsafe
|
||||
.suggestion = add the `unsafe` keyword to this definition
|
||||
|
||||
ast_passes_assoc_const_without_body =
|
||||
associated constant in `impl` without body
|
||||
.suggestion = provide a definition for the constant
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::str::FromStr;
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_abi::ExternAbi;
|
||||
|
|
@ -81,6 +82,7 @@ struct AstValidator<'a> {
|
|||
|
||||
/// Used to ban explicit safety on foreign items when the extern block is not marked as unsafe.
|
||||
extern_mod_safety: Option<Safety>,
|
||||
extern_mod_abi: Option<ExternAbi>,
|
||||
|
||||
lint_node_id: NodeId,
|
||||
|
||||
|
|
@ -121,10 +123,17 @@ impl<'a> AstValidator<'a> {
|
|||
self.outer_trait_or_trait_impl = old;
|
||||
}
|
||||
|
||||
fn with_in_extern_mod(&mut self, extern_mod_safety: Safety, f: impl FnOnce(&mut Self)) {
|
||||
let old = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
|
||||
fn with_in_extern_mod(
|
||||
&mut self,
|
||||
extern_mod_safety: Safety,
|
||||
abi: Option<ExternAbi>,
|
||||
f: impl FnOnce(&mut Self),
|
||||
) {
|
||||
let old_safety = mem::replace(&mut self.extern_mod_safety, Some(extern_mod_safety));
|
||||
let old_abi = mem::replace(&mut self.extern_mod_abi, abi);
|
||||
f(self);
|
||||
self.extern_mod_safety = old;
|
||||
self.extern_mod_safety = old_safety;
|
||||
self.extern_mod_abi = old_abi;
|
||||
}
|
||||
|
||||
fn with_tilde_const(
|
||||
|
|
@ -370,6 +379,65 @@ impl<'a> AstValidator<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
/// An `extern "custom"` function must be unsafe, and must not have any parameters or return
|
||||
/// type.
|
||||
fn check_custom_abi(&self, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
|
||||
let dcx = self.dcx();
|
||||
|
||||
// An `extern "custom"` function must be unsafe.
|
||||
match sig.header.safety {
|
||||
Safety::Unsafe(_) => { /* all good */ }
|
||||
Safety::Safe(safe_span) => {
|
||||
let safe_span =
|
||||
self.sess.psess.source_map().span_until_non_whitespace(safe_span.to(sig.span));
|
||||
dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span });
|
||||
}
|
||||
Safety::Default => match ctxt {
|
||||
FnCtxt::Foreign => { /* all good */ }
|
||||
FnCtxt::Free | FnCtxt::Assoc(_) => {
|
||||
self.dcx().emit_err(errors::AbiCustomSafeFunction {
|
||||
span: sig.span,
|
||||
unsafe_span: sig.span.shrink_to_lo(),
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
// An `extern "custom"` function cannot be `async` and/or `gen`.
|
||||
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
||||
let coroutine_kind_span = self
|
||||
.sess
|
||||
.psess
|
||||
.source_map()
|
||||
.span_until_non_whitespace(coroutine_kind.span().to(sig.span));
|
||||
|
||||
self.dcx().emit_err(errors::AbiCustomCoroutine {
|
||||
span: sig.span,
|
||||
coroutine_kind_span,
|
||||
coroutine_kind_str: coroutine_kind.as_str(),
|
||||
});
|
||||
}
|
||||
|
||||
// An `extern "custom"` function must not have any parameters or return type.
|
||||
let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
|
||||
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
|
||||
spans.push(ret_ty.span);
|
||||
}
|
||||
|
||||
if !spans.is_empty() {
|
||||
let header_span = sig.header.span().unwrap_or(sig.span.shrink_to_lo());
|
||||
let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());
|
||||
let padding = if header_span.is_empty() { "" } else { " " };
|
||||
|
||||
self.dcx().emit_err(errors::AbiCustomInvalidSignature {
|
||||
spans,
|
||||
symbol: ident.name,
|
||||
suggestion_span,
|
||||
padding,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// This ensures that items can only be `unsafe` (or unmarked) outside of extern
|
||||
/// blocks.
|
||||
///
|
||||
|
|
@ -1005,7 +1073,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
if abi.is_none() {
|
||||
self.handle_missing_abi(*extern_span, item.id);
|
||||
}
|
||||
self.with_in_extern_mod(*safety, |this| {
|
||||
|
||||
let extern_abi = abi.and_then(|abi| ExternAbi::from_str(abi.symbol.as_str()).ok());
|
||||
self.with_in_extern_mod(*safety, extern_abi, |this| {
|
||||
visit::walk_item(this, item);
|
||||
});
|
||||
self.extern_mod_span = old_item;
|
||||
|
|
@ -1145,6 +1215,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_foreign_fn_bodyless(*ident, body.as_deref());
|
||||
self.check_foreign_fn_headerless(sig.header);
|
||||
self.check_foreign_item_ascii_only(*ident);
|
||||
if self.extern_mod_abi == Some(ExternAbi::Custom) {
|
||||
self.check_custom_abi(FnCtxt::Foreign, ident, sig);
|
||||
}
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
|
|
@ -1352,6 +1425,13 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
|||
self.check_item_safety(span, safety);
|
||||
}
|
||||
|
||||
if let FnKind::Fn(ctxt, _, fun) = fk
|
||||
&& let Extern::Explicit(str_lit, _) = fun.sig.header.ext
|
||||
&& let Ok(ExternAbi::Custom) = ExternAbi::from_str(str_lit.symbol.as_str())
|
||||
{
|
||||
self.check_custom_abi(ctxt, &fun.ident, &fun.sig);
|
||||
}
|
||||
|
||||
self.check_c_variadic_type(fk);
|
||||
|
||||
// Functions cannot both be `const async` or `const gen`
|
||||
|
|
@ -1703,6 +1783,7 @@ pub fn check_crate(
|
|||
outer_impl_trait_span: None,
|
||||
disallow_tilde_const: Some(TildeConstReason::Item),
|
||||
extern_mod_safety: None,
|
||||
extern_mod_abi: None,
|
||||
lint_node_id: CRATE_NODE_ID,
|
||||
is_sdylib_interface,
|
||||
lint_buffer: lints,
|
||||
|
|
|
|||
|
|
@ -824,3 +824,67 @@ pub(crate) struct MissingAbi {
|
|||
#[suggestion(code = "extern \"<abi>\"", applicability = "has-placeholders")]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_safe_foreign_function)]
|
||||
pub(crate) struct AbiCustomSafeForeignFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub safe_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_safe_function)]
|
||||
pub(crate) struct AbiCustomSafeFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "unsafe ",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub unsafe_span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_coroutine)]
|
||||
pub(crate) struct AbiCustomCoroutine {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub coroutine_kind_span: Span,
|
||||
pub coroutine_kind_str: &'static str,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(ast_passes_abi_custom_invalid_signature)]
|
||||
#[note]
|
||||
pub(crate) struct AbiCustomInvalidSignature {
|
||||
#[primary_span]
|
||||
pub spans: Vec<Span>,
|
||||
|
||||
#[suggestion(
|
||||
ast_passes_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "{padding}fn {symbol}()",
|
||||
style = "verbose"
|
||||
)]
|
||||
pub suggestion_span: Span,
|
||||
pub symbol: Symbol,
|
||||
pub padding: &'static str,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,11 @@ pub(crate) fn conv_to_call_conv(
|
|||
CanonAbi::Rust | CanonAbi::C => default_call_conv,
|
||||
CanonAbi::RustCold => CallConv::Cold,
|
||||
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
CanonAbi::Custom => default_call_conv,
|
||||
|
||||
CanonAbi::X86(x86_call) => match x86_call {
|
||||
X86Call::SysV64 => CallConv::SystemV,
|
||||
X86Call::Win64 => CallConv::WindowsFastcall,
|
||||
|
|
|
|||
|
|
@ -239,12 +239,16 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
|
|||
pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &str) -> Option<FnAttribute<'gcc>> {
|
||||
let attribute = match conv {
|
||||
CanonAbi::C | CanonAbi::Rust => return None,
|
||||
CanonAbi::RustCold => FnAttribute::Cold,
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
CanonAbi::Custom => return None,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::CCmseNonSecureCall => FnAttribute::ArmCmseNonsecureCall,
|
||||
ArmCall::CCmseNonSecureEntry => FnAttribute::ArmCmseNonsecureEntry,
|
||||
ArmCall::Aapcs => FnAttribute::ArmPcs("aapcs"),
|
||||
},
|
||||
CanonAbi::RustCold => FnAttribute::Cold,
|
||||
CanonAbi::GpuKernel => {
|
||||
if arch == "amdgpu" {
|
||||
FnAttribute::GcnAmdGpuHsaKernel
|
||||
|
|
|
|||
|
|
@ -649,6 +649,10 @@ impl llvm::CallConv {
|
|||
match conv {
|
||||
CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
|
||||
CanonAbi::RustCold => llvm::PreserveMost,
|
||||
// Functions with this calling convention can only be called from assembly, but it is
|
||||
// possible to declare an `extern "custom"` block, so the backend still needs a calling
|
||||
// convention for declaring foreign functions.
|
||||
CanonAbi::Custom => llvm::CCallConv,
|
||||
CanonAbi::GpuKernel => {
|
||||
if arch == "amdgpu" {
|
||||
llvm::AmdgpuKernel
|
||||
|
|
|
|||
|
|
@ -353,6 +353,8 @@ declare_features! (
|
|||
(unstable, abi_avr_interrupt, "1.45.0", Some(69664)),
|
||||
/// Allows `extern "C-cmse-nonsecure-call" fn()`.
|
||||
(unstable, abi_c_cmse_nonsecure_call, "1.51.0", Some(81391)),
|
||||
/// Allows `extern "custom" fn()`.
|
||||
(unstable, abi_custom, "CURRENT_RUSTC_VERSION", Some(140829)),
|
||||
/// Allows `extern "gpu-kernel" fn()`.
|
||||
(unstable, abi_gpu_kernel, "1.86.0", Some(135467)),
|
||||
/// Allows `extern "msp430-interrupt" fn()`.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
hir_analysis_abi_custom_clothed_function =
|
||||
items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
.suggestion = convert this to an `#[unsafe(naked)]` function
|
||||
|
||||
hir_analysis_ambiguous_assoc_item = ambiguous associated {$assoc_kind} `{$assoc_ident}` in bounds of `{$qself}`
|
||||
.label = ambiguous associated {$assoc_kind} `{$assoc_ident}`
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ use rustc_middle::ty::error::TypeErrorToStringExt;
|
|||
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
|
||||
use rustc_middle::ty::util::Discr;
|
||||
use rustc_middle::ty::{
|
||||
AdtDef, BottomUpFolder, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,
|
||||
AdtDef, BottomUpFolder, FnSig, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,
|
||||
TypeVisitable, TypeVisitableExt, fold_regions,
|
||||
};
|
||||
use rustc_session::lint::builtin::UNINHABITED_STATIC;
|
||||
|
|
@ -100,6 +100,18 @@ pub fn check_abi_fn_ptr(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Ex
|
|||
}
|
||||
}
|
||||
|
||||
pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) {
|
||||
if fn_sig.abi == ExternAbi::Custom {
|
||||
// Function definitions that use `extern "custom"` must be naked functions.
|
||||
if !tcx.has_attr(def_id, sym::naked) {
|
||||
tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction {
|
||||
span: fn_sig_span,
|
||||
naked_span: tcx.def_span(def_id).shrink_to_lo(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {
|
||||
let def = tcx.adt_def(def_id);
|
||||
let span = tcx.def_span(def_id);
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ pub mod wfcheck;
|
|||
|
||||
use std::num::NonZero;
|
||||
|
||||
pub use check::{check_abi, check_abi_fn_ptr};
|
||||
pub use check::{check_abi, check_abi_fn_ptr, check_custom_abi};
|
||||
use rustc_abi::{ExternAbi, VariantIdx};
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_errors::{Diag, ErrorGuaranteed, pluralize, struct_span_code_err};
|
||||
|
|
|
|||
|
|
@ -1698,3 +1698,17 @@ pub(crate) struct SelfInTypeAlias {
|
|||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_analysis_abi_custom_clothed_function)]
|
||||
pub(crate) struct AbiCustomClothedFunction {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
#[suggestion(
|
||||
hir_analysis_suggestion,
|
||||
applicability = "maybe-incorrect",
|
||||
code = "#[unsafe(naked)]\n",
|
||||
style = "short"
|
||||
)]
|
||||
pub naked_span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
hir_typeck_abi_custom_call =
|
||||
functions with the `"custom"` ABI cannot be called
|
||||
.note = an `extern "custom"` function can only be called from within inline assembly
|
||||
|
||||
hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
|
||||
|
||||
hir_typeck_add_return_type_add = try adding a return type
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
use std::iter;
|
||||
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_errors::{Applicability, Diag, ErrorGuaranteed, StashKey};
|
||||
use rustc_hir::def::{self, CtorKind, Namespace, Res};
|
||||
|
|
@ -83,6 +84,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
while result.is_none() && autoderef.next().is_some() {
|
||||
result = self.try_overloaded_call_step(call_expr, callee_expr, arg_exprs, &autoderef);
|
||||
}
|
||||
self.check_call_custom_abi(autoderef.final_ty(false), call_expr.span);
|
||||
self.register_predicates(autoderef.into_obligations());
|
||||
|
||||
let output = match result {
|
||||
|
|
@ -135,6 +137,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
output
|
||||
}
|
||||
|
||||
/// Functions of type `extern "custom" fn(/* ... */)` cannot be called using `ExprKind::Call`.
|
||||
///
|
||||
/// These functions have a calling convention that is unknown to rust, hence it cannot generate
|
||||
/// code for the call. The only way to execute such a function is via inline assembly.
|
||||
fn check_call_custom_abi(&self, callee_ty: Ty<'tcx>, span: Span) {
|
||||
let abi = match callee_ty.kind() {
|
||||
ty::FnDef(def_id, _) => self.tcx.fn_sig(def_id).skip_binder().skip_binder().abi,
|
||||
ty::FnPtr(_, header) => header.abi,
|
||||
_ => return,
|
||||
};
|
||||
|
||||
if let ExternAbi::Custom = abi {
|
||||
self.tcx.dcx().emit_err(errors::AbiCustomCall { span });
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip(self, call_expr, callee_expr, arg_exprs, autoderef), ret)]
|
||||
fn try_overloaded_call_step(
|
||||
&self,
|
||||
|
|
|
|||
|
|
@ -1163,3 +1163,10 @@ pub(crate) struct NakedFunctionsMustNakedAsm {
|
|||
#[label]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Diagnostic)]
|
||||
#[diag(hir_typeck_abi_custom_call)]
|
||||
pub(crate) struct AbiCustomCall {
|
||||
#[primary_span]
|
||||
pub span: Span,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
//!
|
||||
//! See [`rustc_hir_analysis::check`] for more context on type checking in general.
|
||||
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx};
|
||||
use rustc_abi::{ExternAbi, FIRST_VARIANT, FieldIdx};
|
||||
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
use rustc_data_structures::unord::UnordMap;
|
||||
|
|
@ -1627,6 +1627,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
Some(method.def_id),
|
||||
);
|
||||
|
||||
// Functions of type `extern "custom" fn(/* ... */)` cannot be called using
|
||||
// `ExprKind::MethodCall`. These functions have a calling convention that is
|
||||
// unknown to rust, hence it cannot generate code for the call. The only way
|
||||
// to execute such a function is via inline assembly.
|
||||
if let ExternAbi::Custom = method.sig.abi {
|
||||
self.tcx.dcx().emit_err(crate::errors::AbiCustomCall { span: expr.span });
|
||||
}
|
||||
|
||||
method.sig.output()
|
||||
}
|
||||
Err(error) => {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ use rustc_errors::{Applicability, ErrorGuaranteed, pluralize, struct_span_code_e
|
|||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::{HirId, HirIdMap, Node};
|
||||
use rustc_hir_analysis::check::check_abi;
|
||||
use rustc_hir_analysis::check::{check_abi, check_custom_abi};
|
||||
use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
|
||||
use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
|
||||
use rustc_middle::query::Providers;
|
||||
|
|
@ -138,7 +138,7 @@ fn typeck_with_inspect<'tcx>(
|
|||
// for visit the asm expr of the body.
|
||||
let ty = fcx.check_expr(body.value);
|
||||
fcx.write_ty(id, ty);
|
||||
} else if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() {
|
||||
} else if let Some(hir::FnSig { header, decl, span: fn_sig_span }) = node.fn_sig() {
|
||||
let fn_sig = if decl.output.is_suggestable_infer_ty().is_some() {
|
||||
// In the case that we're recovering `fn() -> W<_>` or some other return
|
||||
// type that has an infer in it, lower the type directly so that it'll
|
||||
|
|
@ -150,6 +150,8 @@ fn typeck_with_inspect<'tcx>(
|
|||
};
|
||||
|
||||
check_abi(tcx, id, span, fn_sig.abi());
|
||||
check_custom_abi(tcx, def_id, fn_sig.skip_binder(), *fn_sig_span);
|
||||
|
||||
loops::check(tcx, def_id, body);
|
||||
|
||||
// Compute the function signature from point of view of inside the fn.
|
||||
|
|
|
|||
|
|
@ -1266,6 +1266,7 @@ pub fn fn_can_unwind(tcx: TyCtxt<'_>, fn_def_id: Option<DefId>, abi: ExternAbi)
|
|||
| RiscvInterruptS
|
||||
| CCmseNonSecureCall
|
||||
| CCmseNonSecureEntry
|
||||
| Custom
|
||||
| Unadjusted => false,
|
||||
Rust | RustCall | RustCold => tcx.sess.panic_strategy() == PanicStrategy::Unwind,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -496,6 +496,7 @@ impl RustcInternal for Abi {
|
|||
Abi::RustCold => rustc_abi::ExternAbi::RustCold,
|
||||
Abi::RiscvInterruptM => rustc_abi::ExternAbi::RiscvInterruptM,
|
||||
Abi::RiscvInterruptS => rustc_abi::ExternAbi::RiscvInterruptS,
|
||||
Abi::Custom => rustc_abi::ExternAbi::Custom,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,7 @@ impl<'tcx> Stable<'tcx> for CanonAbi {
|
|||
CanonAbi::C => CallConvention::C,
|
||||
CanonAbi::Rust => CallConvention::Rust,
|
||||
CanonAbi::RustCold => CallConvention::Cold,
|
||||
CanonAbi::Custom => CallConvention::Custom,
|
||||
CanonAbi::Arm(arm_call) => match arm_call {
|
||||
ArmCall::Aapcs => CallConvention::ArmAapcs,
|
||||
ArmCall::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall,
|
||||
|
|
|
|||
|
|
@ -879,6 +879,7 @@ impl<'tcx> Stable<'tcx> for rustc_abi::ExternAbi {
|
|||
ExternAbi::RustCold => Abi::RustCold,
|
||||
ExternAbi::RiscvInterruptM => Abi::RiscvInterruptM,
|
||||
ExternAbi::RiscvInterruptS => Abi::RiscvInterruptS,
|
||||
ExternAbi::Custom => Abi::Custom,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -430,6 +430,8 @@ pub enum CallConvention {
|
|||
PreserveMost,
|
||||
PreserveAll,
|
||||
|
||||
Custom,
|
||||
|
||||
// Target-specific calling conventions.
|
||||
ArmAapcs,
|
||||
CCmseNonSecureCall,
|
||||
|
|
|
|||
|
|
@ -1103,6 +1103,7 @@ pub enum Abi {
|
|||
RustCold,
|
||||
RiscvInterruptM,
|
||||
RiscvInterruptS,
|
||||
Custom,
|
||||
}
|
||||
|
||||
/// A binder represents a possibly generic type and its bound vars.
|
||||
|
|
|
|||
|
|
@ -407,6 +407,7 @@ symbols! {
|
|||
abi_amdgpu_kernel,
|
||||
abi_avr_interrupt,
|
||||
abi_c_cmse_nonsecure_call,
|
||||
abi_custom,
|
||||
abi_efiapi,
|
||||
abi_gpu_kernel,
|
||||
abi_msp430_interrupt,
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@ impl AbiMap {
|
|||
(ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
|
||||
(ExternAbi::RustCold, _) => CanonAbi::RustCold,
|
||||
|
||||
(ExternAbi::Custom, _) => CanonAbi::Custom,
|
||||
|
||||
(ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => {
|
||||
CanonAbi::X86(X86Call::Stdcall)
|
||||
}
|
||||
|
|
|
|||
121
tests/ui/abi/bad-custom.rs
Normal file
121
tests/ui/abi/bad-custom.rs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
//@ edition: 2021
|
||||
//@ check-fail
|
||||
//@ needs-asm-support
|
||||
#![feature(abi_custom)]
|
||||
|
||||
#[unsafe(naked)]
|
||||
extern "custom" fn must_be_unsafe(a: i64) -> i64 {
|
||||
//~^ ERROR functions with the `"custom"` ABI must be unsafe
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
std::arch::naked_asm!("")
|
||||
}
|
||||
|
||||
#[unsafe(naked)]
|
||||
unsafe extern "custom" fn no_parameters(a: i64) {
|
||||
//~^ ERROR invalid signature for `extern "custom"` function
|
||||
std::arch::naked_asm!("")
|
||||
}
|
||||
|
||||
#[unsafe(naked)]
|
||||
unsafe extern "custom" fn no_return_type() -> i64 {
|
||||
//~^ ERROR invalid signature for `extern "custom"` function
|
||||
std::arch::naked_asm!("")
|
||||
}
|
||||
|
||||
unsafe extern "custom" fn double(a: i64) -> i64 {
|
||||
//~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
struct Thing(i64);
|
||||
|
||||
impl Thing {
|
||||
unsafe extern "custom" fn is_even(self) -> bool {
|
||||
//~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
trait BitwiseNot {
|
||||
unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
|
||||
//~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
impl BitwiseNot for Thing {}
|
||||
|
||||
trait Negate {
|
||||
extern "custom" fn negate(a: i64) -> i64;
|
||||
//~^ ERROR functions with the `"custom"` ABI must be unsafe
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
}
|
||||
|
||||
impl Negate for Thing {
|
||||
extern "custom" fn negate(a: i64) -> i64 {
|
||||
//~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR functions with the `"custom"` ABI must be unsafe
|
||||
//~| ERROR invalid signature for `extern "custom"` function
|
||||
-a
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "custom" {
|
||||
fn increment(a: i64) -> i64;
|
||||
//~^ ERROR invalid signature for `extern "custom"` function
|
||||
|
||||
safe fn extern_cannot_be_safe();
|
||||
//~^ ERROR foreign functions with the `"custom"` ABI cannot be safe
|
||||
}
|
||||
|
||||
fn caller(f: unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 {
|
||||
unsafe { f(x) }
|
||||
//~^ ERROR functions with the `"custom"` ABI cannot be called
|
||||
}
|
||||
|
||||
fn caller_by_ref(f: &unsafe extern "custom" fn(i64) -> i64, mut x: i64) -> i64 {
|
||||
unsafe { f(x) }
|
||||
//~^ ERROR functions with the `"custom"` ABI cannot be called
|
||||
}
|
||||
|
||||
type Custom = unsafe extern "custom" fn(i64) -> i64;
|
||||
|
||||
fn caller_alias(f: Custom, mut x: i64) -> i64 {
|
||||
unsafe { f(x) }
|
||||
//~^ ERROR functions with the `"custom"` ABI cannot be called
|
||||
}
|
||||
|
||||
#[unsafe(naked)]
|
||||
const unsafe extern "custom" fn no_const_fn() {
|
||||
std::arch::naked_asm!("")
|
||||
//~^ ERROR inline assembly is not allowed in constant functions
|
||||
}
|
||||
|
||||
async unsafe extern "custom" fn no_async_fn() {
|
||||
//~^ ERROR items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
//~| ERROR functions with the `"custom"` ABI cannot be `async`
|
||||
}
|
||||
|
||||
fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() {
|
||||
//~^ ERROR expected a `Fn()` closure, found `unsafe extern "custom" fn()`
|
||||
f
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
unsafe {
|
||||
assert_eq!(double(21), 42);
|
||||
//~^ ERROR functions with the `"custom"` ABI cannot be called
|
||||
|
||||
assert_eq!(unsafe { increment(41) }, 42);
|
||||
//~^ ERROR functions with the `"custom"` ABI cannot be called
|
||||
|
||||
assert!(Thing(41).is_even());
|
||||
//~^ ERROR functions with the `"custom"` ABI cannot be called
|
||||
|
||||
assert_eq!(Thing::bitwise_not(42), !42);
|
||||
//~^ ERROR functions with the `"custom"` ABI cannot be called
|
||||
}
|
||||
}
|
||||
299
tests/ui/abi/bad-custom.stderr
Normal file
299
tests/ui/abi/bad-custom.stderr
Normal file
|
|
@ -0,0 +1,299 @@
|
|||
error: functions with the `"custom"` ABI must be unsafe
|
||||
--> $DIR/bad-custom.rs:7:1
|
||||
|
|
||||
LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add the `unsafe` keyword to this definition
|
||||
|
|
||||
LL | unsafe extern "custom" fn must_be_unsafe(a: i64) -> i64 {
|
||||
| ++++++
|
||||
|
||||
error: invalid signature for `extern "custom"` function
|
||||
--> $DIR/bad-custom.rs:7:35
|
||||
|
|
||||
LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 {
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - extern "custom" fn must_be_unsafe(a: i64) -> i64 {
|
||||
LL + extern "custom" fn must_be_unsafe() {
|
||||
|
|
||||
|
||||
error: invalid signature for `extern "custom"` function
|
||||
--> $DIR/bad-custom.rs:14:41
|
||||
|
|
||||
LL | unsafe extern "custom" fn no_parameters(a: i64) {
|
||||
| ^^^^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - unsafe extern "custom" fn no_parameters(a: i64) {
|
||||
LL + unsafe extern "custom" fn no_parameters() {
|
||||
|
|
||||
|
||||
error: invalid signature for `extern "custom"` function
|
||||
--> $DIR/bad-custom.rs:20:47
|
||||
|
|
||||
LL | unsafe extern "custom" fn no_return_type() -> i64 {
|
||||
| ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - unsafe extern "custom" fn no_return_type() -> i64 {
|
||||
LL + unsafe extern "custom" fn no_return_type() {
|
||||
|
|
||||
|
||||
error: invalid signature for `extern "custom"` function
|
||||
--> $DIR/bad-custom.rs:25:34
|
||||
|
|
||||
LL | unsafe extern "custom" fn double(a: i64) -> i64 {
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - unsafe extern "custom" fn double(a: i64) -> i64 {
|
||||
LL + unsafe extern "custom" fn double() {
|
||||
|
|
||||
|
||||
error: invalid signature for `extern "custom"` function
|
||||
--> $DIR/bad-custom.rs:34:39
|
||||
|
|
||||
LL | unsafe extern "custom" fn is_even(self) -> bool {
|
||||
| ^^^^ ^^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - unsafe extern "custom" fn is_even(self) -> bool {
|
||||
LL + unsafe extern "custom" fn is_even() {
|
||||
|
|
||||
|
||||
error: invalid signature for `extern "custom"` function
|
||||
--> $DIR/bad-custom.rs:42:43
|
||||
|
|
||||
LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
|
||||
LL + unsafe extern "custom" fn bitwise_not() {
|
||||
|
|
||||
|
||||
error: functions with the `"custom"` ABI must be unsafe
|
||||
--> $DIR/bad-custom.rs:52:5
|
||||
|
|
||||
LL | extern "custom" fn negate(a: i64) -> i64;
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add the `unsafe` keyword to this definition
|
||||
|
|
||||
LL | unsafe extern "custom" fn negate(a: i64) -> i64;
|
||||
| ++++++
|
||||
|
||||
error: invalid signature for `extern "custom"` function
|
||||
--> $DIR/bad-custom.rs:52:31
|
||||
|
|
||||
LL | extern "custom" fn negate(a: i64) -> i64;
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - extern "custom" fn negate(a: i64) -> i64;
|
||||
LL + extern "custom" fn negate();
|
||||
|
|
||||
|
||||
error: functions with the `"custom"` ABI must be unsafe
|
||||
--> $DIR/bad-custom.rs:58:5
|
||||
|
|
||||
LL | extern "custom" fn negate(a: i64) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add the `unsafe` keyword to this definition
|
||||
|
|
||||
LL | unsafe extern "custom" fn negate(a: i64) -> i64 {
|
||||
| ++++++
|
||||
|
||||
error: invalid signature for `extern "custom"` function
|
||||
--> $DIR/bad-custom.rs:58:31
|
||||
|
|
||||
LL | extern "custom" fn negate(a: i64) -> i64 {
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - extern "custom" fn negate(a: i64) -> i64 {
|
||||
LL + extern "custom" fn negate() {
|
||||
|
|
||||
|
||||
error: invalid signature for `extern "custom"` function
|
||||
--> $DIR/bad-custom.rs:67:18
|
||||
|
|
||||
LL | fn increment(a: i64) -> i64;
|
||||
| ^^^^^^ ^^^
|
||||
|
|
||||
= note: functions with the `"custom"` ABI cannot have any parameters or return type
|
||||
help: remove the parameters and return type
|
||||
|
|
||||
LL - fn increment(a: i64) -> i64;
|
||||
LL + fn increment();
|
||||
|
|
||||
|
||||
error: foreign functions with the `"custom"` ABI cannot be safe
|
||||
--> $DIR/bad-custom.rs:70:5
|
||||
|
|
||||
LL | safe fn extern_cannot_be_safe();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: remove the `safe` keyword from this definition
|
||||
|
|
||||
LL - safe fn extern_cannot_be_safe();
|
||||
LL + fn extern_cannot_be_safe();
|
||||
|
|
||||
|
||||
error: functions with the `"custom"` ABI cannot be `async`
|
||||
--> $DIR/bad-custom.rs:97:1
|
||||
|
|
||||
LL | async unsafe extern "custom" fn no_async_fn() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: remove the `async` keyword from this definiton
|
||||
|
|
||||
LL - async unsafe extern "custom" fn no_async_fn() {
|
||||
LL + unsafe extern "custom" fn no_async_fn() {
|
||||
|
|
||||
|
||||
error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
--> $DIR/bad-custom.rs:97:1
|
||||
|
|
||||
LL | async unsafe extern "custom" fn no_async_fn() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: convert this to an `#[unsafe(naked)]` function
|
||||
|
|
||||
LL + #[unsafe(naked)]
|
||||
LL | async unsafe extern "custom" fn no_async_fn() {
|
||||
|
|
||||
|
||||
error[E0277]: expected a `Fn()` closure, found `unsafe extern "custom" fn()`
|
||||
--> $DIR/bad-custom.rs:102:64
|
||||
|
|
||||
LL | fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() {
|
||||
| ^^^^^^^^^ call the function in a closure: `|| unsafe { /* code */ }`
|
||||
LL |
|
||||
LL | f
|
||||
| - return type was inferred to be `unsafe extern "custom" fn()` here
|
||||
|
|
||||
= help: the trait `Fn()` is not implemented for `unsafe extern "custom" fn()`
|
||||
= note: unsafe function cannot be called generically without an unsafe block
|
||||
= note: wrap the `unsafe extern "custom" fn()` in a closure with no arguments: `|| { /* code */ }`
|
||||
|
||||
error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
--> $DIR/bad-custom.rs:25:1
|
||||
|
|
||||
LL | unsafe extern "custom" fn double(a: i64) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: convert this to an `#[unsafe(naked)]` function
|
||||
|
|
||||
LL + #[unsafe(naked)]
|
||||
LL | unsafe extern "custom" fn double(a: i64) -> i64 {
|
||||
|
|
||||
|
||||
error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
--> $DIR/bad-custom.rs:34:5
|
||||
|
|
||||
LL | unsafe extern "custom" fn is_even(self) -> bool {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: convert this to an `#[unsafe(naked)]` function
|
||||
|
|
||||
LL + #[unsafe(naked)]
|
||||
LL | unsafe extern "custom" fn is_even(self) -> bool {
|
||||
|
|
||||
|
||||
error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
--> $DIR/bad-custom.rs:42:5
|
||||
|
|
||||
LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: convert this to an `#[unsafe(naked)]` function
|
||||
|
|
||||
LL + #[unsafe(naked)]
|
||||
LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
|
||||
|
|
||||
|
||||
error: items with the `"custom"` ABI can only be declared externally or defined via naked functions
|
||||
--> $DIR/bad-custom.rs:58:5
|
||||
|
|
||||
LL | extern "custom" fn negate(a: i64) -> i64 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: convert this to an `#[unsafe(naked)]` function
|
||||
|
|
||||
LL + #[unsafe(naked)]
|
||||
LL | extern "custom" fn negate(a: i64) -> i64 {
|
||||
|
|
||||
|
||||
error: functions with the `"custom"` ABI cannot be called
|
||||
--> $DIR/bad-custom.rs:75:14
|
||||
|
|
||||
LL | unsafe { f(x) }
|
||||
| ^^^^
|
||||
|
||||
error: functions with the `"custom"` ABI cannot be called
|
||||
--> $DIR/bad-custom.rs:80:14
|
||||
|
|
||||
LL | unsafe { f(x) }
|
||||
| ^^^^
|
||||
|
||||
error: functions with the `"custom"` ABI cannot be called
|
||||
--> $DIR/bad-custom.rs:87:14
|
||||
|
|
||||
LL | unsafe { f(x) }
|
||||
| ^^^^
|
||||
|
||||
error: functions with the `"custom"` ABI cannot be called
|
||||
--> $DIR/bad-custom.rs:109:20
|
||||
|
|
||||
LL | assert_eq!(double(21), 42);
|
||||
| ^^^^^^^^^^
|
||||
|
||||
error: functions with the `"custom"` ABI cannot be called
|
||||
--> $DIR/bad-custom.rs:112:29
|
||||
|
|
||||
LL | assert_eq!(unsafe { increment(41) }, 42);
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error: functions with the `"custom"` ABI cannot be called
|
||||
--> $DIR/bad-custom.rs:115:17
|
||||
|
|
||||
LL | assert!(Thing(41).is_even());
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: functions with the `"custom"` ABI cannot be called
|
||||
--> $DIR/bad-custom.rs:118:20
|
||||
|
|
||||
LL | assert_eq!(Thing::bitwise_not(42), !42);
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error[E0015]: inline assembly is not allowed in constant functions
|
||||
--> $DIR/bad-custom.rs:93:5
|
||||
|
|
||||
LL | std::arch::naked_asm!("")
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 28 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0015, E0277.
|
||||
For more information about an error, try `rustc --explain E0015`.
|
||||
88
tests/ui/abi/custom.rs
Normal file
88
tests/ui/abi/custom.rs
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
// Test that `extern "custom"` functions can be called from assembly, and defined using a naked
|
||||
// function, and `global_asm!` with an `extern "custom"` block.
|
||||
//
|
||||
//@ run-pass
|
||||
//@ only-x86_64
|
||||
#![feature(abi_custom)]
|
||||
|
||||
use std::arch::{asm, global_asm, naked_asm};
|
||||
|
||||
#[unsafe(naked)]
|
||||
unsafe extern "custom" fn double() {
|
||||
naked_asm!("add rax, rax", "ret");
|
||||
}
|
||||
|
||||
global_asm!(
|
||||
// work around macOS prefixing symbols with _
|
||||
" .globl {0}",
|
||||
"{0}:",
|
||||
" add rax, 1",
|
||||
" ret",
|
||||
sym increment,
|
||||
);
|
||||
|
||||
unsafe extern "custom" {
|
||||
fn increment();
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
struct Thing(u64);
|
||||
|
||||
impl Thing {
|
||||
#[unsafe(naked)]
|
||||
unsafe extern "custom" fn is_even() {
|
||||
naked_asm!("test al, 1", "sete al", "ret");
|
||||
}
|
||||
}
|
||||
|
||||
trait BitwiseNot {
|
||||
#[unsafe(naked)]
|
||||
unsafe extern "custom" fn bitwise_not() {
|
||||
naked_asm!("not rax", "ret");
|
||||
}
|
||||
}
|
||||
|
||||
impl BitwiseNot for Thing {}
|
||||
|
||||
#[unsafe(naked)]
|
||||
unsafe extern "C" fn const_generic<const N: u64>() {
|
||||
naked_asm!(
|
||||
"mov rax, {}",
|
||||
"ret",
|
||||
const N,
|
||||
);
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
let mut x: u64 = 21;
|
||||
unsafe { asm!("call {}", sym double, inout("rax") x) };
|
||||
assert_eq!(x, 42);
|
||||
|
||||
let mut x: u64 = 41;
|
||||
unsafe { asm!("call {}", sym increment, inout("rax") x) };
|
||||
assert_eq!(x, 42);
|
||||
|
||||
let mut x: u8;
|
||||
unsafe { asm!("call {}", sym Thing::is_even, inout("al") 42u8 => x) };
|
||||
assert!(x != 0);
|
||||
|
||||
let mut x: u64 = 42;
|
||||
unsafe { asm!("call {}", sym Thing::bitwise_not, inout("rax") x) };
|
||||
assert_eq!(x, !42);
|
||||
|
||||
// Create and call in `asm!` an `extern "custom"` function pointer.
|
||||
fn caller(f: unsafe extern "custom" fn(), mut x: u64) -> u64 {
|
||||
unsafe { asm!("call {}", in(reg) f, inout("rax") x) };
|
||||
x
|
||||
}
|
||||
|
||||
assert_eq!(caller(double, 2), 4);
|
||||
|
||||
let x: u64;
|
||||
unsafe { asm!("call {}", sym const_generic::<42>, out("rax") x) };
|
||||
assert_eq!(x, 42);
|
||||
|
||||
let x: u64;
|
||||
unsafe { asm!("call {}", sym const_generic::<84>, out("rax") x) };
|
||||
assert_eq!(x, 84);
|
||||
}
|
||||
51
tests/ui/feature-gates/feature-gate-abi-custom.rs
Normal file
51
tests/ui/feature-gates/feature-gate-abi-custom.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
//@ add-core-stubs
|
||||
//@ needs-asm-support
|
||||
#![no_core]
|
||||
#![feature(no_core, lang_items)]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[unsafe(naked)]
|
||||
unsafe extern "custom" fn f7() {
|
||||
//~^ ERROR "custom" ABI is experimental
|
||||
naked_asm!("")
|
||||
}
|
||||
trait Tr {
|
||||
extern "custom" fn m7();
|
||||
//~^ ERROR "custom" ABI is experimental
|
||||
//~| ERROR functions with the `"custom"` ABI must be unsafe
|
||||
#[unsafe(naked)]
|
||||
extern "custom" fn dm7() {
|
||||
//~^ ERROR "custom" ABI is experimental
|
||||
//~| ERROR functions with the `"custom"` ABI must be unsafe
|
||||
naked_asm!("")
|
||||
}
|
||||
}
|
||||
|
||||
struct S;
|
||||
|
||||
// Methods in trait impl
|
||||
impl Tr for S {
|
||||
#[unsafe(naked)]
|
||||
extern "custom" fn m7() {
|
||||
//~^ ERROR "custom" ABI is experimental
|
||||
//~| ERROR functions with the `"custom"` ABI must be unsafe
|
||||
naked_asm!("")
|
||||
}
|
||||
}
|
||||
|
||||
// Methods in inherent impl
|
||||
impl S {
|
||||
#[unsafe(naked)]
|
||||
extern "custom" fn im7() {
|
||||
//~^ ERROR "custom" ABI is experimental
|
||||
//~| ERROR functions with the `"custom"` ABI must be unsafe
|
||||
naked_asm!("")
|
||||
}
|
||||
}
|
||||
|
||||
type A7 = extern "custom" fn(); //~ ERROR "custom" ABI is experimental
|
||||
|
||||
extern "custom" {} //~ ERROR "custom" ABI is experimental
|
||||
117
tests/ui/feature-gates/feature-gate-abi-custom.stderr
Normal file
117
tests/ui/feature-gates/feature-gate-abi-custom.stderr
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
error: functions with the `"custom"` ABI must be unsafe
|
||||
--> $DIR/feature-gate-abi-custom.rs:16:5
|
||||
|
|
||||
LL | extern "custom" fn m7();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add the `unsafe` keyword to this definition
|
||||
|
|
||||
LL | unsafe extern "custom" fn m7();
|
||||
| ++++++
|
||||
|
||||
error: functions with the `"custom"` ABI must be unsafe
|
||||
--> $DIR/feature-gate-abi-custom.rs:20:5
|
||||
|
|
||||
LL | extern "custom" fn dm7() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add the `unsafe` keyword to this definition
|
||||
|
|
||||
LL | unsafe extern "custom" fn dm7() {
|
||||
| ++++++
|
||||
|
||||
error: functions with the `"custom"` ABI must be unsafe
|
||||
--> $DIR/feature-gate-abi-custom.rs:32:5
|
||||
|
|
||||
LL | extern "custom" fn m7() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add the `unsafe` keyword to this definition
|
||||
|
|
||||
LL | unsafe extern "custom" fn m7() {
|
||||
| ++++++
|
||||
|
||||
error: functions with the `"custom"` ABI must be unsafe
|
||||
--> $DIR/feature-gate-abi-custom.rs:42:5
|
||||
|
|
||||
LL | extern "custom" fn im7() {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
help: add the `unsafe` keyword to this definition
|
||||
|
|
||||
LL | unsafe extern "custom" fn im7() {
|
||||
| ++++++
|
||||
|
||||
error[E0658]: the extern "custom" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-abi-custom.rs:11:15
|
||||
|
|
||||
LL | unsafe extern "custom" fn f7() {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
|
||||
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "custom" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-abi-custom.rs:16:12
|
||||
|
|
||||
LL | extern "custom" fn m7();
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
|
||||
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "custom" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-abi-custom.rs:20:12
|
||||
|
|
||||
LL | extern "custom" fn dm7() {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
|
||||
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "custom" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-abi-custom.rs:32:12
|
||||
|
|
||||
LL | extern "custom" fn m7() {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
|
||||
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "custom" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-abi-custom.rs:42:12
|
||||
|
|
||||
LL | extern "custom" fn im7() {
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
|
||||
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "custom" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-abi-custom.rs:49:18
|
||||
|
|
||||
LL | type A7 = extern "custom" fn();
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
|
||||
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error[E0658]: the extern "custom" ABI is experimental and subject to change
|
||||
--> $DIR/feature-gate-abi-custom.rs:51:8
|
||||
|
|
||||
LL | extern "custom" {}
|
||||
| ^^^^^^^^
|
||||
|
|
||||
= note: see issue #140829 <https://github.com/rust-lang/rust/issues/140829> for more information
|
||||
= help: add `#![feature(abi_custom)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
|
|
@ -9,6 +9,7 @@ avr-interrupt
|
|||
avr-non-blocking-interrupt
|
||||
cdecl
|
||||
cdecl-unwind
|
||||
custom
|
||||
efiapi
|
||||
fastcall
|
||||
fastcall-unwind
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue