about summary refs log tree commit diff
path: root/tests/run-make/extern-fn-struct-passing-abi/test.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/run-make/extern-fn-struct-passing-abi/test.rs')
-rw-r--r--tests/run-make/extern-fn-struct-passing-abi/test.rs138
1 files changed, 138 insertions, 0 deletions
diff --git a/tests/run-make/extern-fn-struct-passing-abi/test.rs b/tests/run-make/extern-fn-struct-passing-abi/test.rs
new file mode 100644
index 00000000000..afe0f52ef0b
--- /dev/null
+++ b/tests/run-make/extern-fn-struct-passing-abi/test.rs
@@ -0,0 +1,138 @@
+// Passing structs via FFI should work regardless of whether
+// they get passed in multiple registers, byval pointers or the stack
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct Rect {
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct BiggerRect {
+    s: Rect,
+    a: i32,
+    b: i32,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct FloatRect {
+    a: i32,
+    b: i32,
+    c: f64,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct Huge {
+    a: i32,
+    b: i32,
+    c: i32,
+    d: i32,
+    e: i32,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct FloatPoint {
+    x: f64,
+    y: f64,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct FloatOne {
+    x: f64,
+}
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+#[repr(C)]
+struct IntOdd {
+    a: i8,
+    b: i8,
+    c: i8,
+}
+
+#[link(name = "test", kind = "static")]
+extern "C" {
+    fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect);
+
+    fn byval_many_rect(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, s: Rect);
+
+    fn byval_rect_floats(
+        a: f32,
+        b: f32,
+        c: f64,
+        d: f32,
+        e: f32,
+        f: f32,
+        g: f64,
+        s: Rect,
+        t: FloatRect,
+    );
+
+    fn byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect);
+
+    fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect);
+
+    fn split_rect(a: i32, b: i32, s: Rect);
+
+    fn split_rect_floats(a: f32, b: f32, s: FloatRect);
+
+    fn split_rect_with_floats(a: i32, b: i32, c: f32, d: i32, e: f32, f: i32, s: Rect);
+
+    fn split_and_byval_rect(a: i32, b: i32, c: i32, s: Rect, t: Rect);
+
+    fn split_ret_byval_struct(a: i32, b: i32, s: Rect) -> Rect;
+
+    fn sret_byval_struct(a: i32, b: i32, c: i32, d: i32, s: Rect) -> BiggerRect;
+
+    fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect;
+
+    fn huge_struct(s: Huge) -> Huge;
+
+    fn float_point(p: FloatPoint) -> FloatPoint;
+
+    fn float_one(f: FloatOne) -> FloatOne;
+
+    fn int_odd(i: IntOdd) -> IntOdd;
+}
+
+fn main() {
+    let s = Rect { a: 553, b: 554, c: 555, d: 556 };
+    let t = BiggerRect { s: s, a: 27834, b: 7657 };
+    let u = FloatRect { a: 3489, b: 3490, c: 8. };
+    let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 };
+    let p = FloatPoint { x: 5., y: -3. };
+    let f1 = FloatOne { x: 7. };
+    let i = IntOdd { a: 1, b: 2, c: 3 };
+
+    unsafe {
+        byval_rect(1, 2, 3, 4, 5, s);
+        byval_many_rect(1, 2, 3, 4, 5, 6, s);
+        byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u);
+        byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s);
+        byval_rect_with_many_huge(v, v, v, v, v, v, Rect { a: 123, b: 456, c: 789, d: 420 });
+        split_rect(1, 2, s);
+        split_rect_floats(1., 2., u);
+        split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s);
+        split_and_byval_rect(1, 2, 3, s, s);
+        split_rect(1, 2, s);
+        assert_eq!(huge_struct(v), v);
+        assert_eq!(split_ret_byval_struct(1, 2, s), s);
+        assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t);
+        assert_eq!(sret_split_struct(1, 2, s), t);
+        assert_eq!(float_point(p), p);
+        assert_eq!(int_odd(i), i);
+
+        // MSVC/GCC/Clang are not consistent in the ABI of single-float aggregates.
+        // x86_64: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028
+        // i686: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82041
+        #[cfg(not(all(windows, target_env = "gnu")))]
+        assert_eq!(float_one(f1), f1);
+    }
+}