Skip to content

Error on invalid signatures for interrupt ABIs #142633

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3316,6 +3316,7 @@ dependencies = [
"rustc_parse",
"rustc_session",
"rustc_span",
"rustc_target",
"thin-vec",
]

Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_ast_passes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ rustc_macros = { path = "../rustc_macros" }
rustc_parse = { path = "../rustc_parse" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
thin-vec = "0.2.12"
# tidy-alphabetical-end
19 changes: 12 additions & 7 deletions compiler/rustc_ast_passes/messages.ftl
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
ast_passes_abi_custom_coroutine =
functions with the `"custom"` ABI cannot be `{$coroutine_kind_str}`
ast_passes_abi_cannot_be_coroutine =
functions with the {$abi} 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
Expand All @@ -15,6 +10,16 @@ ast_passes_abi_custom_safe_function =
functions with the `"custom"` ABI must be unsafe
.suggestion = add the `unsafe` keyword to this definition

ast_passes_abi_must_not_have_parameters_or_return_type=
invalid signature for `extern {$abi}` function
.note = functions with the {$abi} ABI cannot have any parameters or return type
.suggestion = remove the parameters and return type

ast_passes_abi_must_not_have_return_type=
invalid signature for `extern {$abi}` function
.note = functions with the `"custom"` ABI cannot have a return type
.help = remove the return type

ast_passes_assoc_const_without_body =
associated constant in `impl` without body
.suggestion = provide a definition for the constant
Expand Down
87 changes: 70 additions & 17 deletions compiler/rustc_ast_passes/src/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand All @@ -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};
Expand Down Expand Up @@ -365,46 +366,94 @@ 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 this function does not violate the constraints of its ABI.
fn check_abi(&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.check_abi_is_unsafe(abi, ctxt, sig);

// An `extern "custom"` function cannot be `async` and/or `gen`.
self.check_abi_is_not_coroutine(abi, sig);

// An `extern "custom"` function must have type `fn()`.
self.check_abi_no_params_or_return(abi, ident, sig);
}

CanonAbi::Interrupt(interrupt_kind) => {
// An interrupt handler cannot be `async` and/or `gen`.
self.check_abi_is_not_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.check_abi_no_params_or_return(abi, ident, sig);
}
}
}
}
AbiMapping::Invalid => { /* ignore */ }
}
}

fn check_abi_is_unsafe(&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 check_abi_is_not_coroutine(&self, abi: ExternAbi, sig: &FnSig) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

very "just as planned" of you, nice

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 {
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 check_abi_no_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);
Expand All @@ -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,
});
}
}
Expand Down Expand Up @@ -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_abi(
self.extern_mod_abi.unwrap_or(ExternAbi::FALLBACK),
FnCtxt::Foreign,
ident,
sig,
);
}
ForeignItemKind::TyAlias(box TyAlias {
defaultness,
Expand Down Expand Up @@ -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_abi(abi, ctxt, &fun.ident, &fun.sig);
}

self.check_c_variadic_type(fk);
Expand Down
22 changes: 18 additions & 4 deletions compiler/rustc_ast_passes/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Errors emitted by ast_passes.

use rustc_abi::ExternAbi;
use rustc_ast::ParamKindOrd;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, EmissionGuarantee, Subdiagnostic};
Expand Down Expand Up @@ -845,6 +846,7 @@ pub(crate) struct AbiCustomSafeForeignFunction {
pub(crate) struct AbiCustomSafeFunction {
#[primary_span]
pub span: Span,
pub abi: ExternAbi,

#[suggestion(
ast_passes_suggestion,
Expand All @@ -856,10 +858,11 @@ pub(crate) struct AbiCustomSafeFunction {
}

#[derive(Diagnostic)]
#[diag(ast_passes_abi_custom_coroutine)]
pub(crate) struct AbiCustomCoroutine {
#[diag(ast_passes_abi_cannot_be_coroutine)]
pub(crate) struct AbiCannotBeCoroutine {
#[primary_span]
pub span: Span,
pub abi: ExternAbi,

#[suggestion(
ast_passes_suggestion,
Expand All @@ -872,11 +875,12 @@ pub(crate) struct AbiCustomCoroutine {
}

#[derive(Diagnostic)]
#[diag(ast_passes_abi_custom_invalid_signature)]
#[diag(ast_passes_abi_must_not_have_parameters_or_return_type)]
#[note]
pub(crate) struct AbiCustomInvalidSignature {
pub(crate) struct AbiMustNotHaveParametersOrReturnType {
#[primary_span]
pub spans: Vec<Span>,
pub abi: ExternAbi,

#[suggestion(
ast_passes_suggestion,
Expand All @@ -888,3 +892,13 @@ pub(crate) struct AbiCustomInvalidSignature {
pub symbol: Symbol,
pub padding: &'static str,
}

#[derive(Diagnostic)]
#[diag(ast_passes_abi_must_not_have_return_type)]
#[note]
pub(crate) struct AbiMustNotHaveReturnType {
#[primary_span]
#[help]
pub span: Span,
pub abi: ExternAbi,
}
6 changes: 2 additions & 4 deletions tests/codegen/abi-x86-interrupt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
extern crate minicore;
use minicore::*;

// CHECK: define x86_intrcc i64 @has_x86_interrupt_abi
// CHECK: define x86_intrcc void @has_x86_interrupt_abi
#[no_mangle]
pub extern "x86-interrupt" fn has_x86_interrupt_abi(a: i64) -> i64 {
a
}
pub extern "x86-interrupt" fn has_x86_interrupt_abi() {}
2 changes: 1 addition & 1 deletion tests/ui/abi/bad-custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ const unsafe extern "custom" fn no_const_fn() {

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`
//~| ERROR functions with the "custom" ABI cannot be `async`
}

fn no_promotion_to_fn_trait(f: unsafe extern "custom" fn()) -> impl Fn() {
Expand Down
20 changes: 10 additions & 10 deletions tests/ui/abi/bad-custom.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ error: invalid signature for `extern "custom"` function
LL | extern "custom" fn must_be_unsafe(a: i64) -> i64 {
| ^^^^^^ ^^^
|
= note: functions with the `"custom"` ABI cannot have any parameters or return type
= 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 {
Expand All @@ -28,7 +28,7 @@ error: invalid signature for `extern "custom"` function
LL | unsafe extern "custom" fn no_parameters(a: i64) {
| ^^^^^^
|
= note: functions with the `"custom"` ABI cannot have any parameters or return type
= 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) {
Expand All @@ -41,7 +41,7 @@ error: invalid signature for `extern "custom"` function
LL | unsafe extern "custom" fn no_return_type() -> i64 {
| ^^^
|
= note: functions with the `"custom"` ABI cannot have any parameters or return type
= 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 {
Expand All @@ -54,7 +54,7 @@ error: invalid signature for `extern "custom"` function
LL | unsafe extern "custom" fn double(a: i64) -> i64 {
| ^^^^^^ ^^^
|
= note: functions with the `"custom"` ABI cannot have any parameters or return type
= 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 {
Expand All @@ -67,7 +67,7 @@ error: invalid signature for `extern "custom"` function
LL | unsafe extern "custom" fn is_even(self) -> bool {
| ^^^^ ^^^^
|
= note: functions with the `"custom"` ABI cannot have any parameters or return type
= 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 {
Expand All @@ -80,7 +80,7 @@ error: invalid signature for `extern "custom"` function
LL | unsafe extern "custom" fn bitwise_not(a: i64) -> i64 {
| ^^^^^^ ^^^
|
= note: functions with the `"custom"` ABI cannot have any parameters or return type
= 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 {
Expand All @@ -104,7 +104,7 @@ error: invalid signature for `extern "custom"` function
LL | extern "custom" fn negate(a: i64) -> i64;
| ^^^^^^ ^^^
|
= note: functions with the `"custom"` ABI cannot have any parameters or return type
= 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;
Expand All @@ -128,7 +128,7 @@ error: invalid signature for `extern "custom"` function
LL | extern "custom" fn negate(a: i64) -> i64 {
| ^^^^^^ ^^^
|
= note: functions with the `"custom"` ABI cannot have any parameters or return type
= 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 {
Expand All @@ -141,7 +141,7 @@ error: invalid signature for `extern "custom"` function
LL | fn increment(a: i64) -> i64;
| ^^^^^^ ^^^
|
= note: functions with the `"custom"` ABI cannot have any parameters or return type
= 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;
Expand All @@ -160,7 +160,7 @@ LL - safe fn extern_cannot_be_safe();
LL + fn extern_cannot_be_safe();
|

error: functions with the `"custom"` ABI cannot be `async`
error: functions with the "custom" ABI cannot be `async`
--> $DIR/bad-custom.rs:97:1
|
LL | async unsafe extern "custom" fn no_async_fn() {
Expand Down
Loading