Skip to content

Commit 765309e

Browse files
compiler: allow interrupts to return () or !
1 parent 6a62830 commit 765309e

File tree

2 files changed

+124
-2
lines changed

2 files changed

+124
-2
lines changed

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,13 @@ impl<'a> AstValidator<'a> {
396396
if let InterruptKind::X86 = interrupt_kind {
397397
// "x86-interrupt" is special because it does have arguments.
398398
// FIXME(workingjubilee): properly lint on acceptable input types.
399-
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
399+
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
400+
&& match &ret_ty.kind {
401+
TyKind::Never => false,
402+
TyKind::Tup(tup) if tup.is_empty() => false,
403+
_ => true,
404+
}
405+
{
400406
self.dcx().emit_err(errors::AbiMustNotHaveReturnType {
401407
span: ret_ty.span,
402408
abi,
@@ -455,7 +461,13 @@ impl<'a> AstValidator<'a> {
455461

456462
fn reject_params_or_return(&self, abi: ExternAbi, ident: &Ident, sig: &FnSig) {
457463
let mut spans: Vec<_> = sig.decl.inputs.iter().map(|p| p.span).collect();
458-
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output {
464+
if let FnRetTy::Ty(ref ret_ty) = sig.decl.output
465+
&& match &ret_ty.kind {
466+
TyKind::Never => false,
467+
TyKind::Tup(tup) if tup.is_empty() => false,
468+
_ => true,
469+
}
470+
{
459471
spans.push(ret_ty.span);
460472
}
461473

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*! Tests interrupt ABIs can return !
2+
3+
Most interrupt ABIs share a similar restriction in terms of not allowing most signatures,
4+
but it makes sense to allow them to return ! because they could indeed be divergent.
5+
6+
This test uses `cfg` because it is not testing whether these ABIs work on the platform.
7+
*/
8+
//@ add-core-stubs
9+
//@ revisions: x64 i686 riscv32 riscv64 avr msp430
10+
//@ build-pass
11+
//
12+
//@ [x64] needs-llvm-components: x86
13+
//@ [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib
14+
//@ [i686] needs-llvm-components: x86
15+
//@ [i686] compile-flags: --target=i686-unknown-linux-gnu --crate-type=rlib
16+
//@ [riscv32] needs-llvm-components: riscv
17+
//@ [riscv32] compile-flags: --target=riscv32i-unknown-none-elf --crate-type=rlib
18+
//@ [riscv64] needs-llvm-components: riscv
19+
//@ [riscv64] compile-flags: --target=riscv64gc-unknown-none-elf --crate-type=rlib
20+
//@ [avr] needs-llvm-components: avr
21+
//@ [avr] compile-flags: --target=avr-none -C target-cpu=atmega328p --crate-type=rlib
22+
//@ [msp430] needs-llvm-components: msp430
23+
//@ [msp430] compile-flags: --target=msp430-none-elf --crate-type=rlib
24+
#![no_core]
25+
#![feature(
26+
no_core,
27+
abi_msp430_interrupt,
28+
abi_avr_interrupt,
29+
abi_x86_interrupt,
30+
abi_riscv_interrupt
31+
)]
32+
33+
extern crate minicore;
34+
use minicore::*;
35+
36+
/* interrupts can return never */
37+
38+
#[cfg(avr)]
39+
extern "avr-interrupt" fn avr_ret_never() -> ! {
40+
unsafe { hint::unreachable_unchecked() }
41+
}
42+
43+
#[cfg(msp430)]
44+
extern "msp430-interrupt" fn msp430_ret_never() -> ! {
45+
unsafe { hint::unreachable_unchecked() }
46+
}
47+
48+
#[cfg(any(riscv32,riscv64))]
49+
extern "riscv-interrupt-m" fn riscv_m_ret_never() -> ! {
50+
unsafe { hint::unreachable_unchecked() }
51+
}
52+
53+
#[cfg(any(riscv32,riscv64))]
54+
extern "riscv-interrupt-s" fn riscv_s_ret_never() -> ! {
55+
unsafe { hint::unreachable_unchecked() }
56+
}
57+
58+
#[cfg(any(x64,i686))]
59+
extern "x86-interrupt" fn x86_ret_never() -> ! {
60+
unsafe { hint::unreachable_unchecked() }
61+
}
62+
63+
/* interrupts can return explicit () */
64+
65+
#[cfg(avr)]
66+
extern "avr-interrupt" fn avr_ret_unit() -> () {
67+
unsafe { hint::unreachable_unchecked() }
68+
}
69+
70+
#[cfg(msp430)]
71+
extern "msp430-interrupt" fn msp430_ret_unit() -> () {
72+
unsafe { hint::unreachable_unchecked() }
73+
}
74+
75+
#[cfg(any(riscv32,riscv64))]
76+
extern "riscv-interrupt-m" fn riscv_m_ret_unit() -> () {
77+
unsafe { hint::unreachable_unchecked() }
78+
}
79+
80+
#[cfg(any(riscv32,riscv64))]
81+
extern "riscv-interrupt-s" fn riscv_s_ret_unit() -> () {
82+
unsafe { hint::unreachable_unchecked() }
83+
}
84+
85+
#[cfg(any(x64,i686))]
86+
extern "x86-interrupt" fn x86_ret_unit() -> () {
87+
unsafe { hint::unreachable_unchecked() }
88+
}
89+
90+
/* extern "interrupt" fnptrs can return ! too */
91+
92+
#[cfg(avr)]
93+
fn avr_ptr(_f: extern "avr-interrupt" fn() -> !) {
94+
}
95+
96+
#[cfg(msp430)]
97+
fn msp430_ptr(_f: extern "msp430-interrupt" fn() -> !) {
98+
}
99+
100+
#[cfg(any(riscv32,riscv64))]
101+
fn riscv_m_ptr(_f: extern "riscv-interrupt-m" fn() -> !) {
102+
}
103+
104+
#[cfg(any(riscv32,riscv64))]
105+
fn riscv_s_ptr(_f: extern "riscv-interrupt-s" fn() -> !) {
106+
}
107+
108+
#[cfg(any(x64,i686))]
109+
fn x86_ptr(_f: extern "x86-interrupt" fn() -> !) {
110+
}

0 commit comments

Comments
 (0)