rust-lang / rust-lang/rust-bindgen

Failed to generate `Default` impl for arrays larger than 32 entries

Open
#2,803 8 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
5.3k
Forks
829
Avg merge
1d 1h
Merged PRs (30d)
15

Description

Input C/C++ Header
#define CCHDEVICENAME 32
typedef long LONG;
typedef char CHAR;
typedef unsigned long DWORD;

typedef struct tagRECT
{
    LONG    left;
    LONG    top;
    LONG    right;
    LONG    bottom;
} RECT;
typedef struct tagMONITORINFO
{
    DWORD   cbSize;
    RECT    rcMonitor;
    RECT    rcWork;
    DWORD   dwFlags;
} MONITORINFO, *LPMONITORINFO;
typedef struct tagMONITORINFOEXA
{
    MONITORINFO;
    CHAR        szDevice[CCHDEVICENAME];
} MONITORINFOEXA, *LPMONITORINFOEXA;
        
Bindgen Invocation
use std::env;
use std::path::PathBuf;

fn main() {

    let bindings = bindgen::Builder::default()
        .header_contents(
            "input.h",
            r#"
#define CCHDEVICENAME 32
typedef long LONG;
typedef char CHAR;
typedef unsigned long DWORD;

typedef struct tagRECT
{
    LONG    left;
    LONG    top;
    LONG    right;
    LONG    bottom;
} RECT;
typedef struct tagMONITORINFO
{
    DWORD   cbSize;
    RECT    rcMonitor;
    RECT    rcWork;
    DWORD   dwFlags;
} MONITORINFO, *LPMONITORINFO;
typedef struct tagMONITORINFOEXA
{
    MONITORINFO;
    CHAR        szDevice[CCHDEVICENAME];
} MONITORINFOEXA, *LPMONITORINFOEXA;"#,
        )
        .derive_default(true)
        .parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
        .generate()
        .expect("Unable to generate bindings");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}

Actual Results
error[E0277]: the trait bound `[u8; 40]: Default` is not satisfied
   --> D:\git-repos\bindgen-test\target\debug\build\bindgen-test-39d5729a71a2ce1c\out/bindings.rs:140:5
    |
138 | #[derive(Debug, Default, Copy, Clone)]
    |                 ------- in this derive macro expansion
139 | pub struct tagMONITORINFOEXA {
140 |     pub __bindgen_padding_0: [u8; 40usize],
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `[u8; 40]`
    |
    = help: the following other types implement trait `Default`:
              [T; 0]
              [T; 1]
              [T; 2]
              [T; 3]
              [T; 4]
              [T; 5]
              [T; 6]
              [T; 7]
            and 27 others
    = note: this error originates in the derive macro `Default` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0277`.
error: could not compile `bindgen-test` (lib) due to 1 previous error

Caused by:
  process didn't exit successfully: `sccache rustc --crate-name bindgen_test --edition=2021 src\lib.rs --error-format=json --json=diagnostic-rendered-ansi,artifacts,future-incompat --diagnostic-width=191 --crate-type lib --emit=dep-info,metadata,link -C embed-bitcode=no -C debuginfo=2 -C metadata=dfb5b3ab9206c6f2 -C extra-filename=-dfb5b3ab9206c6f2 --out-dir D:\git-repos\bindgen-test\target\debug\deps -C incremental=D:\git-repos\bindgen-test\target\debug\incremental -L dependency=D:\git-repos\bindgen-test\target\debug\deps` (exit code: 1)

and/or

/* automatically generated by rust-bindgen 0.69.4 */

pub const CCHDEVICENAME: u32 = 32;
pub type LONG = ::std::os::raw::c_long;
pub type CHAR = ::std::os::raw::c_char;
pub type DWORD = ::std::os::raw::c_ulong;
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct tagRECT {
    pub left: LONG,
    pub top: LONG,
    pub right: LONG,
    pub bottom: LONG,
}
#[test]
fn bindgen_test_layout_tagRECT() {
    const UNINIT: ::std::mem::MaybeUninit<tagRECT> = ::std::mem::MaybeUninit::uninit();
    let ptr = UNINIT.as_ptr();
    assert_eq!(
        ::std::mem::size_of::<tagRECT>(),
        16usize,
        concat!("Size of: ", stringify!(tagRECT))
    );
    assert_eq!(
        ::std::mem::align_of::<tagRECT>(),
        4usize,
        concat!("Alignment of ", stringify!(tagRECT))
    );
    assert_eq!(
        unsafe { ::std::ptr::addr_of!((*ptr).left) as usize - ptr as usize },
        0usize,
        concat!(
            "Offset of field: ",
            stringify!(tagRECT),
            "::",
            stringify!(left)
        )
    );
    assert_eq!(
        unsafe { ::std::ptr::addr_of!((*ptr).top) as usize - ptr as usize },
        4usize,
        concat!(
            "Offset of field: ",
            stringify!(tagRECT),
            "::",
            stringify!(top)
        )
    );
    assert_eq!(
        unsafe { ::std::ptr::addr_of!((*ptr).right) as usize - ptr as usize },
        8usize,
        concat!(
            "Offset of field: ",
            stringify!(tagRECT),
            "::",
            stringify!(right)
        )
    );
    assert_eq!(
        unsafe { ::std::ptr::addr_of!((*ptr).bottom) as usize - ptr as usize },
        12usize,
        concat!(
            "Offset of field: ",
            stringify!(tagRECT),
            "::",
            stringify!(bottom)
        )
    );
}
pub type RECT = tagRECT;
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct tagMONITORINFO {
    pub cbSize: DWORD,
    pub rcMonitor: RECT,
    pub rcWork: RECT,
    pub dwFlags: DWORD,
}
#[test]
fn bindgen_test_layout_tagMONITORINFO() {
    const UNINIT: ::std::mem::MaybeUninit<tagMONITORINFO> = ::std::mem::MaybeUninit::uninit();
    let ptr = UNINIT.as_ptr();
    assert_eq!(
        ::std::mem::size_of::<tagMONITORINFO>(),
        40usize,
        concat!("Size of: ", stringify!(tagMONITORINFO))
    );
    assert_eq!(
        ::std::mem::align_of::<tagMONITORINFO>(),
        4usize,
        concat!("Alignment of ", stringify!(tagMONITORINFO))
    );
    assert_eq!(
        unsafe { ::std::ptr::addr_of!((*ptr).cbSize) as usize - ptr as usize },
        0usize,
        concat!(
            "Offset of field: ",
            stringify!(tagMONITORINFO),
            "::",
            stringify!(cbSize)
        )
    );
    assert_eq!(
        unsafe { ::std::ptr::addr_of!((*ptr).rcMonitor) as usize - ptr as usize },
        4usize,
        concat!(
            "Offset of field: ",
            stringify!(tagMONITORINFO),
            "::",
            stringify!(rcMonitor)
        )
    );
    assert_eq!(
        unsafe { ::std::ptr::addr_of!((*ptr).rcWork) as usize - ptr as usize },
        20usize,
        concat!(
            "Offset of field: ",
            stringify!(tagMONITORINFO),
            "::",
            stringify!(rcWork)
        )
    );
    assert_eq!(
        unsafe { ::std::ptr::addr_of!((*ptr).dwFlags) as usize - ptr as usize },
        36usize,
        concat!(
            "Offset of field: ",
            stringify!(tagMONITORINFO),
            "::",
            stringify!(dwFlags)
        )
    );
}
pub type MONITORINFO = tagMONITORINFO;
pub type LPMONITORINFO = *mut tagMONITORINFO;
#[repr(C)]
#[repr(align(4))]
#[derive(Debug, Default, Copy, Clone)]
pub struct tagMONITORINFOEXA {
    pub __bindgen_padding_0: [u8; 40usize],
    pub szDevice: [CHAR; 32usize],
}
#[test]
fn bindgen_test_layout_tagMONITORINFOEXA() {
    const UNINIT: ::std::mem::MaybeUninit<tagMONITORINFOEXA> = ::std::mem::MaybeUninit::uninit();
    let ptr = UNINIT.as_ptr();
    assert_eq!(
        ::std::mem::size_of::<tagMONITORINFOEXA>(),
        72usize,
        concat!("Size of: ", stringify!(tagMONITORINFOEXA))
    );
    assert_eq!(
        ::std::mem::align_of::<tagMONITORINFOEXA>(),
        4usize,
        concat!("Alignment of ", stringify!(tagMONITORINFOEXA))
    );
    assert_eq!(
        unsafe { ::std::ptr::addr_of!((*ptr).szDevice) as usize - ptr as usize },
        40usize,
        concat!(
            "Offset of field: ",
            stringify!(tagMONITORINFOEXA),
            "::",
            stringify!(szDevice)
        )
    );
}
pub type MONITORINFOEXA = tagMONITORINFOEXA;
pub type LPMONITORINFOEXA = *mut tagMONITORINFOEXA;

Expected Results

I expected it to generate a default implementation successfully. This seems to be another regression of #1718/#1719 and #2082, where it fails to generate a valid Default when the array has more than the 32 entries (where rust itself generates a Default for <=32 entries).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the provided bindgen::Builder invocation with .derive_default(true) and inspect the generated tagMONITORINFOEXA bindings, especially the [u8; 40] padding field. The issue is done when generated bindings compile successfully with Default for arrays larger than 32 entries.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
devtools
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.