about summary refs log tree commit diff
path: root/tests
diff options
context:
space:
mode:
authorSeth Pellegrino <seth@codecopse.net>2023-05-23 15:08:23 -0700
committerSeth Pellegrino <seth@codecopse.net>2023-08-08 18:09:56 -0700
commit897c7bb23bfd29b94de4b390cdc3c5c38be84990 (patch)
treeffa72276d4e24a61e1d6870d66b0dbbe8d31d592 /tests
parentf88a8b71cebb730cbd5058c45ebcae1d4d9be377 (diff)
downloadrust-897c7bb23bfd29b94de4b390cdc3c5c38be84990.tar.gz
rust-897c7bb23bfd29b94de4b390cdc3c5c38be84990.zip
feat: `riscv-interrupt-{m,s}` calling conventions
Similar to prior support added for the mips430, avr, and x86 targets
this change implements the rough equivalent of clang's
[`__attribute__((interrupt))`][clang-attr] for riscv targets, enabling
e.g.

```rust
static mut CNT: usize = 0;

pub extern "riscv-interrupt-m" fn isr_m() {
    unsafe {
        CNT += 1;
    }
}
```

to produce highly effective assembly like:

```asm
pub extern "riscv-interrupt-m" fn isr_m() {
420003a0:       1141                    addi    sp,sp,-16
    unsafe {
        CNT += 1;
420003a2:       c62a                    sw      a0,12(sp)
420003a4:       c42e                    sw      a1,8(sp)
420003a6:       3fc80537                lui     a0,0x3fc80
420003aa:       63c52583                lw      a1,1596(a0) # 3fc8063c <_ZN12esp_riscv_rt3CNT17hcec3e3a214887d53E.0>
420003ae:       0585                    addi    a1,a1,1
420003b0:       62b52e23                sw      a1,1596(a0)
    }
}
420003b4:       4532                    lw      a0,12(sp)
420003b6:       45a2                    lw      a1,8(sp)
420003b8:       0141                    addi    sp,sp,16
420003ba:       30200073                mret
```

(disassembly via `riscv64-unknown-elf-objdump -C -S --disassemble ./esp32c3-hal/target/riscv32imc-unknown-none-elf/release/examples/gpio_interrupt`)

This outcome is superior to hand-coded interrupt routines which, lacking
visibility into any non-assembly body of the interrupt handler, have to
be very conservative and save the [entire CPU state to the stack
frame][full-frame-save]. By instead asking LLVM to only save the
registers that it uses, we defer the decision to the tool with the best
context: it can more accurately account for the cost of spills if it
knows that every additional register used is already at the cost of an
implicit spill.

At the LLVM level, this is apparently [implemented by] marking every
register as "[callee-save]," matching the semantics of an interrupt
handler nicely (it has to leave the CPU state just as it found it after
its `{m|s}ret`).

This approach is not suitable for every interrupt handler, as it makes
no attempt to e.g. save the state in a user-accessible stack frame. For
a full discussion of those challenges and tradeoffs, please refer to
[the interrupt calling conventions RFC][rfc].

Inside rustc, this implementation differs from prior art because LLVM
does not expose the "all-saved" function flavor as a calling convention
directly, instead preferring to use an attribute that allows for
differentiating between "machine-mode" and "superivsor-mode" interrupts.

Finally, some effort has been made to guide those who may not yet be
aware of the differences between machine-mode and supervisor-mode
interrupts as to why no `riscv-interrupt` calling convention is exposed
through rustc, and similarly for why `riscv-interrupt-u` makes no
appearance (as it would complicate future LLVM upgrades).

[clang-attr]: https://clang.llvm.org/docs/AttributeReference.html#interrupt-risc-v
[full-frame-save]: https://github.com/esp-rs/esp-riscv-rt/blob/9281af2ecffe13e40992917316f36920c26acaf3/src/lib.rs#L440-L469
[implemented by]: https://github.com/llvm/llvm-project/blob/b7fb2a3fec7c187d58a6d338ab512d9173bca987/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp#L61-L67
[callee-save]: https://github.com/llvm/llvm-project/blob/973f1fe7a8591c7af148e573491ab68cc15b6ecf/llvm/lib/Target/RISCV/RISCVCallingConv.td#L30-L37
[rfc]: https://github.com/rust-lang/rfcs/pull/3246
Diffstat (limited to 'tests')
-rw-r--r--tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr27
-rw-r--r--tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr27
-rw-r--r--tests/ui/abi/riscv-discoverability-guidance.rs27
-rw-r--r--tests/ui/abi/unsupported.aarch64.stderr26
-rw-r--r--tests/ui/abi/unsupported.arm.stderr24
-rw-r--r--tests/ui/abi/unsupported.i686.stderr20
-rw-r--r--tests/ui/abi/unsupported.riscv32.stderr61
-rw-r--r--tests/ui/abi/unsupported.riscv64.stderr61
-rw-r--r--tests/ui/abi/unsupported.rs40
-rw-r--r--tests/ui/abi/unsupported.x64.stderr24
-rw-r--r--tests/ui/feature-gates/feature-gate-abi-riscv-interrupt.rs33
-rw-r--r--tests/ui/feature-gates/feature-gate-abi-riscv-interrupt.stderr57
12 files changed, 382 insertions, 45 deletions
diff --git a/tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr b/tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr
new file mode 100644
index 00000000000..02082c13f91
--- /dev/null
+++ b/tests/ui/abi/riscv-discoverability-guidance.riscv32.stderr
@@ -0,0 +1,27 @@
+error[E0703]: invalid ABI: found `riscv-interrupt`
+  --> $DIR/riscv-discoverability-guidance.rs:17:8
+   |
+LL | extern "riscv-interrupt" fn isr() {}
+   |        ^^^^^^^^^^^^^^^^^
+   |        |
+   |        invalid ABI
+   |        help: did you mean: `"riscv-interrupt-m"`
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions.
+   = note: please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively
+
+error[E0703]: invalid ABI: found `riscv-interrupt-u`
+  --> $DIR/riscv-discoverability-guidance.rs:23:8
+   |
+LL | extern "riscv-interrupt-u" fn isr_U() {}
+   |        ^^^^^^^^^^^^^^^^^^^
+   |        |
+   |        invalid ABI
+   |        help: did you mean: `"riscv-interrupt-m"`
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions.
+   = note: user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0703`.
diff --git a/tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr b/tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr
new file mode 100644
index 00000000000..02082c13f91
--- /dev/null
+++ b/tests/ui/abi/riscv-discoverability-guidance.riscv64.stderr
@@ -0,0 +1,27 @@
+error[E0703]: invalid ABI: found `riscv-interrupt`
+  --> $DIR/riscv-discoverability-guidance.rs:17:8
+   |
+LL | extern "riscv-interrupt" fn isr() {}
+   |        ^^^^^^^^^^^^^^^^^
+   |        |
+   |        invalid ABI
+   |        help: did you mean: `"riscv-interrupt-m"`
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions.
+   = note: please use one of riscv-interrupt-m or riscv-interrupt-s for machine- or supervisor-level interrupts, respectively
+
+error[E0703]: invalid ABI: found `riscv-interrupt-u`
+  --> $DIR/riscv-discoverability-guidance.rs:23:8
+   |
+LL | extern "riscv-interrupt-u" fn isr_U() {}
+   |        ^^^^^^^^^^^^^^^^^^^
+   |        |
+   |        invalid ABI
+   |        help: did you mean: `"riscv-interrupt-m"`
+   |
+   = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions.
+   = note: user-mode interrupt handlers have been removed from LLVM pending standardization, see: https://reviews.llvm.org/D149314
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0703`.
diff --git a/tests/ui/abi/riscv-discoverability-guidance.rs b/tests/ui/abi/riscv-discoverability-guidance.rs
new file mode 100644
index 00000000000..f57fcd6044f
--- /dev/null
+++ b/tests/ui/abi/riscv-discoverability-guidance.rs
@@ -0,0 +1,27 @@
+// ignore-tidy-linelength
+// revisions: riscv32 riscv64
+//
+// [riscv32] needs-llvm-components: riscv
+// [riscv32] compile-flags: --target=riscv32i-unknown-none-elf -C target-feature=-unaligned-scalar-mem --crate-type=rlib
+// [riscv64] needs-llvm-components: riscv
+// [riscv64] compile-flags: --target=riscv64gc-unknown-none-elf -C target-feature=-unaligned-scalar-mem --crate-type=rlib
+#![no_core]
+#![feature(
+    no_core,
+    lang_items,
+    abi_riscv_interrupt
+)]
+#[lang = "sized"]
+trait Sized {}
+
+extern "riscv-interrupt" fn isr() {}
+//~^ ERROR invalid ABI
+//~^^ NOTE invalid ABI
+//~^^^ NOTE invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
+//~^^^^ NOTE please use one of riscv-interrupt-m or riscv-interrupt-s
+
+extern "riscv-interrupt-u" fn isr_U() {}
+//~^ ERROR invalid ABI
+//~^^ NOTE invalid ABI
+//~^^^ NOTE invoke `rustc --print=calling-conventions` for a full list of supported calling conventions
+//~^^^^ NOTE user-mode interrupt handlers have been removed from LLVM pending standardization
diff --git a/tests/ui/abi/unsupported.aarch64.stderr b/tests/ui/abi/unsupported.aarch64.stderr
index 980457eeab5..d7b4e6150ff 100644
--- a/tests/ui/abi/unsupported.aarch64.stderr
+++ b/tests/ui/abi/unsupported.aarch64.stderr
@@ -1,53 +1,59 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:25:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:27:1
+  --> $DIR/unsupported.rs:32:1
    |
 LL | extern "amdgpu-kernel" fn amdgpu() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:29:1
+  --> $DIR/unsupported.rs:34:1
    |
 LL | extern "wasm" fn wasm() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:31:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:35:1
+  --> $DIR/unsupported.rs:42:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:37:1
+  --> $DIR/unsupported.rs:44:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:46:1
+   |
+LL | extern "riscv-interrupt-m" fn riscv() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:39:1
+  --> $DIR/unsupported.rs:51:1
    |
 LL | extern "x86-interrupt" fn x86() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:42:1
+  --> $DIR/unsupported.rs:56:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:46:1
+  --> $DIR/unsupported.rs:62:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -56,6 +62,6 @@ LL | extern "stdcall" fn stdcall() {}
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
    = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error: aborting due to 8 previous errors; 1 warning emitted
+error: aborting due to 9 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.arm.stderr b/tests/ui/abi/unsupported.arm.stderr
index 450abd94886..3a3ed2dd9c5 100644
--- a/tests/ui/abi/unsupported.arm.stderr
+++ b/tests/ui/abi/unsupported.arm.stderr
@@ -1,47 +1,53 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:25:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:27:1
+  --> $DIR/unsupported.rs:32:1
    |
 LL | extern "amdgpu-kernel" fn amdgpu() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:29:1
+  --> $DIR/unsupported.rs:34:1
    |
 LL | extern "wasm" fn wasm() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:35:1
+  --> $DIR/unsupported.rs:42:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:37:1
+  --> $DIR/unsupported.rs:44:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:46:1
+   |
+LL | extern "riscv-interrupt-m" fn riscv() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:39:1
+  --> $DIR/unsupported.rs:51:1
    |
 LL | extern "x86-interrupt" fn x86() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:42:1
+  --> $DIR/unsupported.rs:56:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:46:1
+  --> $DIR/unsupported.rs:62:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,6 +56,6 @@ LL | extern "stdcall" fn stdcall() {}
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
    = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error: aborting due to 7 previous errors; 1 warning emitted
+error: aborting due to 8 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.i686.stderr b/tests/ui/abi/unsupported.i686.stderr
index 0340382a452..31b7d030bd3 100644
--- a/tests/ui/abi/unsupported.i686.stderr
+++ b/tests/ui/abi/unsupported.i686.stderr
@@ -1,39 +1,45 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:25:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:27:1
+  --> $DIR/unsupported.rs:32:1
    |
 LL | extern "amdgpu-kernel" fn amdgpu() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:29:1
+  --> $DIR/unsupported.rs:34:1
    |
 LL | extern "wasm" fn wasm() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:31:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:35:1
+  --> $DIR/unsupported.rs:42:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:37:1
+  --> $DIR/unsupported.rs:44:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 6 previous errors
+error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:46:1
+   |
+LL | extern "riscv-interrupt-m" fn riscv() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.riscv32.stderr b/tests/ui/abi/unsupported.riscv32.stderr
new file mode 100644
index 00000000000..1966e18f0a0
--- /dev/null
+++ b/tests/ui/abi/unsupported.riscv32.stderr
@@ -0,0 +1,61 @@
+error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:30:1
+   |
+LL | extern "ptx-kernel" fn ptx() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:32:1
+   |
+LL | extern "amdgpu-kernel" fn amdgpu() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"wasm"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:34:1
+   |
+LL | extern "wasm" fn wasm() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"aapcs"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:36:1
+   |
+LL | extern "aapcs" fn aapcs() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:42:1
+   |
+LL | extern "msp430-interrupt" fn msp430() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:44:1
+   |
+LL | extern "avr-interrupt" fn avr() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:51:1
+   |
+LL | extern "x86-interrupt" fn x86() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"thiscall"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:56:1
+   |
+LL | extern "thiscall" fn thiscall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:62:1
+   |
+LL | extern "stdcall" fn stdcall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
+
+error: aborting due to 8 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.riscv64.stderr b/tests/ui/abi/unsupported.riscv64.stderr
new file mode 100644
index 00000000000..1966e18f0a0
--- /dev/null
+++ b/tests/ui/abi/unsupported.riscv64.stderr
@@ -0,0 +1,61 @@
+error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:30:1
+   |
+LL | extern "ptx-kernel" fn ptx() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:32:1
+   |
+LL | extern "amdgpu-kernel" fn amdgpu() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"wasm"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:34:1
+   |
+LL | extern "wasm" fn wasm() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"aapcs"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:36:1
+   |
+LL | extern "aapcs" fn aapcs() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:42:1
+   |
+LL | extern "msp430-interrupt" fn msp430() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:44:1
+   |
+LL | extern "avr-interrupt" fn avr() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"x86-interrupt"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:51:1
+   |
+LL | extern "x86-interrupt" fn x86() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0570]: `"thiscall"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:56:1
+   |
+LL | extern "thiscall" fn thiscall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: use of calling convention not supported on this target
+  --> $DIR/unsupported.rs:62:1
+   |
+LL | extern "stdcall" fn stdcall() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+   = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
+   = note: `#[warn(unsupported_calling_conventions)]` on by default
+
+error: aborting due to 8 previous errors; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/abi/unsupported.rs b/tests/ui/abi/unsupported.rs
index bcd95f1ed4c..57278e664b5 100644
--- a/tests/ui/abi/unsupported.rs
+++ b/tests/ui/abi/unsupported.rs
@@ -1,4 +1,4 @@
-// revisions: x64 i686 aarch64 arm
+// revisions: x64 i686 aarch64 arm riscv32 riscv64
 //
 // [x64] needs-llvm-components: x86
 // [x64] compile-flags: --target=x86_64-unknown-linux-gnu --crate-type=rlib
@@ -8,6 +8,10 @@
 // [aarch64] compile-flags: --target=aarch64-unknown-linux-gnu --crate-type=rlib
 // [arm] needs-llvm-components: arm
 // [arm] compile-flags: --target=armv7-unknown-linux-gnueabihf --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
 #![no_core]
 #![feature(
     no_core,
@@ -17,10 +21,11 @@
     abi_avr_interrupt,
     abi_amdgpu_kernel,
     wasm_abi,
-    abi_x86_interrupt
+    abi_x86_interrupt,
+    abi_riscv_interrupt
 )]
-#[lang="sized"]
-trait Sized { }
+#[lang = "sized"]
+trait Sized {}
 
 extern "ptx-kernel" fn ptx() {}
 //~^ ERROR is not a supported ABI
@@ -32,21 +37,36 @@ extern "aapcs" fn aapcs() {}
 //[x64]~^ ERROR is not a supported ABI
 //[i686]~^^ ERROR is not a supported ABI
 //[aarch64]~^^^ ERROR is not a supported ABI
+//[riscv32]~^^^^ ERROR is not a supported ABI
+//[riscv64]~^^^^^ ERROR is not a supported ABI
 extern "msp430-interrupt" fn msp430() {}
 //~^ ERROR is not a supported ABI
 extern "avr-interrupt" fn avr() {}
 //~^ ERROR is not a supported ABI
+extern "riscv-interrupt-m" fn riscv() {}
+//[arm]~^ ERROR is not a supported ABI
+//[x64]~^^ ERROR is not a supported ABI
+//[i686]~^^^ ERROR is not a supported ABI
+//[aarch64]~^^^^ ERROR is not a supported ABI
 extern "x86-interrupt" fn x86() {}
 //[aarch64]~^ ERROR is not a supported ABI
 //[arm]~^^ ERROR is not a supported ABI
+//[riscv32]~^^^ ERROR is not a supported ABI
+//[riscv64]~^^^^ ERROR is not a supported ABI
 extern "thiscall" fn thiscall() {}
 //[x64]~^ ERROR is not a supported ABI
-//[aarch64]~^^ ERROR is not a supported ABI
-//[arm]~^^^ ERROR is not a supported ABI
+//[arm]~^^ ERROR is not a supported ABI
+//[aarch64]~^^^ ERROR is not a supported ABI
+//[riscv32]~^^^^ ERROR is not a supported ABI
+//[riscv64]~^^^^^ ERROR is not a supported ABI
 extern "stdcall" fn stdcall() {}
 //[x64]~^ WARN use of calling convention not supported
 //[x64]~^^ WARN this was previously accepted
-//[aarch64]~^^^ WARN use of calling convention not supported
-//[aarch64]~^^^^ WARN this was previously accepted
-//[arm]~^^^^^ WARN use of calling convention not supported
-//[arm]~^^^^^^ WARN this was previously accepted
+//[arm]~^^^ WARN use of calling convention not supported
+//[arm]~^^^^ WARN this was previously accepted
+//[aarch64]~^^^^^ WARN use of calling convention not supported
+//[aarch64]~^^^^^^ WARN this was previously accepted
+//[riscv32]~^^^^^^^ WARN use of calling convention not supported
+//[riscv32]~^^^^^^^^ WARN this was previously accepted
+//[riscv64]~^^^^^^^^^ WARN use of calling convention not supported
+//[riscv64]~^^^^^^^^^^ WARN this was previously accepted
diff --git a/tests/ui/abi/unsupported.x64.stderr b/tests/ui/abi/unsupported.x64.stderr
index 29eed8505b9..ea62cb15148 100644
--- a/tests/ui/abi/unsupported.x64.stderr
+++ b/tests/ui/abi/unsupported.x64.stderr
@@ -1,47 +1,53 @@
 error[E0570]: `"ptx-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:25:1
+  --> $DIR/unsupported.rs:30:1
    |
 LL | extern "ptx-kernel" fn ptx() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"amdgpu-kernel"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:27:1
+  --> $DIR/unsupported.rs:32:1
    |
 LL | extern "amdgpu-kernel" fn amdgpu() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"wasm"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:29:1
+  --> $DIR/unsupported.rs:34:1
    |
 LL | extern "wasm" fn wasm() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"aapcs"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:31:1
+  --> $DIR/unsupported.rs:36:1
    |
 LL | extern "aapcs" fn aapcs() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"msp430-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:35:1
+  --> $DIR/unsupported.rs:42:1
    |
 LL | extern "msp430-interrupt" fn msp430() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error[E0570]: `"avr-interrupt"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:37:1
+  --> $DIR/unsupported.rs:44:1
    |
 LL | extern "avr-interrupt" fn avr() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+error[E0570]: `"riscv-interrupt-m"` is not a supported ABI for the current target
+  --> $DIR/unsupported.rs:46:1
+   |
+LL | extern "riscv-interrupt-m" fn riscv() {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
 error[E0570]: `"thiscall"` is not a supported ABI for the current target
-  --> $DIR/unsupported.rs:42:1
+  --> $DIR/unsupported.rs:56:1
    |
 LL | extern "thiscall" fn thiscall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: use of calling convention not supported on this target
-  --> $DIR/unsupported.rs:46:1
+  --> $DIR/unsupported.rs:62:1
    |
 LL | extern "stdcall" fn stdcall() {}
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -50,6 +56,6 @@ LL | extern "stdcall" fn stdcall() {}
    = note: for more information, see issue #87678 <https://github.com/rust-lang/rust/issues/87678>
    = note: `#[warn(unsupported_calling_conventions)]` on by default
 
-error: aborting due to 7 previous errors; 1 warning emitted
+error: aborting due to 8 previous errors; 1 warning emitted
 
 For more information about this error, try `rustc --explain E0570`.
diff --git a/tests/ui/feature-gates/feature-gate-abi-riscv-interrupt.rs b/tests/ui/feature-gates/feature-gate-abi-riscv-interrupt.rs
new file mode 100644
index 00000000000..7755a46da3b
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-abi-riscv-interrupt.rs
@@ -0,0 +1,33 @@
+// needs-llvm-components: riscv
+// compile-flags: --target=riscv32imc-unknown-none-elf --crate-type=rlib
+#![no_core]
+#![feature(no_core, lang_items)]
+#[lang = "sized"]
+trait Sized {}
+
+// Test that the riscv interrupt ABIs cannot be used when riscv_interrupt
+// feature gate is not used.
+
+extern "riscv-interrupt-m" fn f() {}
+//~^ ERROR riscv-interrupt ABIs are experimental
+extern "riscv-interrupt-s" fn f_s() {}
+//~^ ERROR riscv-interrupt ABIs are experimental
+
+trait T {
+    extern "riscv-interrupt-m" fn m();
+    //~^ ERROR riscv-interrupt ABIs are experimental
+}
+
+struct S;
+impl T for S {
+    extern "riscv-interrupt-m" fn m() {}
+    //~^ ERROR riscv-interrupt ABIs are experimental
+}
+
+impl S {
+    extern "riscv-interrupt-m" fn im() {}
+    //~^ ERROR riscv-interrupt ABIs are experimental
+}
+
+type TA = extern "riscv-interrupt-m" fn();
+//~^ ERROR riscv-interrupt ABIs are experimental
diff --git a/tests/ui/feature-gates/feature-gate-abi-riscv-interrupt.stderr b/tests/ui/feature-gates/feature-gate-abi-riscv-interrupt.stderr
new file mode 100644
index 00000000000..60c7fa0ea67
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-abi-riscv-interrupt.stderr
@@ -0,0 +1,57 @@
+error[E0658]: riscv-interrupt ABIs are experimental and subject to change
+  --> $DIR/feature-gate-abi-riscv-interrupt.rs:11:8
+   |
+LL | extern "riscv-interrupt-m" fn f() {}
+   |        ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #111889 <https://github.com/rust-lang/rust/issues/111889> for more information
+   = help: add `#![feature(abi_riscv_interrupt)]` to the crate attributes to enable
+
+error[E0658]: riscv-interrupt ABIs are experimental and subject to change
+  --> $DIR/feature-gate-abi-riscv-interrupt.rs:13:8
+   |
+LL | extern "riscv-interrupt-s" fn f_s() {}
+   |        ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #111889 <https://github.com/rust-lang/rust/issues/111889> for more information
+   = help: add `#![feature(abi_riscv_interrupt)]` to the crate attributes to enable
+
+error[E0658]: riscv-interrupt ABIs are experimental and subject to change
+  --> $DIR/feature-gate-abi-riscv-interrupt.rs:17:12
+   |
+LL |     extern "riscv-interrupt-m" fn m();
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #111889 <https://github.com/rust-lang/rust/issues/111889> for more information
+   = help: add `#![feature(abi_riscv_interrupt)]` to the crate attributes to enable
+
+error[E0658]: riscv-interrupt ABIs are experimental and subject to change
+  --> $DIR/feature-gate-abi-riscv-interrupt.rs:23:12
+   |
+LL |     extern "riscv-interrupt-m" fn m() {}
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #111889 <https://github.com/rust-lang/rust/issues/111889> for more information
+   = help: add `#![feature(abi_riscv_interrupt)]` to the crate attributes to enable
+
+error[E0658]: riscv-interrupt ABIs are experimental and subject to change
+  --> $DIR/feature-gate-abi-riscv-interrupt.rs:28:12
+   |
+LL |     extern "riscv-interrupt-m" fn im() {}
+   |            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #111889 <https://github.com/rust-lang/rust/issues/111889> for more information
+   = help: add `#![feature(abi_riscv_interrupt)]` to the crate attributes to enable
+
+error[E0658]: riscv-interrupt ABIs are experimental and subject to change
+  --> $DIR/feature-gate-abi-riscv-interrupt.rs:32:18
+   |
+LL | type TA = extern "riscv-interrupt-m" fn();
+   |                  ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #111889 <https://github.com/rust-lang/rust/issues/111889> for more information
+   = help: add `#![feature(abi_riscv_interrupt)]` to the crate attributes to enable
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0658`.