about summary refs log tree commit diff
path: root/tests/codegen-llvm/cffi
diff options
context:
space:
mode:
authorGuillaume Gomez <guillaume1.gomez@gmail.com>2025-07-21 14:34:12 +0200
committerGuillaume Gomez <guillaume1.gomez@gmail.com>2025-07-22 14:28:48 +0200
commita27f3e3fd1e4d16160f8885b6b06665b5319f56c (patch)
treeb033935392cbadf6f85d2dbddf433a88e323aeeb /tests/codegen-llvm/cffi
parented93c1783b404d728d4809973a0550eb33cd293f (diff)
downloadrust-a27f3e3fd1e4d16160f8885b6b06665b5319f56c.tar.gz
rust-a27f3e3fd1e4d16160f8885b6b06665b5319f56c.zip
Rename `tests/codegen` into `tests/codegen-llvm`
Diffstat (limited to 'tests/codegen-llvm/cffi')
-rw-r--r--tests/codegen-llvm/cffi/c-variadic-copy.rs16
-rw-r--r--tests/codegen-llvm/cffi/c-variadic-naked.rs15
-rw-r--r--tests/codegen-llvm/cffi/c-variadic-opt.rs30
-rw-r--r--tests/codegen-llvm/cffi/c-variadic.rs71
-rw-r--r--tests/codegen-llvm/cffi/ffi-const.rs15
-rw-r--r--tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs41
-rw-r--r--tests/codegen-llvm/cffi/ffi-pure.rs15
7 files changed, 203 insertions, 0 deletions
diff --git a/tests/codegen-llvm/cffi/c-variadic-copy.rs b/tests/codegen-llvm/cffi/c-variadic-copy.rs
new file mode 100644
index 00000000000..4c61c4fcf68
--- /dev/null
+++ b/tests/codegen-llvm/cffi/c-variadic-copy.rs
@@ -0,0 +1,16 @@
+// Tests that `VaListImpl::clone` gets inlined into a call to `llvm.va_copy`
+
+#![crate_type = "lib"]
+#![feature(c_variadic)]
+#![no_std]
+use core::ffi::VaList;
+
+extern "C" {
+    fn foreign_c_variadic_1(_: VaList, ...);
+}
+
+pub unsafe extern "C" fn clone_variadic(ap: VaList) {
+    let mut ap2 = ap.clone();
+    // CHECK: call void @llvm.va_copy
+    foreign_c_variadic_1(ap2.as_va_list(), 42i32);
+}
diff --git a/tests/codegen-llvm/cffi/c-variadic-naked.rs b/tests/codegen-llvm/cffi/c-variadic-naked.rs
new file mode 100644
index 00000000000..5843628b633
--- /dev/null
+++ b/tests/codegen-llvm/cffi/c-variadic-naked.rs
@@ -0,0 +1,15 @@
+//@ needs-asm-support
+//@ only-x86_64
+
+// tests that `va_start` is not injected into naked functions
+
+#![crate_type = "lib"]
+#![feature(c_variadic)]
+#![no_std]
+
+#[unsafe(naked)]
+pub unsafe extern "C" fn c_variadic(_: usize, _: ...) {
+    // CHECK-NOT: va_start
+    // CHECK-NOT: alloca
+    core::arch::naked_asm!("ret")
+}
diff --git a/tests/codegen-llvm/cffi/c-variadic-opt.rs b/tests/codegen-llvm/cffi/c-variadic-opt.rs
new file mode 100644
index 00000000000..7e544ee7f37
--- /dev/null
+++ b/tests/codegen-llvm/cffi/c-variadic-opt.rs
@@ -0,0 +1,30 @@
+//@ compile-flags: -C opt-level=3
+
+#![crate_type = "lib"]
+#![feature(c_variadic)]
+#![no_std]
+use core::ffi::VaList;
+
+extern "C" {
+    fn vprintf(fmt: *const i8, ap: VaList) -> i32;
+}
+
+// Ensure that `va_start` and `va_end` are properly injected even
+// when the "spoofed" `VaListImpl` is not used.
+#[no_mangle]
+pub unsafe extern "C" fn c_variadic_no_use(fmt: *const i8, mut ap: ...) -> i32 {
+    // CHECK: call void @llvm.va_start
+    vprintf(fmt, ap.as_va_list())
+    // CHECK: call void @llvm.va_end
+}
+
+// Check that `VaListImpl::clone` gets inlined into a direct call to `llvm.va_copy`
+#[no_mangle]
+pub unsafe extern "C" fn c_variadic_clone(fmt: *const i8, mut ap: ...) -> i32 {
+    // CHECK: call void @llvm.va_start
+    let mut ap2 = ap.clone();
+    // CHECK: call void @llvm.va_copy
+    let res = vprintf(fmt, ap2.as_va_list());
+    res
+    // CHECK: call void @llvm.va_end
+}
diff --git a/tests/codegen-llvm/cffi/c-variadic.rs b/tests/codegen-llvm/cffi/c-variadic.rs
new file mode 100644
index 00000000000..140d2f37f46
--- /dev/null
+++ b/tests/codegen-llvm/cffi/c-variadic.rs
@@ -0,0 +1,71 @@
+//@ needs-unwind
+//@ compile-flags: -C no-prepopulate-passes -Copt-level=0
+//
+
+#![crate_type = "lib"]
+#![feature(c_variadic)]
+#![no_std]
+use core::ffi::VaList;
+
+extern "C" {
+    fn foreign_c_variadic_0(_: i32, ...);
+    fn foreign_c_variadic_1(_: VaList, ...);
+}
+
+pub unsafe extern "C" fn use_foreign_c_variadic_0() {
+    // Ensure that we correctly call foreign C-variadic functions.
+    // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM:i32( signext)?]] 0)
+    foreign_c_variadic_0(0);
+    // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42)
+    foreign_c_variadic_0(0, 42i32);
+    // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024)
+    foreign_c_variadic_0(0, 42i32, 1024i32);
+    // CHECK: call void (i32, ...) @foreign_c_variadic_0([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0)
+    foreign_c_variadic_0(0, 42i32, 1024i32, 0i32);
+}
+
+// Ensure that we do not remove the `va_list` passed to the foreign function when
+// removing the "spoofed" `VaListImpl` that is used by Rust defined C-variadics.
+pub unsafe extern "C" fn use_foreign_c_variadic_1_0(ap: VaList) {
+    // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap)
+    foreign_c_variadic_1(ap);
+}
+
+pub unsafe extern "C" fn use_foreign_c_variadic_1_1(ap: VaList) {
+    // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 42)
+    foreign_c_variadic_1(ap, 42i32);
+}
+pub unsafe extern "C" fn use_foreign_c_variadic_1_2(ap: VaList) {
+    // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42)
+    foreign_c_variadic_1(ap, 2i32, 42i32);
+}
+
+pub unsafe extern "C" fn use_foreign_c_variadic_1_3(ap: VaList) {
+    // CHECK: call void ({{.*}}, ...) @foreign_c_variadic_1({{.*}} %ap, [[PARAM]] 2, [[PARAM]] 42, [[PARAM]] 0)
+    foreign_c_variadic_1(ap, 2i32, 42i32, 0i32);
+}
+
+// Ensure that `va_start` and `va_end` are properly injected.
+#[no_mangle]
+pub unsafe extern "C" fn c_variadic(n: i32, mut ap: ...) -> i32 {
+    // CHECK: call void @llvm.va_start
+    let mut sum = 0;
+    for _ in 0..n {
+        sum += ap.arg::<i32>();
+    }
+    sum
+    // CHECK: call void @llvm.va_end
+}
+
+// Ensure that we generate the correct `call` signature when calling a Rust
+// defined C-variadic.
+pub unsafe fn test_c_variadic_call() {
+    // CHECK: call [[RET:(signext )?i32]] (i32, ...) @c_variadic([[PARAM]] 0)
+    c_variadic(0);
+    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42)
+    c_variadic(0, 42i32);
+    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024)
+    c_variadic(0, 42i32, 1024i32);
+    // CHECK: call [[RET]] (i32, ...) @c_variadic([[PARAM]] 0, [[PARAM]] 42, [[PARAM]] 1024, [[PARAM]] 0)
+    c_variadic(0, 42i32, 1024i32, 0i32);
+}
diff --git a/tests/codegen-llvm/cffi/ffi-const.rs b/tests/codegen-llvm/cffi/ffi-const.rs
new file mode 100644
index 00000000000..3ea9d517ec2
--- /dev/null
+++ b/tests/codegen-llvm/cffi/ffi-const.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
+#![feature(ffi_const)]
+
+pub fn bar() {
+    unsafe { foo() }
+}
+
+extern "C" {
+    // CHECK-LABEL: declare{{.*}}void @foo()
+    // CHECK-SAME: [[ATTRS:#[0-9]+]]
+    // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(none){{.*}} }
+    #[unsafe(ffi_const)]
+    pub fn foo();
+}
diff --git a/tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs b/tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs
new file mode 100644
index 00000000000..859386d2df8
--- /dev/null
+++ b/tests/codegen-llvm/cffi/ffi-out-of-bounds-loads.rs
@@ -0,0 +1,41 @@
+//@ add-core-stubs
+//@ revisions: linux apple
+//@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes -Zlint-llvm-ir
+
+//@[linux] compile-flags: --target x86_64-unknown-linux-gnu
+//@[linux] needs-llvm-components: x86
+//@[apple] compile-flags: --target x86_64-apple-darwin
+//@[apple] needs-llvm-components: x86
+
+// Regression test for #29988
+
+#![feature(no_core, lang_items)]
+#![crate_type = "lib"]
+#![no_std]
+#![no_core]
+
+extern crate minicore;
+use minicore::*;
+
+#[repr(C)]
+struct S {
+    f1: i32,
+    f2: i32,
+    f3: i32,
+}
+
+extern "C" {
+    fn foo(s: S);
+}
+
+// CHECK-LABEL: @test
+#[no_mangle]
+pub fn test() {
+    let s = S { f1: 1, f2: 2, f3: 3 };
+    unsafe {
+        // CHECK: [[ALLOCA:%.+]] = alloca [16 x i8], align 8
+        // CHECK: [[LOAD:%.+]] = load { i64, i32 }, ptr [[ALLOCA]], align 8
+        // CHECK: call void @foo({ i64, i32 } [[LOAD]])
+        foo(s);
+    }
+}
diff --git a/tests/codegen-llvm/cffi/ffi-pure.rs b/tests/codegen-llvm/cffi/ffi-pure.rs
new file mode 100644
index 00000000000..a61e80ecf65
--- /dev/null
+++ b/tests/codegen-llvm/cffi/ffi-pure.rs
@@ -0,0 +1,15 @@
+//@ compile-flags: -C no-prepopulate-passes
+#![crate_type = "lib"]
+#![feature(ffi_pure)]
+
+pub fn bar() {
+    unsafe { foo() }
+}
+
+extern "C" {
+    // CHECK-LABEL: declare{{.*}}void @foo()
+    // CHECK-SAME: [[ATTRS:#[0-9]+]]
+    // CHECK-DAG: attributes [[ATTRS]] = { {{.*}}memory(read){{.*}} }
+    #[unsafe(ffi_pure)]
+    pub fn foo();
+}