about summary refs log tree commit diff
path: root/tests/ui/abi/custom.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/abi/custom.rs')
-rw-r--r--tests/ui/abi/custom.rs88
1 files changed, 88 insertions, 0 deletions
diff --git a/tests/ui/abi/custom.rs b/tests/ui/abi/custom.rs
new file mode 100644
index 00000000000..0f6ff77f580
--- /dev/null
+++ b/tests/ui/abi/custom.rs
@@ -0,0 +1,88 @@
+// Test that `extern "custom"` functions can be called from assembly, and defined using a naked
+// function, and `global_asm!` with an `extern "custom"` block.
+//
+//@ run-pass
+//@ only-x86_64
+#![feature(abi_custom)]
+
+use std::arch::{asm, global_asm, naked_asm};
+
+#[unsafe(naked)]
+unsafe extern "custom" fn double() {
+    naked_asm!("add rax, rax", "ret");
+}
+
+global_asm!(
+    // work around macOS prefixing symbols with _
+    "    .globl  {0}",
+    "{0}:",
+    "    add     rax, 1",
+    "    ret",
+    sym increment,
+);
+
+unsafe extern "custom" {
+    fn increment();
+}
+
+#[repr(transparent)]
+struct Thing(u64);
+
+impl Thing {
+    #[unsafe(naked)]
+    unsafe extern "custom" fn is_even() {
+        naked_asm!("test al, 1", "sete al", "ret");
+    }
+}
+
+trait BitwiseNot {
+    #[unsafe(naked)]
+    unsafe extern "custom" fn bitwise_not() {
+        naked_asm!("not rax", "ret");
+    }
+}
+
+impl BitwiseNot for Thing {}
+
+#[unsafe(naked)]
+unsafe extern "C" fn const_generic<const N: u64>() {
+    naked_asm!(
+        "mov rax, {}",
+        "ret",
+        const N,
+    );
+}
+
+pub fn main() {
+    let mut x: u64 = 21;
+    unsafe { asm!("call {}", sym double, inout("rax") x) };
+    assert_eq!(x, 42);
+
+    let mut x: u64 = 41;
+    unsafe { asm!("call {}", sym increment, inout("rax") x) };
+    assert_eq!(x, 42);
+
+    let mut x: u8;
+    unsafe { asm!("call {}", sym Thing::is_even, inout("al") 42u8 => x) };
+    assert!(x != 0);
+
+    let mut x: u64 = 42;
+    unsafe { asm!("call {}", sym Thing::bitwise_not, inout("rax") x) };
+    assert_eq!(x, !42);
+
+    // Create and call in `asm!` an `extern "custom"` function pointer.
+    fn caller(f: unsafe extern "custom" fn(), mut x: u64) -> u64 {
+        unsafe { asm!("call {}", in(reg) f, inout("rax") x) };
+        x
+    }
+
+    assert_eq!(caller(double, 2), 4);
+
+    let x: u64;
+    unsafe { asm!("call {}", sym const_generic::<42>, out("rax") x) };
+    assert_eq!(x, 42);
+
+    let x: u64;
+    unsafe { asm!("call {}", sym const_generic::<84>, out("rax") x) };
+    assert_eq!(x, 84);
+}