diff options
| author | Jubilee Young <workingjubilee@gmail.com> | 2025-06-26 19:35:28 -0700 |
|---|---|---|
| committer | Jubilee Young <workingjubilee@gmail.com> | 2025-06-27 11:04:04 -0700 |
| commit | d6b3314fb29cc688a968811b6a78dc8a5309cb7d (patch) | |
| tree | e61a9aca70da93e9f83382b173a722564a3f2a2b | |
| parent | db33e98540fca8f3268cafc6276dbefd55681d55 (diff) | |
| download | rust-d6b3314fb29cc688a968811b6a78dc8a5309cb7d.tar.gz rust-d6b3314fb29cc688a968811b6a78dc8a5309cb7d.zip | |
compiler: allow interrupts to return () or !
| -rw-r--r-- | compiler/rustc_ast_passes/src/ast_validation.rs | 16 | ||||
| -rw-r--r-- | tests/ui/abi/interrupt-returns-never-or-unit.rs | 110 |
2 files changed, 124 insertions, 2 deletions
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index da248251203..478cec23fd5 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -396,7 +396,13 @@ impl<'a> AstValidator<'a> { 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 { + if let FnRetTy::Ty(ref ret_ty) = sig.decl.output + && match &ret_ty.kind { + TyKind::Never => false, + TyKind::Tup(tup) if tup.is_empty() => false, + _ => true, + } + { self.dcx().emit_err(errors::AbiMustNotHaveReturnType { span: ret_ty.span, abi, @@ -455,7 +461,13 @@ impl<'a> AstValidator<'a> { 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 { + if let FnRetTy::Ty(ref ret_ty) = sig.decl.output + && match &ret_ty.kind { + TyKind::Never => false, + TyKind::Tup(tup) if tup.is_empty() => false, + _ => true, + } + { spans.push(ret_ty.span); } diff --git a/tests/ui/abi/interrupt-returns-never-or-unit.rs b/tests/ui/abi/interrupt-returns-never-or-unit.rs new file mode 100644 index 00000000000..34d509c8328 --- /dev/null +++ b/tests/ui/abi/interrupt-returns-never-or-unit.rs @@ -0,0 +1,110 @@ +/*! Tests interrupt ABIs can return ! + +Most interrupt ABIs share a similar restriction in terms of not allowing most signatures, +but it makes sense to allow them to return ! because they could indeed be divergent. + +This test uses `cfg` because it is not testing whether these ABIs work on the platform. +*/ +//@ add-core-stubs +//@ revisions: x64 i686 riscv32 riscv64 avr msp430 +//@ build-pass +// +//@ [x64] needs-llvm-components: x86 +//@ [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib +//@ [i686] needs-llvm-components: x86 +//@ [i686] compile-flags: --target=i686-unknown-linux-gnu --crate-type=rlib +//@ [riscv32] needs-llvm-components: riscv +//@ [riscv32] compile-flags: --target=riscv32i-unknown-none-elf --crate-type=rlib +//@ [riscv64] needs-llvm-components: riscv +//@ [riscv64] compile-flags: --target=riscv64gc-unknown-none-elf --crate-type=rlib +//@ [avr] needs-llvm-components: avr +//@ [avr] compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib +//@ [msp430] needs-llvm-components: msp430 +//@ [msp430] compile-flags: --target=msp430-none-elf --crate-type=rlib +#![no_core] +#![feature( + no_core, + abi_msp430_interrupt, + abi_avr_interrupt, + abi_x86_interrupt, + abi_riscv_interrupt +)] + +extern crate minicore; +use minicore::*; + +/* interrupts can return never */ + +#[cfg(avr)] +extern "avr-interrupt" fn avr_ret_never() -> ! { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(msp430)] +extern "msp430-interrupt" fn msp430_ret_never() -> ! { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-m" fn riscv_m_ret_never() -> ! { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-s" fn riscv_s_ret_never() -> ! { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(x64,i686))] +extern "x86-interrupt" fn x86_ret_never() -> ! { + unsafe { hint::unreachable_unchecked() } +} + +/* interrupts can return explicit () */ + +#[cfg(avr)] +extern "avr-interrupt" fn avr_ret_unit() -> () { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(msp430)] +extern "msp430-interrupt" fn msp430_ret_unit() -> () { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-m" fn riscv_m_ret_unit() -> () { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(riscv32,riscv64))] +extern "riscv-interrupt-s" fn riscv_s_ret_unit() -> () { + unsafe { hint::unreachable_unchecked() } +} + +#[cfg(any(x64,i686))] +extern "x86-interrupt" fn x86_ret_unit() -> () { + unsafe { hint::unreachable_unchecked() } +} + +/* extern "interrupt" fnptrs can return ! too */ + +#[cfg(avr)] +fn avr_ptr(_f: extern "avr-interrupt" fn() -> !) { +} + +#[cfg(msp430)] +fn msp430_ptr(_f: extern "msp430-interrupt" fn() -> !) { +} + +#[cfg(any(riscv32,riscv64))] +fn riscv_m_ptr(_f: extern "riscv-interrupt-m" fn() -> !) { +} + +#[cfg(any(riscv32,riscv64))] +fn riscv_s_ptr(_f: extern "riscv-interrupt-s" fn() -> !) { +} + +#[cfg(any(x64,i686))] +fn x86_ptr(_f: extern "x86-interrupt" fn() -> !) { +} |
