Repository: rust-lang/rust-bindgen
Pull request #2840 (2024-05-26 13:46:47)

Print CLI errors to stderr instead of stdout
This prevents them of sneaking into output files instead of being displayed when manually generating bindings by redirecting stdout.

Similar to #1031, the CLI should print to stderr too.


Patch:
diff --git a/bindgen-cli/main.rs b/bindgen-cli/main.rs
index a3a011fc..caa47c62 100644
--- a/bindgen-cli/main.rs
+++ b/bindgen-cli/main.rs
@@ -38,7 +38,7 @@ pub fn main() {
                 if verbose {
                     print_verbose_err()
                 }
-                println!("{}", info);
+                eprintln!("{}", info);
             }));
 
             let bindings =
@@ -49,21 +49,21 @@ pub fn main() {
             bindings.write(output).expect("Unable to write output");
         }
         Err(error) => {
-            println!("{}", error);
+            eprintln!("{}", error);
             std::process::exit(1);
         }
     };
 }
 
 fn print_verbose_err() {
-    println!("Bindgen unexpectedly panicked");
-    println!(
+    eprintln!("Bindgen unexpectedly panicked");
+    eprintln!(
         "This may be caused by one of the known-unsupported \
          things (https://rust-lang.github.io/rust-bindgen/cpp.html), \
          please modify the bindgen flags to work around it as \
          described in https://rust-lang.github.io/rust-bindgen/cpp.html"
     );
-    println!(
+    eprintln!(
         "Otherwise, please file an issue at \
          https://github.com/rust-lang/rust-bindgen/issues/new"
     );
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;
+};