Skip to content
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

rustc: Fix x86 ffi for struct arguments #12762

Merged
merged 2 commits into from
Mar 19, 2014
Merged
Show file tree
Hide file tree
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
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
15 changes: 13 additions & 2 deletions src/librustc/middle/trans/cabi_x86.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
10 changes: 10 additions & 0 deletions src/librustc/middle/trans/foreign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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; }

Expand Down
23 changes: 23 additions & 0 deletions src/rt/rust_test_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
4 changes: 1 addition & 3 deletions src/test/run-pass/extern-pass-TwoU16s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 1 addition & 3 deletions src/test/run-pass/extern-pass-TwoU8s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
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);
}
}