rust-lang / rust-bindgen

Automatically generates Rust FFI bindings to C (and some C++) libraries.
https://rust-lang.github.io/rust-bindgen/
BSD 3-Clause "New" or "Revised" License
4.23k stars 679 forks source link

Deriving common traits (`Copy` / `Clone`) doesn't appear to be working for anonymous unions/structs #2785

Closed VariableExp0rt closed 3 months ago

VariableExp0rt commented 3 months ago

Input C/C++ Header

/*
 * IO submission data structure (Submission Queue Entry)
 */
struct io_uring_sqe {
    __u8    opcode;     /* type of operation for this sqe */
    __u8    flags;      /* IOSQE_ flags */
    __u16   ioprio;     /* ioprio for the request */
    __s32   fd;     /* file descriptor to do IO on */
    union {
        __u64   off;    /* offset into file */
        __u64   addr2;
        struct {
            __u32   cmd_op;
            __u32   __pad1;
        };
    };
    union {
        __u64   addr;   /* pointer to buffer or iovecs */
        __u64   splice_off_in;
        struct {
            __u32   level;
            __u32   optname;
        };
    };
    __u32   len;        /* buffer size or number of iovecs */
    union {
        __kernel_rwf_t  rw_flags;
        __u32       fsync_flags;
        __u16       poll_events;    /* compatibility */
        __u32       poll32_events;  /* word-reversed for BE */
        __u32       sync_range_flags;
        __u32       msg_flags;
        __u32       timeout_flags;
        __u32       accept_flags;
        __u32       cancel_flags;
        __u32       open_flags;
        __u32       statx_flags;
        __u32       fadvise_advice;
        __u32       splice_flags;
        __u32       rename_flags;
        __u32       unlink_flags;
        __u32       hardlink_flags;
        __u32       xattr_flags;
        __u32       msg_ring_flags;
        __u32       uring_cmd_flags;
        __u32       waitid_flags;
        __u32       futex_flags;
        __u32       install_fd_flags;
    };
    __u64   user_data;  /* data to be passed back at completion time */
    /* pack this to avoid bogus arm OABI complaints */
    union {
        /* index into fixed buffers, if used */
        __u16   buf_index;
        /* for grouped buffer selection */
        __u16   buf_group;
    } __attribute__((packed));
    /* personality to use, if used */
    __u16   personality;
    union {
        __s32   splice_fd_in;
        __u32   file_index;
        __u32   optlen;
        struct {
            __u16   addr_len;
            __u16   __pad3[1];
        };
    };
    union {
        struct {
            __u64   addr3;
            __u64   __pad2[1];
        };
        __u64   optval;
        /*
         * If the ring is initialized with IORING_SETUP_SQE128, then
         * this field is used for 80 bytes of arbitrary command data
         */
        __u8    cmd[0];
    };
};

Bindgen Invocation

    let bindings = bindgen::Builder::default()
        .header("wrapper.h")
        .allowlist_type("(io_uring_(sqe|cqe)|io_(sq|cq)ring_offsets|io_uring_params)")
        .allowlist_var("^IORING.*")
        .blocklist_type("__.*")
        .raw_line("pub type __u8 = u8;")
        .raw_line("pub type __u16 = u16;")
        .raw_line("pub type __s32 = i32;")
        .raw_line("pub type __u32 = u32;")
        .raw_line("pub type __u64 = u64;")
        .raw_line("pub type __kernel_rwf_t = i32;")
        .formatter(bindgen::Formatter::Rustfmt)
        .layout_tests(false)
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .generate()
        .expect("Unable to generate bindings");

Actual Results

#[repr(C)]
pub struct io_uring_sqe {
    pub opcode: __u8,
    pub flags: __u8,
    pub ioprio: __u16,
    pub fd: __s32,
    pub __bindgen_anon_1: io_uring_sqe__bindgen_ty_1,
    pub __bindgen_anon_2: io_uring_sqe__bindgen_ty_2,
    pub len: __u32,
    pub __bindgen_anon_3: io_uring_sqe__bindgen_ty_3,
    pub user_data: __u64,
    pub __bindgen_anon_4: io_uring_sqe__bindgen_ty_4,
    pub personality: __u16,
    pub __bindgen_anon_5: io_uring_sqe__bindgen_ty_5,
    pub __bindgen_anon_6: io_uring_sqe__bindgen_ty_6,
}

Expected Results

#[repr(C)]
#[derive(Default, Copy, Clone)]
pub struct io_uring_sqe {
    pub opcode: __u8,
    pub flags: __u8,
    pub ioprio: __u16,
    pub fd: __s32,
    pub __bindgen_anon_1: io_uring_sqe__bindgen_ty_1,
    pub __bindgen_anon_2: io_uring_sqe__bindgen_ty_2,
    pub len: __u32,
    pub __bindgen_anon_3: io_uring_sqe__bindgen_ty_3,
    pub user_data: __u64,
    pub __bindgen_anon_4: io_uring_sqe__bindgen_ty_4,
    pub personality: __u16,
    pub __bindgen_anon_5: io_uring_sqe__bindgen_ty_5,
    pub __bindgen_anon_6: io_uring_sqe__bindgen_ty_6,
}

As we discussed in #2784, I managed to get the bindings generated by aliasing the __<> types, but now hitting this.

emilio commented 3 months ago

Ah, sorry, I forgot you need to use https://docs.rs/bindgen/latest/bindgen/callbacks/trait.ParseCallbacks.html#method.blocklisted_type_implements_trait to get the behavior you want precisely (otherwise bindgen makes no assumptions about blocklisted items).