From ad9af55ac2a87db5fe282b403d7e8b125101980a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 27 Aug 2025 18:45:50 +0200 Subject: [PATCH 1/2] codegen: Appease nightly clippy too. --- bindgen/codegen/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 25118f2a89..60e3404875 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -3749,7 +3749,7 @@ impl CodeGenerator for Enum { utils::call_discovered_item_callback(ctx, item, || { DiscoveredItem::Enum { - final_name: name.to_string(), + final_name: name.clone(), } }); @@ -4653,7 +4653,7 @@ impl CodeGenerator for Function { } utils::call_discovered_item_callback(ctx, item, || { DiscoveredItem::Function { - final_name: canonical_name.to_string(), + final_name: canonical_name.clone(), } }); From 4e159b741a2adef1a224fb832a2e28d1af8f595c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 27 Aug 2025 16:46:50 +0200 Subject: [PATCH 2/2] codegen: Guarantee opaque type layout across all architectures. Fixes #3279 --- .../tests/bitfield_large_overflow.rs | 10 +++- ...ive-debug-opaque-template-instantiation.rs | 25 ++------- .../expectations/tests/derive-debug-opaque.rs | 40 ++++--------- .../tests/expectations/tests/issue-3027.rs | 10 ++-- .../tests/expectations/tests/issue-372.rs | 22 ++------ .../tests/issue-544-stylo-creduce-2.rs | 10 ++-- .../tests/expectations/tests/layout_array.rs | 10 +++- .../tests/layout_large_align_field.rs | 10 +++- .../libclang-9/issue-544-stylo-creduce-2.rs | 14 ++--- .../expectations/tests/non-type-params.rs | 14 ++--- .../expectations/tests/nsBaseHashtable.rs | 10 ++-- .../tests/expectations/tests/objc_template.rs | 15 ++++- .../tests/opaque-template-inst-member.rs | 33 +++-------- .../partial-specialization-and-inheritance.rs | 10 ++-- .../expectations/tests/size_t_template.rs | 10 ++-- .../tests/expectations/tests/unknown_attr.rs | 10 +++- .../tests/va_list_aarch64_linux.rs | 14 ++--- bindgen/codegen/helpers.rs | 50 +++++++++-------- bindgen/codegen/mod.rs | 52 ++++++++++------- bindgen/ir/analysis/derive.rs | 49 ++++------------ bindgen/ir/context.rs | 19 +++++-- bindgen/ir/item.rs | 3 +- bindgen/ir/layout.rs | 56 ------------------- bindgen/ir/ty.rs | 18 +++++- 24 files changed, 212 insertions(+), 302 deletions(-) diff --git a/bindgen-tests/tests/expectations/tests/bitfield_large_overflow.rs b/bindgen-tests/tests/expectations/tests/bitfield_large_overflow.rs index ed7d1b3bb7..ac5d75735e 100644 --- a/bindgen-tests/tests/expectations/tests/bitfield_large_overflow.rs +++ b/bindgen-tests/tests/expectations/tests/bitfield_large_overflow.rs @@ -1,9 +1,17 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] +#[repr(C, align(8))] +pub struct __BindgenOpaqueArray8(pub T); +impl Default for __BindgenOpaqueArray8<[T; N]> { + fn default() -> Self { + Self([::default(); N]) + } +} #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct _bindgen_ty_1 { pub _bindgen_align: [u64; 0], - pub _bindgen_opaque_blob: [u64; 10usize], + pub _bindgen_opaque_blob: __BindgenOpaqueArray8<[u8; 80usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { diff --git a/bindgen-tests/tests/expectations/tests/derive-debug-opaque-template-instantiation.rs b/bindgen-tests/tests/expectations/tests/derive-debug-opaque-template-instantiation.rs index ac564a3cf6..9d75e74d77 100644 --- a/bindgen-tests/tests/expectations/tests/derive-debug-opaque-template-instantiation.rs +++ b/bindgen-tests/tests/expectations/tests/derive-debug-opaque-template-instantiation.rs @@ -1,17 +1,16 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -/// If Bindgen could only determine the size and alignment of a -/// type, it is represented like this. -#[derive(PartialEq, Copy, Clone, Debug, Hash)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[repr(C)] -pub struct __BindgenOpaqueArray(pub [T; N]); -impl Default for __BindgenOpaqueArray { +pub struct __BindgenOpaqueArray(pub T); +impl Default for __BindgenOpaqueArray<[T; N]> { fn default() -> Self { Self([::default(); N]) } } #[repr(C)] +#[derive(Debug, Default, Copy, Clone)] pub struct Instance { - pub val: __BindgenOpaqueArray, + pub val: __BindgenOpaqueArray<[u32; 50usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { @@ -19,17 +18,3 @@ const _: () = { ["Alignment of Instance"][::std::mem::align_of::() - 4usize]; ["Offset of field: Instance::val"][::std::mem::offset_of!(Instance, val) - 0usize]; }; -impl Default for Instance { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -impl ::std::fmt::Debug for Instance { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "Instance {{ val: opaque }}") - } -} diff --git a/bindgen-tests/tests/expectations/tests/derive-debug-opaque.rs b/bindgen-tests/tests/expectations/tests/derive-debug-opaque.rs index c8b3f10b93..4ec1fb2a35 100644 --- a/bindgen-tests/tests/expectations/tests/derive-debug-opaque.rs +++ b/bindgen-tests/tests/expectations/tests/derive-debug-opaque.rs @@ -1,29 +1,25 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] +#[repr(C)] +pub struct __BindgenOpaqueArray(pub T); +impl Default for __BindgenOpaqueArray<[T; N]> { + fn default() -> Self { + Self([::default(); N]) + } +} #[repr(C)] #[repr(align(4))] +#[derive(Debug, Default, Copy, Clone)] pub struct Opaque { - pub _bindgen_opaque_blob: [u32; 41usize], + pub _bindgen_opaque_blob: __BindgenOpaqueArray<[u32; 41usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { ["Size of Opaque"][::std::mem::size_of::() - 164usize]; ["Alignment of Opaque"][::std::mem::align_of::() - 4usize]; }; -impl Default for Opaque { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -impl ::std::fmt::Debug for Opaque { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "Opaque {{ opaque }}") - } -} #[repr(C)] +#[derive(Debug, Default, Copy, Clone)] pub struct OpaqueUser { pub opaque: Opaque, } @@ -35,17 +31,3 @@ const _: () = { "Offset of field: OpaqueUser::opaque", ][::std::mem::offset_of!(OpaqueUser, opaque) - 0usize]; }; -impl Default for OpaqueUser { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -impl ::std::fmt::Debug for OpaqueUser { - fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - write!(f, "OpaqueUser {{ opaque: {:?} }}", self.opaque) - } -} diff --git a/bindgen-tests/tests/expectations/tests/issue-3027.rs b/bindgen-tests/tests/expectations/tests/issue-3027.rs index 757aa9d9df..c8c2a7e542 100644 --- a/bindgen-tests/tests/expectations/tests/issue-3027.rs +++ b/bindgen-tests/tests/expectations/tests/issue-3027.rs @@ -1,12 +1,10 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] #[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] pub mod root { - /// If Bindgen could only determine the size and alignment of a - /// type, it is represented like this. - #[derive(PartialEq, Copy, Clone, Debug, Hash)] + #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[repr(C)] - pub struct __BindgenOpaqueArray(pub [T; N]); - impl Default for __BindgenOpaqueArray { + pub struct __BindgenOpaqueArray(pub T); + impl Default for __BindgenOpaqueArray<[T; N]> { fn default() -> Self { Self([::default(); N]) } @@ -19,7 +17,7 @@ pub mod root { #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct C { - pub a: root::__BindgenOpaqueArray, + pub a: root::__BindgenOpaqueArray<[u8; 3usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { diff --git a/bindgen-tests/tests/expectations/tests/issue-372.rs b/bindgen-tests/tests/expectations/tests/issue-372.rs index 62160d6351..cf00a70743 100644 --- a/bindgen-tests/tests/expectations/tests/issue-372.rs +++ b/bindgen-tests/tests/expectations/tests/issue-372.rs @@ -1,12 +1,10 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] #[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] pub mod root { - /// If Bindgen could only determine the size and alignment of a - /// type, it is represented like this. - #[derive(PartialEq, Copy, Clone, Debug, Hash)] - #[repr(C)] - pub struct __BindgenOpaqueArray(pub [T; N]); - impl Default for __BindgenOpaqueArray { + #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] + #[repr(C, align(8))] + pub struct __BindgenOpaqueArray8(pub T); + impl Default for __BindgenOpaqueArray8<[T; N]> { fn default() -> Self { Self([::default(); N]) } @@ -74,8 +72,9 @@ pub mod root { ai = 11, } #[repr(C)] + #[derive(Debug, Default, Copy, Clone)] pub struct F { - pub w: root::__BindgenOpaqueArray, + pub w: root::__BindgenOpaqueArray8<[u8; 264usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { @@ -83,13 +82,4 @@ pub mod root { ["Alignment of F"][::std::mem::align_of::() - 8usize]; ["Offset of field: F::w"][::std::mem::offset_of!(F, w) - 0usize]; }; - impl Default for F { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } - } } diff --git a/bindgen-tests/tests/expectations/tests/issue-544-stylo-creduce-2.rs b/bindgen-tests/tests/expectations/tests/issue-544-stylo-creduce-2.rs index 8a752f6999..a160d0275d 100644 --- a/bindgen-tests/tests/expectations/tests/issue-544-stylo-creduce-2.rs +++ b/bindgen-tests/tests/expectations/tests/issue-544-stylo-creduce-2.rs @@ -1,10 +1,8 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -/// If Bindgen could only determine the size and alignment of a -/// type, it is represented like this. -#[derive(PartialEq, Copy, Clone, Debug, Hash)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[repr(C)] -pub struct __BindgenOpaqueArray(pub [T; N]); -impl Default for __BindgenOpaqueArray { +pub struct __BindgenOpaqueArray(pub T); +impl Default for __BindgenOpaqueArray<[T; N]> { fn default() -> Self { Self([::default(); N]) } @@ -14,7 +12,7 @@ impl Default for __BindgenOpaqueArray { pub struct Foo { pub member: *mut Foo_SecondAlias, } -pub type Foo_FirstAlias = __BindgenOpaqueArray; +pub type Foo_FirstAlias = __BindgenOpaqueArray<[u8; 0usize]>; pub type Foo_SecondAlias = Foo; impl Default for Foo { fn default() -> Self { diff --git a/bindgen-tests/tests/expectations/tests/layout_array.rs b/bindgen-tests/tests/expectations/tests/layout_array.rs index a2805b7060..3afe1c2dd8 100644 --- a/bindgen-tests/tests/expectations/tests/layout_array.rs +++ b/bindgen-tests/tests/expectations/tests/layout_array.rs @@ -1,4 +1,12 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] +#[repr(C, align(8))] +pub struct __BindgenOpaqueArray8(pub T); +impl Default for __BindgenOpaqueArray8<[T; N]> { + fn default() -> Self { + Self([::default(); N]) + } +} pub const RTE_CACHE_LINE_SIZE: u32 = 64; pub const RTE_MEMPOOL_OPS_NAMESIZE: u32 = 32; pub const RTE_MEMPOOL_MAX_OPS_IDX: u32 = 16; @@ -125,7 +133,7 @@ pub struct rte_mempool_ops_table { pub sl: rte_spinlock_t, ///< Number of used ops structs in the table. pub num_ops: u32, - pub __bindgen_padding_0: [u64; 7usize], + pub __bindgen_padding_0: __BindgenOpaqueArray8<[u8; 56usize]>, /// Storage for all possible ops structs. pub ops: [rte_mempool_ops; 16usize], } diff --git a/bindgen-tests/tests/expectations/tests/layout_large_align_field.rs b/bindgen-tests/tests/expectations/tests/layout_large_align_field.rs index 3be68eb925..0ccd40a5f8 100644 --- a/bindgen-tests/tests/expectations/tests/layout_large_align_field.rs +++ b/bindgen-tests/tests/expectations/tests/layout_large_align_field.rs @@ -1,4 +1,12 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] +#[repr(C, align(8))] +pub struct __BindgenOpaqueArray8(pub T); +impl Default for __BindgenOpaqueArray8<[T; N]> { + fn default() -> Self { + Self([::default(); N]) + } +} #[repr(C)] #[derive(Default)] pub struct __IncompleteArrayField(::std::marker::PhantomData, [T; 0]); @@ -286,7 +294,7 @@ pub struct rte_ip_frag_tbl { pub last: *mut ip_frag_pkt, ///< LRU list for table entries. pub lru: ip_pkt_list, - pub __bindgen_padding_0: u64, + pub __bindgen_padding_0: __BindgenOpaqueArray8<[u8; 8usize]>, ///< statistics counters. pub stat: ip_frag_tbl_stat, ///< hash table. diff --git a/bindgen-tests/tests/expectations/tests/libclang-9/issue-544-stylo-creduce-2.rs b/bindgen-tests/tests/expectations/tests/libclang-9/issue-544-stylo-creduce-2.rs index 7f0471bd96..d64a8948ee 100644 --- a/bindgen-tests/tests/expectations/tests/libclang-9/issue-544-stylo-creduce-2.rs +++ b/bindgen-tests/tests/expectations/tests/libclang-9/issue-544-stylo-creduce-2.rs @@ -1,10 +1,8 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -/// If Bindgen could only determine the size and alignment of a -/// type, it is represented like this. -#[derive(PartialEq, Copy, Clone, Debug, Hash)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[repr(C)] -pub struct __BindgenOpaqueArray(pub [T; N]); -impl Default for __BindgenOpaqueArray { +pub struct __BindgenOpaqueArray(pub T); +impl Default for __BindgenOpaqueArray<[T; N]> { fn default() -> Self { Self([::default(); N]) } @@ -12,10 +10,10 @@ impl Default for __BindgenOpaqueArray { #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct Foo { - pub member: *mut __BindgenOpaqueArray, + pub member: *mut __BindgenOpaqueArray<[u8; 0usize]>, } -pub type Foo_FirstAlias = __BindgenOpaqueArray; -pub type Foo_SecondAlias = __BindgenOpaqueArray; +pub type Foo_FirstAlias = __BindgenOpaqueArray<[u8; 0usize]>; +pub type Foo_SecondAlias = __BindgenOpaqueArray<[u8; 0usize]>; impl Default for Foo { fn default() -> Self { let mut s = ::std::mem::MaybeUninit::::uninit(); diff --git a/bindgen-tests/tests/expectations/tests/non-type-params.rs b/bindgen-tests/tests/expectations/tests/non-type-params.rs index afd21fb767..325620b9bb 100644 --- a/bindgen-tests/tests/expectations/tests/non-type-params.rs +++ b/bindgen-tests/tests/expectations/tests/non-type-params.rs @@ -1,21 +1,19 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -/// If Bindgen could only determine the size and alignment of a -/// type, it is represented like this. -#[derive(PartialEq, Copy, Clone, Debug, Hash)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[repr(C)] -pub struct __BindgenOpaqueArray(pub [T; N]); -impl Default for __BindgenOpaqueArray { +pub struct __BindgenOpaqueArray(pub T); +impl Default for __BindgenOpaqueArray<[T; N]> { fn default() -> Self { Self([::default(); N]) } } pub type Array16 = u8; -pub type ArrayInt4 = __BindgenOpaqueArray; +pub type ArrayInt4 = __BindgenOpaqueArray<[u32; 4usize]>; #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct UsesArray { - pub array_char_16: __BindgenOpaqueArray, - pub array_bool_8: __BindgenOpaqueArray, + pub array_char_16: __BindgenOpaqueArray<[u8; 16usize]>, + pub array_bool_8: __BindgenOpaqueArray<[u8; 8usize]>, pub array_int_4: ArrayInt4, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/nsBaseHashtable.rs b/bindgen-tests/tests/expectations/tests/nsBaseHashtable.rs index 32fcc37aba..81b9f000c6 100644 --- a/bindgen-tests/tests/expectations/tests/nsBaseHashtable.rs +++ b/bindgen-tests/tests/expectations/tests/nsBaseHashtable.rs @@ -1,10 +1,8 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -/// If Bindgen could only determine the size and alignment of a -/// type, it is represented like this. -#[derive(PartialEq, Copy, Clone, Debug, Hash)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[repr(C)] -pub struct __BindgenOpaqueArray(pub [T; N]); -impl Default for __BindgenOpaqueArray { +pub struct __BindgenOpaqueArray(pub T); +impl Default for __BindgenOpaqueArray<[T; N]> { fn default() -> Self { Self([::default(); N]) } @@ -24,7 +22,7 @@ pub struct nsTHashtable { pub struct nsBaseHashtable { pub _address: u8, } -pub type nsBaseHashtable_KeyType = __BindgenOpaqueArray; +pub type nsBaseHashtable_KeyType = __BindgenOpaqueArray<[u8; 0usize]>; pub type nsBaseHashtable_EntryType = nsBaseHashtableET; #[repr(C)] #[derive(Debug, Copy, Clone)] diff --git a/bindgen-tests/tests/expectations/tests/objc_template.rs b/bindgen-tests/tests/expectations/tests/objc_template.rs index ee47f67d4c..1c70009df3 100644 --- a/bindgen-tests/tests/expectations/tests/objc_template.rs +++ b/bindgen-tests/tests/expectations/tests/objc_template.rs @@ -3,6 +3,14 @@ use objc::{self, msg_send, sel, sel_impl, class}; #[allow(non_camel_case_types)] pub type id = *mut objc::runtime::Object; +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] +#[repr(C, align(8))] +pub struct __BindgenOpaqueArray8(pub T); +impl Default for __BindgenOpaqueArray8<[T; N]> { + fn default() -> Self { + Self([::default(); N]) + } +} #[repr(transparent)] #[derive(Debug, Copy, Clone)] pub struct Foo(pub id); @@ -20,7 +28,7 @@ impl Foo { } impl IFoo for Foo {} pub trait IFoo: Sized + std::ops::Deref { - unsafe fn get(&self) -> u64 + unsafe fn get(&self) -> __BindgenOpaqueArray8<[u8; 8usize]> where ::Target: objc::Message + Sized, { @@ -48,7 +56,10 @@ pub trait IFooMultiGeneric< KeyType: 'static, ObjectType: 'static, >: Sized + std::ops::Deref { - unsafe fn objectForKey_(&self, key: u64) -> u64 + unsafe fn objectForKey_( + &self, + key: __BindgenOpaqueArray8<[u8; 8usize]>, + ) -> __BindgenOpaqueArray8<[u8; 8usize]> where ::Target: objc::Message + Sized, { diff --git a/bindgen-tests/tests/expectations/tests/opaque-template-inst-member.rs b/bindgen-tests/tests/expectations/tests/opaque-template-inst-member.rs index cc02195939..f765f01150 100644 --- a/bindgen-tests/tests/expectations/tests/opaque-template-inst-member.rs +++ b/bindgen-tests/tests/expectations/tests/opaque-template-inst-member.rs @@ -1,10 +1,8 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -/// If Bindgen could only determine the size and alignment of a -/// type, it is represented like this. -#[derive(PartialEq, Copy, Clone, Debug, Hash)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[repr(C)] -pub struct __BindgenOpaqueArray(pub [T; N]); -impl Default for __BindgenOpaqueArray { +pub struct __BindgenOpaqueArray(pub T); +impl Default for __BindgenOpaqueArray<[T; N]> { fn default() -> Self { Self([::default(); N]) } @@ -17,8 +15,9 @@ pub struct OpaqueTemplate { /** This should not end up deriving Debug/Hash because its `mBlah` field cannot derive Debug/Hash because the instantiation's definition cannot derive Debug/Hash.*/ #[repr(C)] +#[derive(Debug, Default, Copy, Clone, Hash, PartialEq, Eq)] pub struct ContainsOpaqueTemplate { - pub mBlah: __BindgenOpaqueArray, + pub mBlah: __BindgenOpaqueArray<[u32; 101usize]>, pub mBaz: ::std::os::raw::c_int, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] @@ -36,25 +35,12 @@ const _: () = { "Offset of field: ContainsOpaqueTemplate::mBaz", ][::std::mem::offset_of!(ContainsOpaqueTemplate, mBaz) - 404usize]; }; -impl Default for ContainsOpaqueTemplate { - fn default() -> Self { - let mut s = ::std::mem::MaybeUninit::::uninit(); - unsafe { - ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -impl ::std::cmp::PartialEq for ContainsOpaqueTemplate { - fn eq(&self, other: &ContainsOpaqueTemplate) -> bool { - self.mBlah == other.mBlah && self.mBaz == other.mBaz - } -} /** This should not end up deriving Debug/Hash either, for similar reasons, although we're exercising base member edges now.*/ #[repr(C)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct InheritsOpaqueTemplate { - pub _base: __BindgenOpaqueArray, + pub _base: __BindgenOpaqueArray<[u8; 401usize]>, pub wow: *mut ::std::os::raw::c_char, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] @@ -78,8 +64,3 @@ impl Default for InheritsOpaqueTemplate { } } } -impl ::std::cmp::PartialEq for InheritsOpaqueTemplate { - fn eq(&self, other: &InheritsOpaqueTemplate) -> bool { - self._base == other._base && self.wow == other.wow - } -} diff --git a/bindgen-tests/tests/expectations/tests/partial-specialization-and-inheritance.rs b/bindgen-tests/tests/expectations/tests/partial-specialization-and-inheritance.rs index a4234d2aaa..cba5cfbb52 100644 --- a/bindgen-tests/tests/expectations/tests/partial-specialization-and-inheritance.rs +++ b/bindgen-tests/tests/expectations/tests/partial-specialization-and-inheritance.rs @@ -1,10 +1,8 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -/// If Bindgen could only determine the size and alignment of a -/// type, it is represented like this. -#[derive(PartialEq, Copy, Clone, Debug, Hash)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[repr(C)] -pub struct __BindgenOpaqueArray(pub [T; N]); -impl Default for __BindgenOpaqueArray { +pub struct __BindgenOpaqueArray(pub T); +impl Default for __BindgenOpaqueArray<[T; N]> { fn default() -> Self { Self([::default(); N]) } @@ -26,7 +24,7 @@ pub struct Usage { } unsafe extern "C" { #[link_name = "\u{1}_ZN5Usage13static_memberE"] - pub static mut Usage_static_member: __BindgenOpaqueArray; + pub static mut Usage_static_member: __BindgenOpaqueArray<[u32; 2usize]>; } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { diff --git a/bindgen-tests/tests/expectations/tests/size_t_template.rs b/bindgen-tests/tests/expectations/tests/size_t_template.rs index 9126c5071a..08ffa22750 100644 --- a/bindgen-tests/tests/expectations/tests/size_t_template.rs +++ b/bindgen-tests/tests/expectations/tests/size_t_template.rs @@ -1,10 +1,8 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -/// If Bindgen could only determine the size and alignment of a -/// type, it is represented like this. -#[derive(PartialEq, Copy, Clone, Debug, Hash)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] #[repr(C)] -pub struct __BindgenOpaqueArray(pub [T; N]); -impl Default for __BindgenOpaqueArray { +pub struct __BindgenOpaqueArray(pub T); +impl Default for __BindgenOpaqueArray<[T; N]> { fn default() -> Self { Self([::default(); N]) } @@ -12,7 +10,7 @@ impl Default for __BindgenOpaqueArray { #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct C { - pub arr: __BindgenOpaqueArray, + pub arr: __BindgenOpaqueArray<[u32; 3usize]>, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] const _: () = { diff --git a/bindgen-tests/tests/expectations/tests/unknown_attr.rs b/bindgen-tests/tests/expectations/tests/unknown_attr.rs index bdfebb29dc..d749dad977 100644 --- a/bindgen-tests/tests/expectations/tests/unknown_attr.rs +++ b/bindgen-tests/tests/expectations/tests/unknown_attr.rs @@ -1,10 +1,18 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] +#[repr(C, align(8))] +pub struct __BindgenOpaqueArray8(pub T); +impl Default for __BindgenOpaqueArray8<[T; N]> { + fn default() -> Self { + Self([::default(); N]) + } +} #[repr(C)] #[repr(align(16))] #[derive(Debug, Default, Copy, Clone)] pub struct max_align_t { pub __clang_max_align_nonce1: ::std::os::raw::c_longlong, - pub __bindgen_padding_0: u64, + pub __bindgen_padding_0: __BindgenOpaqueArray8<[u8; 8usize]>, pub __clang_max_align_nonce2: ::std::os::raw::c_longlong, } #[allow(clippy::unnecessary_operation, clippy::identity_op)] diff --git a/bindgen-tests/tests/expectations/tests/va_list_aarch64_linux.rs b/bindgen-tests/tests/expectations/tests/va_list_aarch64_linux.rs index 31f75ced23..b33f4894c1 100644 --- a/bindgen-tests/tests/expectations/tests/va_list_aarch64_linux.rs +++ b/bindgen-tests/tests/expectations/tests/va_list_aarch64_linux.rs @@ -1,18 +1,16 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -/// If Bindgen could only determine the size and alignment of a -/// type, it is represented like this. -#[derive(PartialEq, Copy, Clone, Debug, Hash)] -#[repr(C)] -pub struct __BindgenOpaqueArray(pub [T; N]); -impl Default for __BindgenOpaqueArray { +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] +#[repr(C, align(8))] +pub struct __BindgenOpaqueArray8(pub T); +impl Default for __BindgenOpaqueArray8<[T; N]> { fn default() -> Self { Self([::default(); N]) } } -pub type va_list = __BindgenOpaqueArray; +pub type va_list = __BindgenOpaqueArray8<[u8; 32usize]>; unsafe extern "C" { pub fn vprintf( format: *const ::std::os::raw::c_char, - vlist: __BindgenOpaqueArray, + vlist: __BindgenOpaqueArray8<[u8; 32usize]>, ) -> ::std::os::raw::c_int; } diff --git a/bindgen/codegen/helpers.rs b/bindgen/codegen/helpers.rs index 9b2e5256c3..19338ee65f 100644 --- a/bindgen/codegen/helpers.rs +++ b/bindgen/codegen/helpers.rs @@ -4,6 +4,7 @@ use proc_macro2::{Ident, Span}; use crate::ir::context::BindgenContext; use crate::ir::layout::Layout; +use crate::ir::ty::RUST_DERIVE_IN_ARRAY_LIMIT; pub(crate) mod attributes { use proc_macro2::{Ident, Span, TokenStream}; @@ -85,32 +86,33 @@ pub(crate) fn blob( layout: Layout, ffi_safe: bool, ) -> syn::Type { - let opaque = layout.opaque(); - - // FIXME(emilio, #412): We fall back to byte alignment, but there are - // some things that legitimately are more than 8-byte aligned. - // - // Eventually we should be able to `unwrap` here, but... - let ty = opaque.known_rust_type_for_array().unwrap_or_else(|| { - warn!("Found unknown alignment on code generation!"); - syn::parse_quote! { u8 } - }); - - let data_len = opaque.array_size().unwrap_or(layout.size); - - if data_len == 1 { - ty - } else if ffi_safe { - ctx.generated_opaque_array(); - if ctx.options().enable_cxx_namespaces { - syn::parse_quote! { root::__BindgenOpaqueArray<#ty, #data_len> } + let align = layout.align.max(1); + // For alignments <= 4, it holds that the integer type of the same size aligns to that same + // size. For bigger alignments that's not guaranteed, e.g. on x86 u64 is aligned to 4 bytes. + if align <= 4 { + let ty = Layout::known_type_for_size(align).unwrap(); + let len = layout.size / align; + return if len == 1 { + ty + } else if !ffi_safe && len <= RUST_DERIVE_IN_ARRAY_LIMIT { + syn::parse_quote! { [#ty; #len] } } else { - syn::parse_quote! { __BindgenOpaqueArray<#ty, #data_len> } - } + ctx.generated_opaque_array(1); + if ctx.options().enable_cxx_namespaces { + syn::parse_quote! { root::__BindgenOpaqueArray<[#ty; #len]> } + } else { + syn::parse_quote! { __BindgenOpaqueArray<[#ty; #len]> } + } + }; + } + + ctx.generated_opaque_array(align); + let ident = format_ident!("__BindgenOpaqueArray{}", align); + let size = layout.size; + if ctx.options().enable_cxx_namespaces { + syn::parse_quote! { root::#ident<[u8; #size]> } } else { - // This is not FFI safe as an argument; the struct above is - // preferable. - syn::parse_quote! { [ #ty ; #data_len ] } + syn::parse_quote! { #ident<[u8; #size]> } } } diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 60e3404875..295029e0d9 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -580,9 +580,7 @@ impl CodeGenerator for Module { if ctx.need_bindgen_complex_type() { utils::prepend_complex_type(&mut *result); } - if ctx.need_opaque_array_type() { - utils::prepend_opaque_array_type(&mut *result); - } + utils::prepend_opaque_array_types(ctx, &mut *result); if result.saw_objc { utils::prepend_objc_header(ctx, &mut *result); } @@ -2259,14 +2257,13 @@ impl CodeGenerator for CompInfo { if has_address { let layout = Layout::new(1, 1); - let ty = helpers::blob(ctx, Layout::new(1, 1), false); struct_layout.saw_field_with_layout( "_address", layout, /* offset = */ Some(0), ); fields.push(quote! { - pub _address: #ty, + pub _address: u8, }); } } @@ -2275,7 +2272,6 @@ impl CodeGenerator for CompInfo { match layout { Some(l) => { explicit_align = Some(l.align); - let ty = helpers::blob(ctx, l, false); fields.push(quote! { pub _bindgen_opaque_blob: #ty , @@ -2312,7 +2308,7 @@ impl CodeGenerator for CompInfo { if !struct_layout.is_rust_union() { let ty = helpers::blob(ctx, layout, false); fields.push(quote! { - pub bindgen_union_field: #ty , + pub bindgen_union_field: #ty, }); } } @@ -5610,23 +5606,37 @@ pub(crate) mod utils { result.extend(old_items); } - pub(crate) fn prepend_opaque_array_type( + pub(crate) fn prepend_opaque_array_types( + ctx: &BindgenContext, result: &mut Vec, ) { - let ty = quote! { - /// If Bindgen could only determine the size and alignment of a - /// type, it is represented like this. - #[derive(PartialEq, Copy, Clone, Debug, Hash)] - #[repr(C)] - pub struct __BindgenOpaqueArray(pub [T; N]); - impl Default for __BindgenOpaqueArray { - fn default() -> Self { - Self([::default(); N]) + let mut tys = vec![]; + // If Bindgen could only determine the size and alignment of a type, it is represented like + // this. + for align in ctx.opaque_array_types_needed() { + let ident = if align == 1 { + format_ident!("__BindgenOpaqueArray") + } else { + format_ident!("__BindgenOpaqueArray{}", align) + }; + let repr = if align <= 1 { + quote! { #[repr(C)] } + } else { + let explicit = super::helpers::ast_ty::int_expr(align as i64); + quote! { #[repr(C, align(#explicit))] } + }; + tys.push(quote! { + #[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] + #repr + pub struct #ident(pub T); + impl Default for #ident<[T; N]> { + fn default() -> Self { + Self([::default(); N]) + } } - } - }; - - result.insert(0, ty); + }); + } + result.splice(0..0, tys); } pub(crate) fn build_path( diff --git a/bindgen/ir/analysis/derive.rs b/bindgen/ir/analysis/derive.rs index b1f167fb6c..7316950ba2 100644 --- a/bindgen/ir/analysis/derive.rs +++ b/bindgen/ir/analysis/derive.rs @@ -179,26 +179,11 @@ impl CannotDerive<'_> { return CanDerive::No; } - let layout_can_derive = - ty.layout(self.ctx).map_or(CanDerive::Yes, |l| { - l.opaque().array_size_within_derive_limit() - }); - - match layout_can_derive { - CanDerive::Yes => { - trace!( - " we can trivially derive {} for the layout", - self.derive_trait - ); - } - _ => { - trace!( - " we cannot derive {} for the layout", - self.derive_trait - ); - } - } - return layout_can_derive; + trace!( + " we can trivially derive {} for the layout", + self.derive_trait + ); + return CanDerive::Yes; } match *ty.kind() { @@ -338,25 +323,11 @@ impl CannotDerive<'_> { return CanDerive::No; } - let layout_can_derive = - ty.layout(self.ctx).map_or(CanDerive::Yes, |l| { - l.opaque().array_size_within_derive_limit() - }); - match layout_can_derive { - CanDerive::Yes => { - trace!( - " union layout can trivially derive {}", - self.derive_trait - ); - } - _ => { - trace!( - " union layout cannot derive {}", - self.derive_trait - ); - } - } - return layout_can_derive; + trace!( + " union layout can trivially derive {}", + self.derive_trait + ); + return CanDerive::Yes; } } diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index 47f837f966..346d2932f7 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -387,7 +387,7 @@ pub(crate) struct BindgenContext { options: BindgenOptions, /// Whether an opaque array was generated - generated_opaque_array: Cell, + generated_opaque_array: RefCell>, /// Whether a bindgen complex was generated generated_bindgen_complex: Cell, @@ -596,7 +596,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" options, generated_bindgen_complex: Cell::new(false), generated_bindgen_float16: Cell::new(false), - generated_opaque_array: Cell::new(false), + generated_opaque_array: Default::default(), allowlisted: None, blocklisted_types_implement_traits: Default::default(), codegen_items: None, @@ -2588,13 +2588,20 @@ If you encounter an error missing from this list, please file an issue or a PR!" } /// Call if an opaque array is generated - pub(crate) fn generated_opaque_array(&self) { - self.generated_opaque_array.set(true); + pub(crate) fn generated_opaque_array(&self, align: usize) { + self.generated_opaque_array.borrow_mut().insert(align); } /// Whether we need to generate the opaque array type - pub(crate) fn need_opaque_array_type(&self) -> bool { - self.generated_opaque_array.get() + pub(crate) fn opaque_array_types_needed(&self) -> Vec { + let mut alignments = self + .generated_opaque_array + .borrow() + .iter() + .copied() + .collect::>(); + alignments.sort_unstable(); + alignments } /// Call if a bindgen complex is generated diff --git a/bindgen/ir/item.rs b/bindgen/ir/item.rs index d38879f390..260c5e8764 100644 --- a/bindgen/ir/item.rs +++ b/bindgen/ir/item.rs @@ -12,7 +12,6 @@ use super::derive::{ use super::dot::DotAttributes; use super::function::{Function, FunctionKind}; use super::item_kind::ItemKind; -use super::layout::Opaque; use super::module::Module; use super::template::{AsTemplateParam, TemplateParameters}; use super::traversal::{EdgeKind, Trace, Tracer}; @@ -451,7 +450,7 @@ impl Item { ctx: &mut BindgenContext, ) -> TypeId { let location = ty.declaration().location(); - let ty = Opaque::from_clang_ty(ty, ctx); + let ty = Type::new_opaque_from_clang_ty(ty, ctx); let kind = ItemKind::Type(ty); let parent = ctx.root_module().into(); ctx.add_item( diff --git a/bindgen/ir/layout.rs b/bindgen/ir/layout.rs index 905e47c732..ba570e3702 100644 --- a/bindgen/ir/layout.rs +++ b/bindgen/ir/layout.rs @@ -1,10 +1,6 @@ //! Intermediate representation for the physical layout of some type. -use super::derive::CanDerive; -use super::ty::{Type, TypeKind, RUST_DERIVE_IN_ARRAY_LIMIT}; -use crate::clang; use crate::ir::context::BindgenContext; -use std::cmp; /// A type that represents the struct layout of a type. #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -71,56 +67,4 @@ impl Layout { pub(crate) fn for_size(ctx: &BindgenContext, size: usize) -> Self { Self::for_size_internal(ctx.target_pointer_size(), size) } - - /// Get this layout as an opaque type. - pub(crate) fn opaque(&self) -> Opaque { - Opaque(*self) - } -} - -/// When we are treating a type as opaque, it is just a blob with a `Layout`. -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct Opaque(pub(crate) Layout); - -impl Opaque { - /// Construct a new opaque type from the given clang type. - pub(crate) fn from_clang_ty( - ty: &clang::Type, - ctx: &BindgenContext, - ) -> Type { - let layout = Layout::new(ty.size(ctx), ty.align(ctx)); - let ty_kind = TypeKind::Opaque; - let is_const = ty.is_const(); - Type::new(None, Some(layout), ty_kind, is_const) - } - - /// Return the known rust type we should use to create a correctly-aligned - /// field with this layout. - pub(crate) fn known_rust_type_for_array(&self) -> Option { - Layout::known_type_for_size(self.0.align) - } - - /// Return the array size that an opaque type for this layout should have if - /// we know the correct type for it, or `None` otherwise. - pub(crate) fn array_size(&self) -> Option { - if self.known_rust_type_for_array().is_some() { - Some(self.0.size / cmp::max(self.0.align, 1)) - } else { - None - } - } - - /// Return `true` if this opaque layout's array size will fit within the - /// maximum number of array elements that Rust allows deriving traits - /// with. Return `false` otherwise. - pub(crate) fn array_size_within_derive_limit(&self) -> CanDerive { - if self - .array_size() - .is_some_and(|size| size <= RUST_DERIVE_IN_ARRAY_LIMIT) - { - CanDerive::Yes - } else { - CanDerive::Manually - } - } } diff --git a/bindgen/ir/ty.rs b/bindgen/ir/ty.rs index 5819f1118f..a53de31c6a 100644 --- a/bindgen/ir/ty.rs +++ b/bindgen/ir/ty.rs @@ -6,7 +6,7 @@ use super::dot::DotAttributes; use super::enum_ty::Enum; use super::function::FunctionSig; use super::item::{IsOpaque, Item}; -use super::layout::{Layout, Opaque}; +use super::layout::Layout; use super::objc::ObjCInterface; use super::template::{ AsTemplateParam, TemplateInstantiation, TemplateParameters, @@ -67,6 +67,17 @@ impl Type { } } + /// Construct an opaque item from a clang type. + pub(crate) fn new_opaque_from_clang_ty( + ty: &clang::Type, + ctx: &BindgenContext, + ) -> Self { + let layout = Layout::new(ty.size(ctx), ty.align(ctx)); + let ty_kind = TypeKind::Opaque; + let is_const = ty.is_const(); + Type::new(None, Some(layout), ty_kind, is_const) + } + /// Which kind of type is this? pub(crate) fn kind(&self) -> &TypeKind { &self.kind @@ -737,7 +748,7 @@ impl Type { opaque type instead." ); return Ok(ParseResult::New( - Opaque::from_clang_ty(&canonical_ty, ctx), + Self::new_opaque_from_clang_ty(&canonical_ty, ctx), None, )); } @@ -868,7 +879,8 @@ impl Type { from class template or base \ specifier, using opaque blob" ); - let opaque = Opaque::from_clang_ty(ty, ctx); + let opaque = + Self::new_opaque_from_clang_ty(ty, ctx); return Ok(ParseResult::New(opaque, None)); } }