Repository: rust-lang/rust-bindgen (rust)

Issue:
Support for one set of bindings depending on another (conflicting `__BindgenBitfieldUnit`)
<!-- Thanks for filing a bindgen issue! We appreciate it :-) -->

Hi! This is kind of a feature request for a (maybe unusual) use case where bindings are generated in multiple different crates. In our case we have [`citro3d-sys`](https://github.com/rust3ds/citro3d-rs/tree/main/citro3d-sys) which depends on some types in [`ctru-sys`](https://github.com/rust3ds/ctru-rs/tree/master/ctru-sys). 

The idea is to reuse existing types from `ctru-sys` wherever possible, instead of regenerating a duplicate definition. For the most part, this works great with `allowlist_type` / `blocklist_type`, so we can use something like this:
```rs
use ctru_sys::*;
use libc::*;
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
```

There is one exception where this doesn't work — `bindgen`-generated types for bitfields. The various `_bindgen_ty_*` seem to avoid overlap (whether this is by design due to deterministic naming, or just coincidence?), but both sets generate `pub struct __BindgenBitfieldUnit<Storage>` as well, which unfortunately does overlap.

### Input C/C++ Header

Minimal reproduction with two crates `a` and `b`:

`a.h`:
```C
typedef struct A {
  unsigned char x;
  unsigned b1 : 1;
  unsigned b2 : 1;
  unsigned baz;
} A;
```
`b.h`:
```C
#include "../a/a.h"

typedef struct B {
  A a;
} B;

typedef struct C {
  unsigned char x;
  unsigned b1 : 1;
  unsigned b2 : 1;
  unsigned baz;
} C;

```

### Bindgen Invocation

<!-- Place either the `bindgen::Builder` or the command line flags used here. -->

`a/build.rs`:
```Rust
    bindgen::Builder::default()
        .header("a.h")
        .generate()
        .expect("Unable to generate bindings")
        .write_to_file(PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("bindings.rs"))
        .expect("Couldn't write bindings!");
```

`b/build.rs`:
```Rust
    bindgen::Builder::default()
        .header("b.h")
        .blocklist_type("A")
        .generate()
        .expect("Unable to generate bindings")
        .write_to_file(PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("bindings.rs"))
        .expect("Couldn't write bindings!");
```


### Actual Results

With `b/lib.rs`:
```rs
// Makes it clear when there are duplicates:
#![deny(ambiguous_glob_reexports)]

pub use a::*;

mod bindings {
    use a::*;
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}

pub use bindings::*;
```

```console
$ cargo check --workspace
   Compiling b v0.1.0 (/Users/ianchamberlain/Documents/Development/rs-sandbox/b)
error: ambiguous glob re-exports
  --> b/src/lib.rs:3:9
   |
3  | pub use a::*;
   |         ^^^^ the name `__BindgenBitfieldUnit` in the type namespace is first re-exported here
...
11 | pub use bindings::*;
   |         ----------- but the name `__BindgenBitfieldUnit` in the type namespace is also re-exported here
   |
note: the lint level is defined here
  --> b/src/lib.rs:1:9
   |
1  | #![deny(ambiguous_glob_reexports)]
   |         ^^^^^^^^^^^^^^^^^^^^^^^^

error: could not compile `b` (lib) due to 1 previous error
```

### Expected Results

<!--
Replace this with a description of what you expected instead of the actual
results. The more precise, the better! For example, if a struct in the generated
bindings is missing a field that exists in the C/C++ struct, note that here.
-->

I think the simplest option to address this in our case would be a flag to skip generating the `__BindgenBitfieldUnit` type — would a PR be accepted to add such a flag? I have mostly worked out the implementation already, but maybe there's a better/simpler way to support this kind of use case?

If it would be accepted, I can open a PR adding a `skip_bindgen_bitfield_unit` flag, which in this case could be used to avoid the generated conflict by reusing `a`'s version of the struct instead of generating a new one in `b`.

Thank you!

Pull request:
Support blocklisting `__BindgenBitfieldUnit`
Closes #2835

Simply skip emitting it if the list of blocklisted types/items matches its name.

Also add a test that verifies blocklisting anonymous types by `_bindgen_ty_*` works as expected – which could be used to prevent similar conflicts between generated type names for anonymous types.

Patch:
diff --git a/bindgen/codegen/helpers.rs b/bindgen/codegen/helpers.rs
index fa1dde87..257ea596 100644
--- a/bindgen/codegen/helpers.rs
+++ b/bindgen/codegen/helpers.rs
@@ -1,5 +1,7 @@
 //! Helpers for code generation that don't need macro expansion.
 
+use proc_macro2::{Ident, Span};
+
 use crate::ir::context::BindgenContext;
 use crate::ir::layout::Layout;
 
@@ -109,10 +111,13 @@ pub(crate) fn integer_type(
     Layout::known_type_for_size(ctx, layout.size)
 }
 
+pub(crate) const BITFIELD_UNIT: &str = "__BindgenBitfieldUnit";
+
 /// Generates a bitfield allocation unit type for a type with the given `Layout`.
 pub(crate) fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> syn::Type {
     let size = layout.size;
-    let ty = syn::parse_quote! { __BindgenBitfieldUnit<[u8; #size]> };
+    let bitfield_unit_name = Ident::new(BITFIELD_UNIT, Span::call_site());
+    let ty = syn::parse_quote! { #bitfield_unit_name<[u8; #size]> };
 
     if ctx.options().enable_cxx_namespaces {
         return syn::parse_quote! { root::#ty };
diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs
index 0b23e0ac..7c1c55ab 100644
--- a/bindgen/codegen/mod.rs
+++ b/bindgen/codegen/mod.rs
@@ -5017,6 +5017,7 @@ pub(crate) fn codegen(
 }
 
 pub(crate) mod utils {
+    use super::helpers::BITFIELD_UNIT;
     use super::serialize::CSerialize;
     use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque};
     use crate::ir::context::BindgenContext;
@@ -5153,6 +5154,12 @@ pub(crate) mod utils {
         ctx: &BindgenContext,
         result: &mut Vec<proc_macro2::TokenStream>,
     ) {
+        if ctx.options().blocklisted_items.matches(BITFIELD_UNIT) ||
+            ctx.options().blocklisted_types.matches(BITFIELD_UNIT)
+        {
+            return;
+        }
+
         let bitfield_unit_src = include_str!("./bitfield_unit.rs");
         let bitfield_unit_src = if ctx.options().rust_features().min_const_fn {
             Cow::Borrowed(bitfield_unit_src)
diff --git a/book/src/using-bitfields.md b/book/src/using-bitfields.md
index 0ee9f032..8929f737 100644
--- a/book/src/using-bitfields.md
+++ b/book/src/using-bitfields.md
@@ -8,6 +8,11 @@ As Rust does not support bitfields, Bindgen generates a struct for each with the
 * For each contiguous block of bitfields, Bindgen emits an opaque physical field that contains one or more logical bitfields
 * A static constructor  ```new_bitfield_{1, 2, ...}``` with a parameter for each bitfield contained within the opaque physical field.
 
+To keep bindgen from generating the bitfield unit struct, it can be blocklisted like any
+other type, i.e. `--blocklist-type "__BindgenBitfieldUnit"`. This may be useful if
+you want to define a custom implementation, or your generated bindings import a
+pre-existing definition for the bitfield unit type.
+
 ## Bitfield examples
 
 For this discussion, we will use the following C type definitions and functions.


Test patch:
diff --git a/bindgen-tests/tests/expectations/tests/anon_enum_blocklist.rs b/bindgen-tests/tests/expectations/tests/anon_enum_blocklist.rs
new file mode 100644
index 00000000..28ab3ad7
--- /dev/null
+++ b/bindgen-tests/tests/expectations/tests/anon_enum_blocklist.rs
@@ -0,0 +1,4 @@
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+pub const FLAG_Z: _bindgen_ty_2 = 0;
+pub const FLAG_W: _bindgen_ty_2 = 1;
+pub type _bindgen_ty_2 = ::std::os::raw::c_uint;
diff --git a/bindgen-tests/tests/expectations/tests/blocklist_bitfield_unit.rs b/bindgen-tests/tests/expectations/tests/blocklist_bitfield_unit.rs
new file mode 100644
index 00000000..d802e282
--- /dev/null
+++ b/bindgen-tests/tests/expectations/tests/blocklist_bitfield_unit.rs
@@ -0,0 +1,68 @@
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+#[path = "./struct_with_bitfields.rs"]
+mod bitfields;
+use bitfields::*;
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct C {
+    pub x: ::std::os::raw::c_uchar,
+    pub _bitfield_align_1: [u8; 0],
+    pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>,
+    pub baz: ::std::os::raw::c_uint,
+}
+const _: () = {
+    ["Size of C"][::std::mem::size_of::<C>() - 8usize];
+    ["Alignment of C"][::std::mem::align_of::<C>() - 4usize];
+    ["Offset of field: C::x"][::std::mem::offset_of!(C, x) - 0usize];
+    ["Offset of field: C::baz"][::std::mem::offset_of!(C, baz) - 4usize];
+};
+impl C {
+    #[inline]
+    pub fn b1(&self) -> ::std::os::raw::c_uint {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u32) }
+    }
+    #[inline]
+    pub fn set_b1(&mut self, val: ::std::os::raw::c_uint) {
+        unsafe {
+            let val: u32 = ::std::mem::transmute(val);
+            self._bitfield_1.set(0usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn b2(&self) -> ::std::os::raw::c_uint {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(1usize, 1u8) as u32) }
+    }
+    #[inline]
+    pub fn set_b2(&mut self, val: ::std::os::raw::c_uint) {
+        unsafe {
+            let val: u32 = ::std::mem::transmute(val);
+            self._bitfield_1.set(1usize, 1u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn new_bitfield_1(
+        b1: ::std::os::raw::c_uint,
+        b2: ::std::os::raw::c_uint,
+    ) -> __BindgenBitfieldUnit<[u8; 1usize]> {
+        let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = Default::default();
+        __bindgen_bitfield_unit
+            .set(
+                0usize,
+                1u8,
+                {
+                    let b1: u32 = unsafe { ::std::mem::transmute(b1) };
+                    b1 as u64
+                },
+            );
+        __bindgen_bitfield_unit
+            .set(
+                1usize,
+                1u8,
+                {
+                    let b2: u32 = unsafe { ::std::mem::transmute(b2) };
+                    b2 as u64
+                },
+            );
+        __bindgen_bitfield_unit
+    }
+}
diff --git a/bindgen-tests/tests/headers/anon_enum_blocklist.h b/bindgen-tests/tests/headers/anon_enum_blocklist.h
new file mode 100644
index 00000000..61aa6e68
--- /dev/null
+++ b/bindgen-tests/tests/headers/anon_enum_blocklist.h
@@ -0,0 +1,11 @@
+// bindgen-flags: --blocklist-type "_bindgen_ty_1"
+
+enum {
+  FLAG_X,
+  FLAG_Y,
+};
+
+enum {
+  FLAG_Z,
+  FLAG_W,
+};
diff --git a/bindgen-tests/tests/headers/blocklist_bitfield_unit.h b/bindgen-tests/tests/headers/blocklist_bitfield_unit.h
new file mode 100644
index 00000000..5f7d94ce
--- /dev/null
+++ b/bindgen-tests/tests/headers/blocklist_bitfield_unit.h
@@ -0,0 +1,7 @@
+// bindgen-flags: --blocklist-type "__BindgenBitfieldUnit" --raw-line '#[path = "./struct_with_bitfields.rs"] mod bitfields;' --raw-line 'use bitfields::*;'
+struct C {
+  unsigned char x;
+  unsigned b1 : 1;
+  unsigned b2 : 1;
+  unsigned baz;
+};