rust-lang / rust-lang/rust-bindgen
Inconsistent behaviour of `derive_default` for opaque types
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 5.3k
- Forks
- 829
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 15
Description
There seems to be inconsistent behavior for derive_default based on whether the type is detected to be opaque by bindgen or explicitly marked as opaque by bindgen.
For a C definition of struct Foo; for an opaque struct, bindgen will generate the following with derive_default(true):
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Foo {
_unused: [u8; 0],
}
When Foo is also explicitly marked opaque with .opaque_type("Foo"), it generates the following:
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Foo {
_unused: [u8; 0],
}
I don't see why explicitly marking the type as opaque should change whether or not Default is derived. I also think that it makes even less sense that Default gets derived for a type that is supposed to be Opaque, since opaque types should never be directly accessed and should be handled only via pointers.
Other Information
rust-bindgen 0.71.1
clang version 19.1.7
Target: x86_64-pc-windows-msvc
Full Code Sample
build.rs:
use std::env;
use std::path::PathBuf;
fn main() {
tracing_subscriber::fmt::init();
let builder = bindgen::Builder::default()
.header_contents(
"input.h",
r#"
struct Foo;
struct BAR__{int unused;};
typedef struct BAR__ *BAR;
"#,
)
.parse_callbacks(Box::new(bindgen::CargoCallbacks::new()))
.derive_default(true);
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
builder
.clone()
.generate()
.expect("Unable to generate bindings")
.write_to_file((out_path).join("not-explicit-opaque.rs"))
.expect("Couldn't write bindings!");
builder
.opaque_type("Foo")
.opaque_type("BAR__") // Only BAR__ should be marked as opaque. The convenience type BAR should remain as a pointer to the opaque BAR__.
.generate()
.expect("Unable to generate bindings")
.write_to_file((out_path).join("explicit-opaque.rs"))
.expect("Couldn't write bindings!");
}
Output:
not-explicit-opaque.rs:
/* automatically generated by rust-bindgen 0.71.1 */
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Foo {
_unused: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct BAR__ {
pub unused: ::std::os::raw::c_int,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
["Size of BAR__"][::std::mem::size_of::<BAR__>() - 4usize];
["Alignment of BAR__"][::std::mem::align_of::<BAR__>() - 4usize];
["Offset of field: BAR__::unused"][::std::mem::offset_of!(BAR__, unused) - 0usize];
};
pub type BAR = *mut BAR__;
explicit-opaque.rs:
/* automatically generated by rust-bindgen 0.71.1 */
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct Foo {
_unused: [u8; 0],
}
#[repr(C)]
#[repr(align(4))]
#[derive(Debug, Default, Copy, Clone)]
pub struct BAR__ {
pub _bindgen_opaque_blob: u32,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
["Size of BAR__"][::std::mem::size_of::<BAR__>() - 4usize];
["Alignment of BAR__"][::std::mem::align_of::<BAR__>() - 4usize];
};
pub type BAR = *mut BAR__;
Output Diff (left is no explicit opaque. right is explicit opaque):
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the difference from build.rs using derive_default(true), opaque_type("Foo"), and opaque_type("BAR__"), then compare not-explicit-opaque.rs with explicit-opaque.rs. Trace how bindgen chooses derives for inferred versus explicitly opaque types, and make the generated Default behavior consistent with the intended opaque-type policy.
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