1 // Passing structs via FFI should work regardless of whether
2 // they get passed in multiple registers, byval pointers or the stack
3
4 #[derive(Clone, Copy, Debug, PartialEq)]
5 #[repr(C)]
6 struct Rect {
7 a: i32,
8 b: i32,
9 c: i32,
10 d: i32,
11 }
12
13 #[derive(Clone, Copy, Debug, PartialEq)]
14 #[repr(C)]
15 struct BiggerRect {
16 s: Rect,
17 a: i32,
18 b: i32,
19 }
20
21 #[derive(Clone, Copy, Debug, PartialEq)]
22 #[repr(C)]
23 struct FloatRect {
24 a: i32,
25 b: i32,
26 c: f64,
27 }
28
29 #[derive(Clone, Copy, Debug, PartialEq)]
30 #[repr(C)]
31 struct Huge {
32 a: i32,
33 b: i32,
34 c: i32,
35 d: i32,
36 e: i32,
37 }
38
39 #[derive(Clone, Copy, Debug, PartialEq)]
40 #[repr(C)]
41 struct FloatPoint {
42 x: f64,
43 y: f64,
44 }
45
46 #[derive(Clone, Copy, Debug, PartialEq)]
47 #[repr(C)]
48 struct FloatOne {
49 x: f64,
50 }
51
52 #[derive(Clone, Copy, Debug, PartialEq)]
53 #[repr(C)]
54 struct IntOdd {
55 a: i8,
56 b: i8,
57 c: i8,
58 }
59
60 #[link(name = "test", kind = "static")]
61 extern "C" {
byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect)62 fn byval_rect(a: i32, b: i32, c: i32, d: i32, e: i32, s: Rect);
63
byval_many_rect(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, s: Rect)64 fn byval_many_rect(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, s: Rect);
65
byval_rect_floats( a: f32, b: f32, c: f64, d: f32, e: f32, f: f32, g: f64, s: Rect, t: FloatRect, )66 fn byval_rect_floats(
67 a: f32,
68 b: f32,
69 c: f64,
70 d: f32,
71 e: f32,
72 f: f32,
73 g: f64,
74 s: Rect,
75 t: FloatRect,
76 );
77
byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect)78 fn byval_rect_with_float(a: i32, b: i32, c: f32, d: i32, e: i32, f: i32, s: Rect);
79
byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect)80 fn byval_rect_with_many_huge(a: Huge, b: Huge, c: Huge, d: Huge, e: Huge, f: Huge, g: Rect);
81
split_rect(a: i32, b: i32, s: Rect)82 fn split_rect(a: i32, b: i32, s: Rect);
83
split_rect_floats(a: f32, b: f32, s: FloatRect)84 fn split_rect_floats(a: f32, b: f32, s: FloatRect);
85
split_rect_with_floats(a: i32, b: i32, c: f32, d: i32, e: f32, f: i32, s: Rect)86 fn split_rect_with_floats(a: i32, b: i32, c: f32, d: i32, e: f32, f: i32, s: Rect);
87
split_and_byval_rect(a: i32, b: i32, c: i32, s: Rect, t: Rect)88 fn split_and_byval_rect(a: i32, b: i32, c: i32, s: Rect, t: Rect);
89
split_ret_byval_struct(a: i32, b: i32, s: Rect) -> Rect90 fn split_ret_byval_struct(a: i32, b: i32, s: Rect) -> Rect;
91
sret_byval_struct(a: i32, b: i32, c: i32, d: i32, s: Rect) -> BiggerRect92 fn sret_byval_struct(a: i32, b: i32, c: i32, d: i32, s: Rect) -> BiggerRect;
93
sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect94 fn sret_split_struct(a: i32, b: i32, s: Rect) -> BiggerRect;
95
huge_struct(s: Huge) -> Huge96 fn huge_struct(s: Huge) -> Huge;
97
float_point(p: FloatPoint) -> FloatPoint98 fn float_point(p: FloatPoint) -> FloatPoint;
99
float_one(f: FloatOne) -> FloatOne100 fn float_one(f: FloatOne) -> FloatOne;
101
int_odd(i: IntOdd) -> IntOdd102 fn int_odd(i: IntOdd) -> IntOdd;
103 }
104
main()105 fn main() {
106 let s = Rect { a: 553, b: 554, c: 555, d: 556 };
107 let t = BiggerRect { s: s, a: 27834, b: 7657 };
108 let u = FloatRect { a: 3489, b: 3490, c: 8. };
109 let v = Huge { a: 5647, b: 5648, c: 5649, d: 5650, e: 5651 };
110 let p = FloatPoint { x: 5., y: -3. };
111 let f1 = FloatOne { x: 7. };
112 let i = IntOdd { a: 1, b: 2, c: 3 };
113
114 unsafe {
115 byval_rect(1, 2, 3, 4, 5, s);
116 byval_many_rect(1, 2, 3, 4, 5, 6, s);
117 byval_rect_floats(1., 2., 3., 4., 5., 6., 7., s, u);
118 byval_rect_with_float(1, 2, 3.0, 4, 5, 6, s);
119 byval_rect_with_many_huge(v, v, v, v, v, v, Rect { a: 123, b: 456, c: 789, d: 420 });
120 split_rect(1, 2, s);
121 split_rect_floats(1., 2., u);
122 split_rect_with_floats(1, 2, 3.0, 4, 5.0, 6, s);
123 split_and_byval_rect(1, 2, 3, s, s);
124 split_rect(1, 2, s);
125 assert_eq!(huge_struct(v), v);
126 assert_eq!(split_ret_byval_struct(1, 2, s), s);
127 assert_eq!(sret_byval_struct(1, 2, 3, 4, s), t);
128 assert_eq!(sret_split_struct(1, 2, s), t);
129 assert_eq!(float_point(p), p);
130 assert_eq!(int_odd(i), i);
131
132 // MSVC/GCC/Clang are not consistent in the ABI of single-float aggregates.
133 // x86_64: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82028
134 // i686: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82041
135 #[cfg(not(all(windows, target_env = "gnu")))]
136 assert_eq!(float_one(f1), f1);
137 }
138 }
139