Repository: rust-lang/rust-bindgen
Pull request #2680 (2023-11-02 20:30:29)

Consider alignment contribution from bitfields
Partial fix to https://lore.kernel.org/rust-for-linux/Y8Ax%2FI5qOcVDZljG@zn.tnic/ (not a full fix, because if `short` below is replaced with a `int` then the code still fails to compile)

Currently binding for code like this wouldn't compile:
```c
struct outer {
    struct {
        short a: 16;
        short b: 16;
    };
} __attribute__((packed));
```
because bindgen sticks an extra `#[repr(align(2))]` on the inner struct.

This extra alignment is not necessary and can be removed. The removed NB line in this PR is no longer relevant because of the addition _bitfield_align field generated starting in #1950.

Reopen of #2388


Patch:
diff --git a/bindgen/codegen/struct_layout.rs b/bindgen/codegen/struct_layout.rs
index 56730603..83d78361 100644
--- a/bindgen/codegen/struct_layout.rs
+++ b/bindgen/codegen/struct_layout.rs
@@ -156,9 +156,7 @@ impl<'a> StructLayoutTracker<'a> {
 
         self.latest_field_layout = Some(layout);
         self.last_field_was_bitfield = true;
-        // NB: We intentionally don't update the max_field_align here, since our
-        // bitfields code doesn't necessarily guarantee it, so we need to
-        // actually generate the dummy alignment.
+        self.max_field_align = cmp::max(self.max_field_align, layout.align);
     }
 
     /// Returns a padding field if necessary for a given new field _before_
diff --git a/bindgen/ir/function.rs b/bindgen/ir/function.rs
index 5bfb70ef..6342758f 100644
--- a/bindgen/ir/function.rs
+++ b/bindgen/ir/function.rs
@@ -303,6 +303,7 @@ fn get_abi(cc: CXCallingConv) -> ClangAbi {
         CXCallingConv_X86VectorCall => ClangAbi::Known(Abi::Vectorcall),
         CXCallingConv_AAPCS => ClangAbi::Known(Abi::Aapcs),
         CXCallingConv_X86_64Win64 => ClangAbi::Known(Abi::Win64),
+        CXCallingConv_AArch64VectorCall => ClangAbi::Known(Abi::Vectorcall),
         other => ClangAbi::Unknown(other),
     }
 }
diff --git a/bindgen/ir/item.rs b/bindgen/ir/item.rs
index 0556452b..dd587b08 100644
--- a/bindgen/ir/item.rs
+++ b/bindgen/ir/item.rs
@@ -1432,57 +1432,58 @@ impl Item {
             }
         }
 
-        // Guess how does clang treat extern "C" blocks?
-        if cursor.kind() == CXCursor_UnexposedDecl {
-            Err(ParseError::Recurse)
-        } else {
+        match cursor.kind() {
+            // On Clang 18+, extern "C" is reported accurately as a LinkageSpec.
+            // Older LLVM treat it as UnexposedDecl.
+            CXCursor_LinkageSpec | CXCursor_UnexposedDecl => {
+                Err(ParseError::Recurse)
+            }
+
             // We allowlist cursors here known to be unhandled, to prevent being
             // too noisy about this.
-            match cursor.kind() {
-                CXCursor_MacroDefinition |
-                CXCursor_MacroExpansion |
-                CXCursor_UsingDeclaration |
-                CXCursor_UsingDirective |
-                CXCursor_StaticAssert |
-                CXCursor_FunctionTemplate => {
-                    debug!(
-                        "Unhandled cursor kind {:?}: {:?}",
-                        cursor.kind(),
-                        cursor
-                    );
-                }
-                CXCursor_InclusionDirective => {
-                    let file = cursor.get_included_file_name();
-                    match file {
-                        None => {
-                            warn!(
-                                "Inclusion of a nameless file in {:?}",
-                                cursor
-                            );
-                        }
-                        Some(included_file) => {
-                            for cb in &ctx.options().parse_callbacks {
-                                cb.include_file(&included_file);
-                            }
+            CXCursor_MacroDefinition |
+            CXCursor_MacroExpansion |
+            CXCursor_UsingDeclaration |
+            CXCursor_UsingDirective |
+            CXCursor_StaticAssert |
+            CXCursor_FunctionTemplate => {
+                debug!(
+                    "Unhandled cursor kind {:?}: {:?}",
+                    cursor.kind(),
+                    cursor
+                );
+                Err(ParseError::Continue)
+            }
 
-                            ctx.add_dep(included_file.into_boxed_str());
-                        }
+            CXCursor_InclusionDirective => {
+                let file = cursor.get_included_file_name();
+                match file {
+                    None => {
+                        warn!("Inclusion of a nameless file in {:?}", cursor);
                     }
-                }
-                _ => {
-                    // ignore toplevel operator overloads
-                    let spelling = cursor.spelling();
-                    if !spelling.starts_with("operator") {
-                        warn!(
-                            "Unhandled cursor kind {:?}: {:?}",
-                            cursor.kind(),
-                            cursor
-                        );
+                    Some(included_file) => {
+                        for cb in &ctx.options().parse_callbacks {
+                            cb.include_file(&included_file);
+                        }
+
+                        ctx.add_dep(included_file.into_boxed_str());
                     }
                 }
+                Err(ParseError::Continue)
             }
 
-            Err(ParseError::Continue)
+            _ => {
+                // ignore toplevel operator overloads
+                let spelling = cursor.spelling();
+                if !spelling.starts_with("operator") {
+                    warn!(
+                        "Unhandled cursor kind {:?}: {:?}",
+                        cursor.kind(),
+                        cursor
+                    );
+                }
+                Err(ParseError::Continue)
+            }
         }
     }
 


Test patch:
diff --git a/bindgen-tests/tests/expectations/tests/bitfield-32bit-overflow.rs b/bindgen-tests/tests/expectations/tests/bitfield-32bit-overflow.rs
index cf045436..ea126bbb 100644
--- a/bindgen-tests/tests/expectations/tests/bitfield-32bit-overflow.rs
+++ b/bindgen-tests/tests/expectations/tests/bitfield-32bit-overflow.rs
@@ -83,7 +83,7 @@ where
         }
     }
 }
-#[repr(C, packed)]
+#[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct MuchBitfield {
     pub _bitfield_align_1: [u8; 0],
diff --git a/bindgen-tests/tests/expectations/tests/bitfield-method-same-name.rs b/bindgen-tests/tests/expectations/tests/bitfield-method-same-name.rs
index 8cd1997a..ce3ea41e 100644
--- a/bindgen-tests/tests/expectations/tests/bitfield-method-same-name.rs
+++ b/bindgen-tests/tests/expectations/tests/bitfield-method-same-name.rs
@@ -83,7 +83,7 @@ where
         }
     }
 }
-#[repr(C, packed)]
+#[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct Foo {
     pub _bitfield_align_1: [u8; 0],
diff --git a/bindgen-tests/tests/expectations/tests/bitfield_align.rs b/bindgen-tests/tests/expectations/tests/bitfield_align.rs
index 559038ed..80023279 100644
--- a/bindgen-tests/tests/expectations/tests/bitfield_align.rs
+++ b/bindgen-tests/tests/expectations/tests/bitfield_align.rs
@@ -332,7 +332,6 @@ impl A {
     }
 }
 #[repr(C)]
-#[repr(align(4))]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct B {
     pub _bitfield_align_1: [u32; 0],
diff --git a/bindgen-tests/tests/expectations/tests/bitfield_align_2.rs b/bindgen-tests/tests/expectations/tests/bitfield_align_2.rs
index dc49137e..963d86f9 100644
--- a/bindgen-tests/tests/expectations/tests/bitfield_align_2.rs
+++ b/bindgen-tests/tests/expectations/tests/bitfield_align_2.rs
@@ -93,7 +93,6 @@ pub enum MyEnum {
     FOUR = 3,
 }
 #[repr(C)]
-#[repr(align(8))]
 #[derive(Debug, Copy, Clone)]
 pub struct TaggedPtr {
     pub _bitfield_align_1: [u64; 0],
diff --git a/bindgen-tests/tests/expectations/tests/bitfield_method_mangling.rs b/bindgen-tests/tests/expectations/tests/bitfield_method_mangling.rs
index ea1502eb..7104682e 100644
--- a/bindgen-tests/tests/expectations/tests/bitfield_method_mangling.rs
+++ b/bindgen-tests/tests/expectations/tests/bitfield_method_mangling.rs
@@ -84,7 +84,6 @@ where
     }
 }
 #[repr(C)]
-#[repr(align(4))]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct mach_msg_type_descriptor_t {
     pub _bitfield_align_1: [u32; 0],
diff --git a/bindgen-tests/tests/expectations/tests/bitfield_pragma_packed.rs b/bindgen-tests/tests/expectations/tests/bitfield_pragma_packed.rs
index c37b42f2..e3168f51 100644
--- a/bindgen-tests/tests/expectations/tests/bitfield_pragma_packed.rs
+++ b/bindgen-tests/tests/expectations/tests/bitfield_pragma_packed.rs
@@ -83,7 +83,7 @@ where
         }
     }
 }
-#[repr(C, packed)]
+#[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct Struct {
     pub _bitfield_align_1: [u8; 0],
@@ -215,3 +215,97 @@ impl Struct {
         __bindgen_bitfield_unit
     }
 }
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Inner {
+    pub _bitfield_align_1: [u16; 0],
+    pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>,
+}
+#[test]
+fn bindgen_test_layout_Inner() {
+    assert_eq!(
+        ::std::mem::size_of::<Inner>(),
+        4usize,
+        concat!("Size of: ", stringify!(Inner)),
+    );
+    assert_eq!(
+        ::std::mem::align_of::<Inner>(),
+        2usize,
+        concat!("Alignment of ", stringify!(Inner)),
+    );
+}
+impl Inner {
+    #[inline]
+    pub fn a(&self) -> ::std::os::raw::c_ushort {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(0usize, 16u8) as u16) }
+    }
+    #[inline]
+    pub fn set_a(&mut self, val: ::std::os::raw::c_ushort) {
+        unsafe {
+            let val: u16 = ::std::mem::transmute(val);
+            self._bitfield_1.set(0usize, 16u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn b(&self) -> ::std::os::raw::c_ushort {
+        unsafe { ::std::mem::transmute(self._bitfield_1.get(16usize, 16u8) as u16) }
+    }
+    #[inline]
+    pub fn set_b(&mut self, val: ::std::os::raw::c_ushort) {
+        unsafe {
+            let val: u16 = ::std::mem::transmute(val);
+            self._bitfield_1.set(16usize, 16u8, val as u64)
+        }
+    }
+    #[inline]
+    pub fn new_bitfield_1(
+        a: ::std::os::raw::c_ushort,
+        b: ::std::os::raw::c_ushort,
+    ) -> __BindgenBitfieldUnit<[u8; 4usize]> {
+        let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 4usize]> = Default::default();
+        __bindgen_bitfield_unit
+            .set(
+                0usize,
+                16u8,
+                {
+                    let a: u16 = unsafe { ::std::mem::transmute(a) };
+                    a as u64
+                },
+            );
+        __bindgen_bitfield_unit
+            .set(
+                16usize,
+                16u8,
+                {
+                    let b: u16 = unsafe { ::std::mem::transmute(b) };
+                    b as u64
+                },
+            );
+        __bindgen_bitfield_unit
+    }
+}
+#[repr(C, packed)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Outer {
+    pub inner: Inner,
+}
+#[test]
+fn bindgen_test_layout_Outer() {
+    const UNINIT: ::std::mem::MaybeUninit<Outer> = ::std::mem::MaybeUninit::uninit();
+    let ptr = UNINIT.as_ptr();
+    assert_eq!(
+        ::std::mem::size_of::<Outer>(),
+        4usize,
+        concat!("Size of: ", stringify!(Outer)),
+    );
+    assert_eq!(
+        ::std::mem::align_of::<Outer>(),
+        1usize,
+        concat!("Alignment of ", stringify!(Outer)),
+    );
+    assert_eq!(
+        unsafe { ::std::ptr::addr_of!((*ptr).inner) as usize - ptr as usize },
+        0usize,
+        concat!("Offset of field: ", stringify!(Outer), "::", stringify!(inner)),
+    );
+}
diff --git a/bindgen-tests/tests/expectations/tests/default_visibility_crate.rs b/bindgen-tests/tests/expectations/tests/default_visibility_crate.rs
index f75a06e9..aef1a61a 100644
--- a/bindgen-tests/tests/expectations/tests/default_visibility_crate.rs
+++ b/bindgen-tests/tests/expectations/tests/default_visibility_crate.rs
@@ -89,7 +89,7 @@ pub struct Point {
     pub(crate) x: ::std::os::raw::c_int,
     pub(crate) y: ::std::os::raw::c_int,
 }
-#[repr(C, packed)]
+#[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct Color {
     pub(crate) _bitfield_align_1: [u8; 0],
diff --git a/bindgen-tests/tests/expectations/tests/default_visibility_private.rs b/bindgen-tests/tests/expectations/tests/default_visibility_private.rs
index 9bd6409f..8b3099c0 100644
--- a/bindgen-tests/tests/expectations/tests/default_visibility_private.rs
+++ b/bindgen-tests/tests/expectations/tests/default_visibility_private.rs
@@ -89,7 +89,7 @@ pub struct Point {
     x: ::std::os::raw::c_int,
     y: ::std::os::raw::c_int,
 }
-#[repr(C, packed)]
+#[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct Color {
     _bitfield_align_1: [u8; 0],
diff --git a/bindgen-tests/tests/expectations/tests/default_visibility_private_respects_cxx_access_spec.rs b/bindgen-tests/tests/expectations/tests/default_visibility_private_respects_cxx_access_spec.rs
index a8b0d297..29fbb3a8 100644
--- a/bindgen-tests/tests/expectations/tests/default_visibility_private_respects_cxx_access_spec.rs
+++ b/bindgen-tests/tests/expectations/tests/default_visibility_private_respects_cxx_access_spec.rs
@@ -89,7 +89,7 @@ pub struct Point {
     pub x: ::std::os::raw::c_int,
     pub y: ::std::os::raw::c_int,
 }
-#[repr(C, packed)]
+#[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct Color {
     _bitfield_align_1: [u8; 0],
diff --git a/bindgen-tests/tests/expectations/tests/issue-1034.rs b/bindgen-tests/tests/expectations/tests/issue-1034.rs
index 0bd7647a..7848090f 100644
--- a/bindgen-tests/tests/expectations/tests/issue-1034.rs
+++ b/bindgen-tests/tests/expectations/tests/issue-1034.rs
@@ -83,7 +83,7 @@ where
         }
     }
 }
-#[repr(C, packed)]
+#[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct S2 {
     pub _bitfield_align_1: [u8; 0],
diff --git a/bindgen-tests/tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs b/bindgen-tests/tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs
index d8880695..89c09cc6 100644
--- a/bindgen-tests/tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs
+++ b/bindgen-tests/tests/expectations/tests/issue-1076-unnamed-bitfield-alignment.rs
@@ -83,7 +83,7 @@ where
         }
     }
 }
-#[repr(C, packed)]
+#[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct S1 {
     pub _bitfield_align_1: [u8; 0],
diff --git a/bindgen-tests/tests/expectations/tests/issue-1947.rs b/bindgen-tests/tests/expectations/tests/issue-1947.rs
index 24aa3548..be623357 100644
--- a/bindgen-tests/tests/expectations/tests/issue-1947.rs
+++ b/bindgen-tests/tests/expectations/tests/issue-1947.rs
@@ -86,7 +86,6 @@ where
 pub type U8 = ::std::os::raw::c_uchar;
 pub type U16 = ::std::os::raw::c_ushort;
 #[repr(C)]
-#[repr(align(2))]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct V56AMDY {
     pub _bitfield_align_1: [u16; 0],
diff --git a/bindgen-tests/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs b/bindgen-tests/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs
index adea1cbe..7bc99336 100644
--- a/bindgen-tests/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs
+++ b/bindgen-tests/tests/expectations/tests/issue-739-pointer-wide-bitfield.rs
@@ -85,7 +85,6 @@ where
     }
 }
 #[repr(C)]
-#[repr(align(8))]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct Foo {
     pub _bitfield_align_1: [u64; 0],
diff --git a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs
index 735cebfb..576f5758 100644
--- a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs
+++ b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque.rs
@@ -181,7 +181,6 @@ pub union jsval_layout {
     pub asUIntPtr: usize,
 }
 #[repr(C)]
-#[repr(align(8))]
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct jsval_layout__bindgen_ty_1 {
     pub _bitfield_align_1: [u64; 0],
diff --git a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque_1_0.rs b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque_1_0.rs
index 2e64796b..0889b652 100644
--- a/bindgen-tests/tests/expectations/tests/jsval_layout_opaque_1_0.rs
+++ b/bindgen-tests/tests/expectations/tests/jsval_layout_opaque_1_0.rs
@@ -229,7 +229,6 @@ pub struct jsval_layout {
 pub struct jsval_layout__bindgen_ty_1 {
     pub _bitfield_align_1: [u64; 0],
     pub _bitfield_1: __BindgenBitfieldUnit<[u8; 8usize]>,
-    pub __bindgen_align: [u64; 0usize],
 }
 #[test]
 fn bindgen_test_layout_jsval_layout__bindgen_ty_1() {
diff --git a/bindgen-tests/tests/expectations/tests/only_bitfields.rs b/bindgen-tests/tests/expectations/tests/only_bitfields.rs
index 42ea60f1..fe216f4b 100644
--- a/bindgen-tests/tests/expectations/tests/only_bitfields.rs
+++ b/bindgen-tests/tests/expectations/tests/only_bitfields.rs
@@ -83,7 +83,7 @@ where
         }
     }
 }
-#[repr(C, packed)]
+#[repr(C)]
 #[derive(Debug, Default, Copy, Clone)]
 pub struct C {
     pub _bitfield_align_1: [u8; 0],
diff --git a/bindgen-tests/tests/expectations/tests/union_bitfield.rs b/bindgen-tests/tests/expectations/tests/union_bitfield.rs
index 096c0371..7f4bd37f 100644
--- a/bindgen-tests/tests/expectations/tests/union_bitfield.rs
+++ b/bindgen-tests/tests/expectations/tests/union_bitfield.rs
@@ -142,7 +142,6 @@ impl U4 {
     }
 }
 #[repr(C)]
-#[repr(align(4))]
 #[derive(Copy, Clone)]
 pub union B {
     pub _bitfield_align_1: [u32; 0],
diff --git a/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield.rs b/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield.rs
index 2f990271..48a1bda9 100644
--- a/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield.rs
+++ b/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield.rs
@@ -90,7 +90,6 @@ pub union foo {
     pub __bindgen_anon_1: foo__bindgen_ty_1,
 }
 #[repr(C)]
-#[repr(align(4))]
 #[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct foo__bindgen_ty_1 {
     pub _bitfield_align_1: [u32; 0],
diff --git a/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield_1_0.rs b/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield_1_0.rs
index dec7fc29..530cb7ea 100644
--- a/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield_1_0.rs
+++ b/bindgen-tests/tests/expectations/tests/union_with_anon_struct_bitfield_1_0.rs
@@ -138,7 +138,6 @@ pub struct foo {
 pub struct foo__bindgen_ty_1 {
     pub _bitfield_align_1: [u32; 0],
     pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>,
-    pub __bindgen_align: [u32; 0usize],
 }
 #[test]
 fn bindgen_test_layout_foo__bindgen_ty_1() {
diff --git a/bindgen-tests/tests/headers/bitfield_pragma_packed.h b/bindgen-tests/tests/headers/bitfield_pragma_packed.h
index b4011ca8..c18b80dd 100644
--- a/bindgen-tests/tests/headers/bitfield_pragma_packed.h
+++ b/bindgen-tests/tests/headers/bitfield_pragma_packed.h
@@ -7,3 +7,14 @@ struct Struct {
     unsigned char e : 8;
 };
 #pragma pack(pop)
+
+struct Inner {
+    unsigned short a: 16;
+    unsigned short b: 16;
+};
+
+#pragma pack(push, 1)
+struct Outer {
+    struct Inner inner;
+};
+#pragma pop