@@ -21,7 +21,7 @@ use std::ops::{Deref, DerefMut};
2121use std::str::FromStr;
2222
2323use itertools::{Either, Itertools};
24- use rustc_abi::ExternAbi;
24+ use rustc_abi::{CanonAbi, ExternAbi, InterruptKind} ;
2525use rustc_ast::ptr::P;
2626use rustc_ast::visit::{AssocCtxt, BoundKind, FnCtxt, FnKind, Visitor, walk_list};
2727use rustc_ast::*;
@@ -37,6 +37,7 @@ use rustc_session::lint::builtin::{
3737};
3838use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
3939use rustc_span::{Ident, Span, kw, sym};
40+ use rustc_target::spec::{AbiMap, AbiMapping};
4041use thin_vec::thin_vec;
4142
4243use crate::errors::{self, TildeConstReason};
@@ -365,46 +366,94 @@ impl<'a> AstValidator<'a> {
365366 }
366367 }
367368
368- /// An `extern "custom"` function must be unsafe, and must not have any parameters or return
369- /// type.
370- fn check_custom_abi(&self, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
369+ /// Check that the signature of this function does not violate the constraints of its ABI.
370+ fn check_extern_fn_signature(&self, abi: ExternAbi, ctxt: FnCtxt, ident: &Ident, sig: &FnSig) {
371+ match AbiMap::from_target(&self.sess.target).canonize_abi(abi, false) {
372+ AbiMapping::Direct(canon_abi) | AbiMapping::Deprecated(canon_abi) => {
373+ match canon_abi {
374+ CanonAbi::C
375+ | CanonAbi::Rust
376+ | CanonAbi::RustCold
377+ | CanonAbi::Arm(_)
378+ | CanonAbi::GpuKernel
379+ | CanonAbi::X86(_) => { /* nothing to check */ }
380+
381+ CanonAbi::Custom => {
382+ // An `extern "custom"` function must be unsafe.
383+ self.reject_safe_fn(abi, ctxt, sig);
384+
385+ // An `extern "custom"` function cannot be `async` and/or `gen`.
386+ self.reject_coroutine(abi, sig);
387+
388+ // An `extern "custom"` function must have type `fn()`.
389+ self.reject_params_or_return(abi, ident, sig);
390+ }
391+
392+ CanonAbi::Interrupt(interrupt_kind) => {
393+ // An interrupt handler cannot be `async` and/or `gen`.
394+ self.reject_coroutine(abi, sig);
395+
396+ if let InterruptKind::X86 = interrupt_kind {
397+ // "x86-interrupt" is special because it does have arguments.
398+ // FIXME(workingjubilee): properly lint on acceptable input types.
399+ if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
400+ self.dcx().emit_err(errors::AbiMustNotHaveReturnType {
401+ span: ret_ty.span,
402+ abi,
403+ });
404+ }
405+ } else {
406+ // An `extern "interrupt"` function must have type `fn()`.
407+ self.reject_params_or_return(abi, ident, sig);
408+ }
409+ }
410+ }
411+ }
412+ AbiMapping::Invalid => { /* ignore */ }
413+ }
414+ }
415+
416+ fn reject_safe_fn(&self, abi: ExternAbi, ctxt: FnCtxt, sig: &FnSig) {
371417 let dcx = self.dcx();
372418
373- // An `extern "custom"` function must be unsafe.
374419 match sig.header.safety {
375420 Safety::Unsafe(_) => { /* all good */ }
376421 Safety::Safe(safe_span) => {
377- let safe_span =
378- self.sess.psess. source_map() .span_until_non_whitespace(safe_span.to(sig.span));
422+ let source_map = self.sess.psess.source_map();
423+ let safe_span = source_map.span_until_non_whitespace(safe_span.to(sig.span));
379424 dcx.emit_err(errors::AbiCustomSafeForeignFunction { span: sig.span, safe_span });
380425 }
381426 Safety::Default => match ctxt {
382427 FnCtxt::Foreign => { /* all good */ }
383428 FnCtxt::Free | FnCtxt::Assoc(_) => {
384- self. dcx() .emit_err(errors::AbiCustomSafeFunction {
429+ dcx.emit_err(errors::AbiCustomSafeFunction {
385430 span: sig.span,
431+ abi,
386432 unsafe_span: sig.span.shrink_to_lo(),
387433 });
388434 }
389435 },
390436 }
437+ }
391438
392- // An `extern "custom"` function cannot be `async` and/or `gen`.
439+ fn reject_coroutine(&self, abi: ExternAbi, sig: &FnSig) {
393440 if let Some(coroutine_kind) = sig.header.coroutine_kind {
394441 let coroutine_kind_span = self
395442 .sess
396443 .psess
397444 .source_map()
398445 .span_until_non_whitespace(coroutine_kind.span().to(sig.span));
399446
400- self.dcx().emit_err(errors::AbiCustomCoroutine {
447+ self.dcx().emit_err(errors::AbiCannotBeCoroutine {
401448 span: sig.span,
449+ abi,
402450 coroutine_kind_span,
403451 coroutine_kind_str: coroutine_kind.as_str(),
404452 });
405453 }
454+ }
406455
407- // An `extern "custom"` function must not have any parameters or return type.
456+ fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) {
408457 let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
409458 if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
410459 spans.push(ret_ty.span);
@@ -415,11 +464,12 @@ impl<'a> AstValidator<'a> {
415464 let suggestion_span = header_span.shrink_to_hi().to(sig.decl.output.span());
416465 let padding = if header_span.is_empty() { "" } else { " " };
417466
418- self.dcx().emit_err(errors::AbiCustomInvalidSignature {
467+ self.dcx().emit_err(errors::AbiMustNotHaveParametersOrReturnType {
419468 spans,
420469 symbol: ident.name,
421470 suggestion_span,
422471 padding,
472+ abi,
423473 });
424474 }
425475 }
@@ -1199,9 +1249,12 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
11991249 self.check_foreign_fn_bodyless(*ident, body.as_deref());
12001250 self.check_foreign_fn_headerless(sig.header);
12011251 self.check_foreign_item_ascii_only(*ident);
1202- if self.extern_mod_abi == Some(ExternAbi::Custom) {
1203- self.check_custom_abi(FnCtxt::Foreign, ident, sig);
1204- }
1252+ self.check_extern_fn_signature(
1253+ self.extern_mod_abi.unwrap_or(ExternAbi::FALLBACK),
1254+ FnCtxt::Foreign,
1255+ ident,
1256+ sig,
1257+ );
12051258 }
12061259 ForeignItemKind::TyAlias(box TyAlias {
12071260 defaultness,
@@ -1411,9 +1464,9 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
14111464
14121465 if let FnKind::Fn(ctxt, _, fun) = fk
14131466 && let Extern::Explicit(str_lit, _) = fun.sig.header.ext
1414- && let Ok(ExternAbi::Custom ) = ExternAbi::from_str(str_lit.symbol.as_str())
1467+ && let Ok(abi ) = ExternAbi::from_str(str_lit.symbol.as_str())
14151468 {
1416- self.check_custom_abi( ctxt, &fun.ident, &fun.sig);
1469+ self.check_extern_fn_signature(abi, ctxt, &fun.ident, &fun.sig);
14171470 }
14181471
14191472 self.check_c_variadic_type(fk);
0 commit comments