Error on invalid signatures for interrupt ABIs
This commit is contained in:
@@ -21,7 +21,7 @@ use std::ops::{Deref, DerefMut};
|
||||
use std::str::FromStr;
|
||||
|
||||
use itertools::{Either, Itertools};
|
||||
use rustc_abi::ExternAbi;
|
||||
use rustc_abi::{CanonAbi, ExternAbi, InterruptKind};
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
|
||||
use rustc_ast::*;
|
||||
@@ -37,6 +37,7 @@ use rustc_session::lint::builtin::{
|
||||
};
|
||||
use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
|
||||
use rustc_span::{Ident, Span, kw, sym};
|
||||
use rustc_target::spec::{AbiMap, AbiMapping};
|
||||
use thin_vec::thin_vec;
|
||||
|
||||
use crate::errors::{self, TildeConstReason};
|
||||
@@ -365,31 +366,77 @@ 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) {
|
||||
/// Check that the signature of this function does not violate the constraints of its ABI.
|
||||
fn check_extern_fn_signature(&self, abi: ExternAbi, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
|
||||
match AbiMap::from_target(&self.sess.target).canonize_abi(abi, false) {
|
||||
AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => {
|
||||
match canon_abi {
|
||||
CanonAbi::C
|
||||
| CanonAbi::Rust
|
||||
| CanonAbi::RustCold
|
||||
| CanonAbi::Arm(_)
|
||||
| CanonAbi::GpuKernel
|
||||
| CanonAbi::X86(_) => { /* nothing to check */ }
|
||||
|
||||
CanonAbi::Custom => {
|
||||
// An `extern "custom"` function must be unsafe.
|
||||
self.reject_safe_fn(abi, ctxt, sig);
|
||||
|
||||
// An `extern "custom"` function cannot be `async` and/or `gen`.
|
||||
self.reject_coroutine(abi, sig);
|
||||
|
||||
// An `extern "custom"` function must have type `fn()`.
|
||||
self.reject_params_or_return(abi, ident, sig);
|
||||
}
|
||||
|
||||
CanonAbi::Interrupt(interrupt_kind) => {
|
||||
// An interrupt handler cannot be `async` and/or `gen`.
|
||||
self.reject_coroutine(abi, sig);
|
||||
|
||||
if let InterruptKind::X86 = interrupt_kind {
|
||||
// "x86-interrupt" is special because it does have arguments.
|
||||
// FIXME(workingjubilee): properly lint on acceptable input types.
|
||||
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
|
||||
self.dcx().emit_err(errors::AbiMustNotHaveReturnType {
|
||||
span: ret_ty.span,
|
||||
abi,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// An `extern "interrupt"` function must have type `fn()`.
|
||||
self.reject_params_or_return(abi, ident, sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
AbiMapping::Invalid => { /* ignore */ }
|
||||
}
|
||||
}
|
||||
|
||||
fn reject_safe_fn(&self, abi: ExternAbi, ctxt: FnCtxt, 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));
|
||||
let source_map = self.sess.psess.source_map();
|
||||
let safe_span = 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 {
|
||||
dcx.emit_err(errors::AbiCustomSafeFunction {
|
||||
span: sig.span,
|
||||
abi,
|
||||
unsafe_span: sig.span.shrink_to_lo(),
|
||||
});
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// An `extern "custom"` function cannot be `async` and/or `gen`.
|
||||
fn reject_coroutine(&self, abi: ExternAbi, sig: &FnSig) {
|
||||
if let Some(coroutine_kind) = sig.header.coroutine_kind {
|
||||
let coroutine_kind_span = self
|
||||
.sess
|
||||
@@ -397,14 +444,16 @@ impl<'a> AstValidator<'a> {
|
||||
.source_map()
|
||||
.span_until_non_whitespace(coroutine_kind.span().to(sig.span));
|
||||
|
||||
self.dcx().emit_err(errors::AbiCustomCoroutine {
|
||||
self.dcx().emit_err(errors::AbiCannotBeCoroutine {
|
||||
span: sig.span,
|
||||
abi,
|
||||
coroutine_kind_span,
|
||||
coroutine_kind_str: coroutine_kind.as_str(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// An `extern "custom"` function must not have any parameters or return type.
|
||||
fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) {
|
||||
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);
|
||||
@@ -415,11 +464,12 @@ impl<'a> AstValidator<'a> {
|
||||
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 {
|
||||
self.dcx().emit_err(errors::AbiMustNotHaveParametersOrReturnType {
|
||||
spans,
|
||||
symbol: ident.name,
|
||||
suggestion_span,
|
||||
padding,
|
||||
abi,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1199,9 +1249,12 @@ 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);
|
||||
}
|
||||
self.check_extern_fn_signature(
|
||||
self.extern_mod_abi.unwrap_or(ExternAbi::FALLBACK),
|
||||
FnCtxt::Foreign,
|
||||
ident,
|
||||
sig,
|
||||
);
|
||||
}
|
||||
ForeignItemKind::TyAlias(box TyAlias {
|
||||
defaultness,
|
||||
@@ -1411,9 +1464,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
|
||||
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())
|
||||
&& let Ok(abi) = ExternAbi::from_str(str_lit.symbol.as_str())
|
||||
{
|
||||
self.check_custom_abi(ctxt, &fun.ident, &fun.sig);
|
||||
self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig);
|
||||
}
|
||||
|
||||
self.check_c_variadic_type(fk);
|
||||
|
||||
Reference in New Issue
Block a user