Skip to content

rustc: Fix x86 ffi for struct arguments #12762

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 19, 2014
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/librustc/middle/trans/cabi.rs
Original file line number Diff line number Diff line change
@@ -25,7 +25,9 @@ pub enum ArgKind {
/// LLVM type or by coercing to another specified type
Direct,
/// Pass the argument indirectly via a hidden pointer
Indirect
Indirect,
/// Ignore the argument (useful for empty struct)
Ignore,
}

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

pub fn ignore(ty: Type) -> ArgType {
ArgType {
kind: Ignore,
ty: ty,
cast: None,
pad: None,
attr: None,
}
}

pub fn is_direct(&self) -> bool {
return self.kind == Direct;
}

pub fn is_indirect(&self) -> bool {
return self.kind == Indirect;
}

pub fn is_ignore(&self) -> bool {
return self.kind == Ignore;
}
}

/// Metadata describing how the arguments to a native function
15 changes: 13 additions & 2 deletions src/librustc/middle/trans/cabi_x86.rs
Original file line number Diff line number Diff line change
@@ -63,8 +63,19 @@ pub fn compute_abi_info(ccx: &CrateContext,
ret_ty = ArgType::direct(rty, None, None, None);
}

for &a in atys.iter() {
arg_tys.push(ArgType::direct(a, None, None, None));
for &t in atys.iter() {
let ty = match t.kind() {
Struct => {
let size = llsize_of_alloc(ccx, t);
if size == 0 {
ArgType::ignore(t)
} else {
ArgType::indirect(t, Some(ByValAttribute))
}
}
_ => ArgType::direct(t, None, None, None),
};
arg_tys.push(ty);
}

return FnType {
10 changes: 10 additions & 0 deletions src/librustc/middle/trans/foreign.rs
Original file line number Diff line number Diff line change
@@ -325,6 +325,10 @@ pub fn trans_native_call<'a>(
for (i, &llarg_rust) in llargs_rust.iter().enumerate() {
let mut llarg_rust = llarg_rust;

if arg_tys[i].is_ignore() {
continue;
}

// Does Rust pass this argument by pointer?
let rust_indirect = type_of::arg_is_indirect(ccx,
*passed_arg_tys.get(i));
@@ -901,6 +905,9 @@ fn lltype_for_fn_from_foreign_types(ccx: &CrateContext, tys: &ForeignTypes) -> T
};

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

for &arg_ty in tys.fn_ty.arg_tys.iter() {
if arg_ty.is_ignore() {
continue;
}
// skip padding
if arg_ty.pad.is_some() { i += 1; }

23 changes: 23 additions & 0 deletions src/rt/rust_test_helpers.c
Original file line number Diff line number Diff line change
@@ -126,6 +126,29 @@ rust_dbg_extern_identity_TwoDoubles(struct TwoDoubles u) {
return u;
}

struct ManyInts {
int8_t arg1;
int16_t arg2;
int32_t arg3;
int16_t arg4;
int8_t arg5;
struct TwoU8s arg6;
};

struct Empty {
};

void
rust_dbg_extern_empty_struct(struct ManyInts v1, struct Empty e, struct ManyInts v2) {
assert(v1.arg1 == v2.arg1 + 1);
assert(v1.arg2 == v2.arg2 + 1);
assert(v1.arg3 == v2.arg3 + 1);
assert(v1.arg4 == v2.arg4 + 1);
assert(v1.arg5 == v2.arg5 + 1);
assert(v1.arg6.one == v2.arg6.one + 1);
assert(v1.arg6.two == v2.arg6.two + 1);
}

intptr_t
rust_get_test_int() {
return 1;
4 changes: 1 addition & 3 deletions src/test/run-pass/extern-pass-TwoU16s.rs
Original file line number Diff line number Diff line change
@@ -8,12 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-test #5744 fails on 32 bit

// Test a foreign function that accepts and returns a struct
// by value.

#[deriving(Eq)]
#[deriving(Eq, Show)]
struct TwoU16s {
one: u16, two: u16
}
4 changes: 1 addition & 3 deletions src/test/run-pass/extern-pass-TwoU8s.rs
Original file line number Diff line number Diff line change
@@ -8,12 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// ignore-test #5744 fails on 32 bit

// Test a foreign function that accepts and returns a struct
// by value.

#[deriving(Eq)]
#[deriving(Eq, Show)]
struct TwoU8s {
one: u8, two: u8
}
55 changes: 55 additions & 0 deletions src/test/run-pass/extern-pass-empty.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// Test a foreign function that accepts empty struct.

struct TwoU8s {
one: u8,
two: u8,
}

struct ManyInts {
arg1: i8,
arg2: i16,
arg3: i32,
arg4: i16,
arg5: i8,
arg6: TwoU8s,
}

struct Empty;

#[link(name = "rustrt")]
extern {
fn rust_dbg_extern_empty_struct(v1: ManyInts, e: Empty, v2: ManyInts);
}

pub fn main() {
unsafe {
let x = ManyInts {
arg1: 2,
arg2: 3,
arg3: 4,
arg4: 5,
arg5: 6,
arg6: TwoU8s { one: 7, two: 8, }
};
let y = ManyInts {
arg1: 1,
arg2: 2,
arg3: 3,
arg4: 4,
arg5: 5,
arg6: TwoU8s { one: 6, two: 7, }
};
let empty = Empty;
rust_dbg_extern_empty_struct(x, empty, y);
}
}