Repository: rust-lang/rust-bindgen
Pull request #3220 (2025-06-08 10:17:10)

codegen: Avoid crashing on variadic unions without layout information. 


Patch:
diff --git a/bindgen/clang.rs b/bindgen/clang.rs
index 04fe3e15..e52fed0d 100644
--- a/bindgen/clang.rs
+++ b/bindgen/clang.rs
@@ -945,7 +945,7 @@ impl Cursor {
     }
 
     /// Gets the tokens that correspond to that cursor.
-    pub(crate) fn tokens(&self) -> RawTokens {
+    pub(crate) fn tokens(&self) -> RawTokens<'_> {
         RawTokens::new(self)
     }
 
@@ -1006,7 +1006,7 @@ impl<'a> RawTokens<'a> {
     }
 
     /// Get an iterator over these tokens.
-    pub(crate) fn iter(&self) -> ClangTokenIterator {
+    pub(crate) fn iter(&self) -> ClangTokenIterator<'_> {
         ClangTokenIterator {
             tu: self.tu,
             raw: self.as_slice().iter(),
diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs
index 8da10ff0..59f2265c 100644
--- a/bindgen/codegen/mod.rs
+++ b/bindgen/codegen/mod.rs
@@ -2337,18 +2337,17 @@ impl CodeGenerator for CompInfo {
                 }
             }
         } else if is_union && !forward_decl {
-            // TODO(emilio): It'd be nice to unify this with the struct path
-            // above somehow.
-            let layout = layout.expect("Unable to get layout information?");
-            if struct_layout.requires_explicit_align(layout) {
-                explicit_align = Some(layout.align);
-            }
-
-            if !struct_layout.is_rust_union() {
-                let ty = helpers::blob(ctx, layout, false);
-                fields.push(quote! {
-                    pub bindgen_union_field: #ty ,
-                });
+            if let Some(layout) = layout {
+                // TODO(emilio): It'd be nice to unify this with the struct path above somehow.
+                if struct_layout.requires_explicit_align(layout) {
+                    explicit_align = Some(layout.align);
+                }
+                if !struct_layout.is_rust_union() {
+                    let ty = helpers::blob(ctx, layout, false);
+                    fields.push(quote! {
+                        pub bindgen_union_field: #ty ,
+                    });
+                }
             }
         }
 
diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs
index 3f9e16ac..c0201a11 100644
--- a/bindgen/ir/context.rs
+++ b/bindgen/ir/context.rs
@@ -1228,7 +1228,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
 
     fn assert_no_dangling_item_traversal(
         &self,
-    ) -> traversal::AssertNoDanglingItemsTraversal {
+    ) -> traversal::AssertNoDanglingItemsTraversal<'_> {
         assert!(self.in_codegen_phase());
         assert_eq!(self.current_module, self.root_module);
 
diff --git a/bindgen/ir/ty.rs b/bindgen/ir/ty.rs
index baaa4a49..38a7f634 100644
--- a/bindgen/ir/ty.rs
+++ b/bindgen/ir/ty.rs
@@ -243,7 +243,7 @@ impl Type {
     }
 
     /// Takes `name`, and returns a suitable identifier representation for it.
-    fn sanitize_name(name: &str) -> Cow<str> {
+    fn sanitize_name(name: &str) -> Cow<'_, str> {
         if clang::is_valid_identifier(name) {
             return Cow::Borrowed(name);
         }
diff --git a/bindgen/lib.rs b/bindgen/lib.rs
index 12ac8a29..b2fecc2c 100644
--- a/bindgen/lib.rs
+++ b/bindgen/lib.rs
@@ -980,7 +980,7 @@ impl Bindings {
     }
 
     /// Gets the rustfmt path to rustfmt the generated bindings.
-    fn rustfmt_path(&self) -> io::Result<Cow<PathBuf>> {
+    fn rustfmt_path(&self) -> io::Result<Cow<'_, PathBuf>> {
         debug_assert!(matches!(self.options.formatter, Formatter::Rustfmt));
         if let Some(ref p) = self.options.rustfmt_path {
             return Ok(Cow::Borrowed(p));


Test patch:
diff --git a/bindgen-tests/tests/expectations/tests/variadic-union.rs b/bindgen-tests/tests/expectations/tests/variadic-union.rs
new file mode 100644
index 00000000..471c9e70
--- /dev/null
+++ b/bindgen-tests/tests/expectations/tests/variadic-union.rs
@@ -0,0 +1,14 @@
+#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)]
+#[repr(C)]
+pub union _Variadic_union {
+    pub _address: u8,
+}
+impl Default for _Variadic_union {
+    fn default() -> Self {
+        let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
+        unsafe {
+            ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
+            s.assume_init()
+        }
+    }
+}
diff --git a/bindgen-tests/tests/headers/variadic-union.hpp b/bindgen-tests/tests/headers/variadic-union.hpp
new file mode 100644
index 00000000..62ed49fc
--- /dev/null
+++ b/bindgen-tests/tests/headers/variadic-union.hpp
@@ -0,0 +1,3 @@
+template <typename... _Types> union _Variadic_union {
+  _Variadic_union() = default;
+};