Skip to content

Commit 61d5bc5

Browse files
committed
auto merge of #12762 : klutzy/rust/win-struct-abi, r=alexcrichton
This fixes struct passing abi on x86 ffi: Structs are now passed indirectly with byval attribute (as clang does). Empty structs are also explicitly ignored rather than directly passed. Fixes #5744 Fixes #11198 Fixes #11343
2 parents 8063450 + 2d31bca commit 61d5bc5

File tree

7 files changed

+120
-9
lines changed

7 files changed

+120
-9
lines changed

src/librustc/middle/trans/cabi.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ pub enum ArgKind {
2525
/// LLVM type or by coercing to another specified type
2626
Direct,
2727
/// Pass the argument indirectly via a hidden pointer
28-
Indirect
28+
Indirect,
29+
/// Ignore the argument (useful for empty struct)
30+
Ignore,
2931
}
3032

3133
/// Information about how a specific C type
@@ -68,13 +70,27 @@ impl ArgType {
6870
}
6971
}
7072

73+
pub fn ignore(ty: Type) -> ArgType {
74+
ArgType {
75+
kind: Ignore,
76+
ty: ty,
77+
cast: None,
78+
pad: None,
79+
attr: None,
80+
}
81+
}
82+
7183
pub fn is_direct(&self) -> bool {
7284
return self.kind == Direct;
7385
}
7486

7587
pub fn is_indirect(&self) -> bool {
7688
return self.kind == Indirect;
7789
}
90+
91+
pub fn is_ignore(&self) -> bool {
92+
return self.kind == Ignore;
93+
}
7894
}
7995

8096
/// Metadata describing how the arguments to a native function

src/librustc/middle/trans/cabi_x86.rs

+13-2
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,19 @@ pub fn compute_abi_info(ccx: &CrateContext,
6363
ret_ty = ArgType::direct(rty, None, None, None);
6464
}
6565

66-
for &a in atys.iter() {
67-
arg_tys.push(ArgType::direct(a, None, None, None));
66+
for &t in atys.iter() {
67+
let ty = match t.kind() {
68+
Struct => {
69+
let size = llsize_of_alloc(ccx, t);
70+
if size == 0 {
71+
ArgType::ignore(t)
72+
} else {
73+
ArgType::indirect(t, Some(ByValAttribute))
74+
}
75+
}
76+
_ => ArgType::direct(t, None, None, None),
77+
};
78+
arg_tys.push(ty);
6879
}
6980

7081
return FnType {

src/librustc/middle/trans/foreign.rs

+10
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,10 @@ pub fn trans_native_call<'a>(
325325
for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
326326
let mut llarg_rust = llarg_rust;
327327

328+
if arg_tys[i].is_ignore() {
329+
continue;
330+
}
331+
328332
// Does Rust pass this argument by pointer?
329333
let rust_indirect = type_of::arg_is_indirect(ccx,
330334
*passed_arg_tys.get(i));
@@ -901,6 +905,9 @@ fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> T
901905
};
902906

903907
for &arg_ty in tys.fn_ty.arg_tys.iter() {
908+
if arg_ty.is_ignore() {
909+
continue;
910+
}
904911
// add padding
905912
match arg_ty.pad {
906913
Some(ty) => llargument_tys.push(ty),
@@ -949,6 +956,9 @@ fn add_argument_attributes(tys: &ForeignTypes,
949956
}
950957

951958
for &arg_ty in tys.fn_ty.arg_tys.iter() {
959+
if arg_ty.is_ignore() {
960+
continue;
961+
}
952962
// skip padding
953963
if arg_ty.pad.is_some() { i += 1; }
954964

src/rt/rust_test_helpers.c

+23
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,29 @@ rust_dbg_extern_identity_TwoDoubles(struct TwoDoubles u) {
126126
return u;
127127
}
128128

129+
struct ManyInts {
130+
int8_t arg1;
131+
int16_t arg2;
132+
int32_t arg3;
133+
int16_t arg4;
134+
int8_t arg5;
135+
struct TwoU8s arg6;
136+
};
137+
138+
struct Empty {
139+
};
140+
141+
void
142+
rust_dbg_extern_empty_struct(struct ManyInts v1, struct Empty e, struct ManyInts v2) {
143+
assert(v1.arg1 == v2.arg1 + 1);
144+
assert(v1.arg2 == v2.arg2 + 1);
145+
assert(v1.arg3 == v2.arg3 + 1);
146+
assert(v1.arg4 == v2.arg4 + 1);
147+
assert(v1.arg5 == v2.arg5 + 1);
148+
assert(v1.arg6.one == v2.arg6.one + 1);
149+
assert(v1.arg6.two == v2.arg6.two + 1);
150+
}
151+
129152
intptr_t
130153
rust_get_test_int() {
131154
return 1;

src/test/run-pass/extern-pass-TwoU16s.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// ignore-test #5744 fails on 32 bit
12-
1311
// Test a foreign function that accepts and returns a struct
1412
// by value.
1513

16-
#[deriving(Eq)]
14+
#[deriving(Eq, Show)]
1715
struct TwoU16s {
1816
one: u16, two: u16
1917
}

src/test/run-pass/extern-pass-TwoU8s.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
// ignore-test #5744 fails on 32 bit
12-
1311
// Test a foreign function that accepts and returns a struct
1412
// by value.
1513

16-
#[deriving(Eq)]
14+
#[deriving(Eq, Show)]
1715
struct TwoU8s {
1816
one: u8, two: u8
1917
}
+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// Test a foreign function that accepts empty struct.
12+
13+
struct TwoU8s {
14+
one: u8,
15+
two: u8,
16+
}
17+
18+
struct ManyInts {
19+
arg1: i8,
20+
arg2: i16,
21+
arg3: i32,
22+
arg4: i16,
23+
arg5: i8,
24+
arg6: TwoU8s,
25+
}
26+
27+
struct Empty;
28+
29+
#[link(name = "rustrt")]
30+
extern {
31+
fn rust_dbg_extern_empty_struct(v1: ManyInts, e: Empty, v2: ManyInts);
32+
}
33+
34+
pub fn main() {
35+
unsafe {
36+
let x = ManyInts {
37+
arg1: 2,
38+
arg2: 3,
39+
arg3: 4,
40+
arg4: 5,
41+
arg5: 6,
42+
arg6: TwoU8s { one: 7, two: 8, }
43+
};
44+
let y = ManyInts {
45+
arg1: 1,
46+
arg2: 2,
47+
arg3: 3,
48+
arg4: 4,
49+
arg5: 5,
50+
arg6: TwoU8s { one: 6, two: 7, }
51+
};
52+
let empty = Empty;
53+
rust_dbg_extern_empty_struct(x, empty, y);
54+
}
55+
}

0 commit comments

Comments
 (0)