I can replicate this after all. Starting with the vague conclusion:
The struct in question is defined in C++. Rust is calling a function that's inside an extern "C" { }
block. I managed to define my own simplified but illustrative C++ struct, and call my functions. All C functions expect pass by value.
- if the struct is passed as the only parameter, it comes through fine - every variation of the struct I tried.
- if passed as the first of 2 parameters (X2):
- if the struct has only data members, it comes through fine. That's OK.
- if the struct has a destructor member, in the X2 case it will be passed by pointer.
#include <stdio.h>
class Rectangle {
public:
float left;
float top;
float right;
float bottom;
// Rectangle(float l, float t, float r, float b): left(l), top(t), right(r), bottom(b) { printf("construct Rectangle\n"); }
~Rectangle() { printf("destruct Rectangle\n"); }
};
extern "C" {
void
LW_ew1(Rectangle p1) {
fprintf(stderr, "foreign ew x 1 ...\n");
fprintf(stderr, "foreign ew { %5.2f, %5.2f, %5.2f, %5.2f }...\n", p1.left, p1.top, p1.right, p1.bottom);
fprintf(stderr, "foreign ew ok\n");
}
void
LW_ew2(Rectangle p1, unsigned p2) {
fprintf(stderr, "foreign ew x 2 ...\n");
fprintf(stderr, "foreign ew { %5.2f, %5.2f, %5.2f, %5.2f }...\n", p1.left, p1.top, p1.right, p1.bottom);
fprintf(stderr, "foreign ew ok\n");
}
}
#![allow(non_snake_case)]
#![allow(dead_code)]
#![allow(non_camel_case_types)]
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Rectangle {
pub left: f32,
pub top: f32,
pub right: f32,
pub bottom: f32,
}
#[repr(C)]
#[repr(align(8))]
pub struct WL {
pub _bindgen_opaque_blob: [u64; 1],
}
#[link(name = "cwrap")]
extern "C" {
pub fn LW_ew1(p1: Rectangle);
#[link_name = "LW_ew2"]
pub fn LW_ew1b(p1: &Rectangle, p2: u32);
pub fn LW_ew2(p1: Rectangle, p2: u32);
}
impl WL {
pub unsafe fn ew(p1: Rectangle) {
println!("WL::ew({:?}, ...)", p1);
LW_ew1(p1);
println!("(passing &Rectangle ...)");
LW_ew1b(&p1, 9);
LW_ew2(p1, 9);
}
}
extern crate tlx;
use tlx::wl::{WL,Rectangle};
fn main() {
let r = Rectangle { left: 209.0, top: 308.0, right: 407.0, bottom: 506.0 };
unsafe { WL::ew(r) };
}