From 2d31bcaf16453b713d769178c5f6738eb5efbd9d Mon Sep 17 00:00:00 2001 From: klutzy Date: Sun, 9 Mar 2014 15:42:22 +0900 Subject: [PATCH] rustc: Fix x86 ffi for empty struct arguments --- src/librustc/middle/trans/cabi.rs | 18 ++++++++- src/librustc/middle/trans/cabi_x86.rs | 7 +++- src/librustc/middle/trans/foreign.rs | 10 +++++ src/rt/rust_test_helpers.c | 23 +++++++++++ src/test/run-pass/extern-pass-empty.rs | 55 ++++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 src/test/run-pass/extern-pass-empty.rs diff --git a/src/librustc/middle/trans/cabi.rs b/src/librustc/middle/trans/cabi.rs index d760c645441..7e67673d160 100644 --- a/src/librustc/middle/trans/cabi.rs +++ b/src/librustc/middle/trans/cabi.rs @@ -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,6 +70,16 @@ 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; } @@ -75,6 +87,10 @@ impl ArgType { 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 diff --git a/src/librustc/middle/trans/cabi_x86.rs b/src/librustc/middle/trans/cabi_x86.rs index 68d5b898471..85a7c14968f 100644 --- a/src/librustc/middle/trans/cabi_x86.rs +++ b/src/librustc/middle/trans/cabi_x86.rs @@ -66,7 +66,12 @@ pub fn compute_abi_info(ccx: &CrateContext, for &t in atys.iter() { let ty = match t.kind() { Struct => { - ArgType::indirect(t, Some(ByValAttribute)) + 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), }; diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs index 7f6781096f5..74bed116806 100644 --- a/src/librustc/middle/trans/foreign.rs +++ b/src/librustc/middle/trans/foreign.rs @@ -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; } diff --git a/src/rt/rust_test_helpers.c b/src/rt/rust_test_helpers.c index ee328e6cdb5..4d5b95155ca 100644 --- a/src/rt/rust_test_helpers.c +++ b/src/rt/rust_test_helpers.c @@ -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; diff --git a/src/test/run-pass/extern-pass-empty.rs b/src/test/run-pass/extern-pass-empty.rs new file mode 100644 index 00000000000..4c343fdb1a2 --- /dev/null +++ b/src/test/run-pass/extern-pass-empty.rs @@ -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 or the MIT license +// , 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); + } +}