Change:
I'm interfacing an external DLL which I'm creating with Visual Studio 2012. I've tried to pass a struct by-value from C to Rust in a callback. The struct and the callback are defined as follows: However the struct received in is corrupted and contains not the data which is sent in C++. I wrote a test program to isolate and reproduce the issue. The gist therefore is here: It can be cloned from It includes the source code for the library with a visual studio project to built it and the rust test program. I also included to build it on Linux. However in Linux I can't reproduct the issue. The struct get's copied correctly there. This is the output from my test program: The first line is the content of the notification in bytes in C++, the second the content in Rust. You can see that the last bytes of the notification structure are different in C++ in Rust. Interesting hereby is also that the last field ( == 9) gets copied into notification.valueid.d (verified this with using other values for ) and the remaining notification fields are garbage.
on IRC mentioned that this could be related to However I'm not sure because that issue is about structs as return values. In my case the struct is a function argument and not the return value.
Issue is also similar. However I could successfully pass structs from Rust to C before - but mine didn't contain u8 values but only pointers and i32/u32 values. Maybe the issue is related to u8/i8 types in structs? Because in my example the problem also exists at the first u8 location.
Update: As on IRC suggested I have created a more compact example and included LLVM IR: The error happens on all structs with more than a single u8 or u16 value. The new test tests are passing a struct with 4 u8 or 4 u16 parameters from Rust to C as well as from C to Rust. I also switched the C side from a C++ project with extern C declarations to a pure C project, so that this issue can be ruled out.
You can bypass the problem by using external LLVM to compile bitcode. I wrote small utility to do that: , and it worked with rsfml.

Discussion:
/// LLVM type or by coercing to another specified type Direct, /// Pass the argument indirectly via a hidden pointer <del> Indirect </del> <ins> Indirect, /// Ignore the argument (useful for empty struct) Ignore, </ins> } /// Information about how a specific C type

} } <ins> pub fn ignore(ty: Type) -> ArgType { ArgType { kind: Ignore, ty: ty, cast: None, pad: None, attr: None, } } </ins> pub fn is_direct(&self) -> bool { return self.kind == Direct; }

pub fn is_indirect(&self) -> bool { return self.kind == Indirect; } <ins> pub fn is_ignore(&self) -> bool { return self.kind == Ignore; } </ins> } /// Metadata describing how the arguments to a native function

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

for (i, &llarg_rust) in llargs_rust.iter().enumerate() { let mut llarg_rust = llarg_rust; <ins> if arg_tys[i].is_ignore() { continue; } </ins> // Does Rust pass this argument by pointer? let rust_indirect = type_of::arg_is_indirect(ccx, *passed_arg_tys.get(i));

}; for &arg_ty in tys.fn_ty.arg_tys.iter() { <ins> if arg_ty.is_ignore() { continue; } </ins> // add padding match arg_ty.pad { Some(ty) => llargument_tys.push(ty),

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

return u; } <ins> 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); } </ins> intptr_t rust_get_test_int() { return 1;

<ins> // 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); } } </ins>