From 52a0113146481970267ab05655c0f42581111f79 Mon Sep 17 00:00:00 2001 From: Weston Carvalho Date: Wed, 13 Jan 2021 10:04:50 -0800 Subject: [PATCH] Generate fields as non-pub if they would be access restricted in C++. --- src/clang.rs | 9 + src/codegen/mod.rs | 54 +- src/ir/comp.rs | 52 +- src/lib.rs | 15 + src/options.rs | 7 + .../tests/no_debug_whitelisted.rs | 7 +- tests/expectations/tests/private_fields.rs | 522 ++++++++++++++++++ tests/headers/private_fields.hpp | 44 ++ 8 files changed, 684 insertions(+), 26 deletions(-) create mode 100644 tests/expectations/tests/private_fields.rs create mode 100644 tests/headers/private_fields.hpp diff --git a/src/clang.rs b/src/clang.rs index 488660c43..661250894 100644 --- a/src/clang.rs +++ b/src/clang.rs @@ -632,6 +632,15 @@ impl Cursor { unsafe { clang_getCXXAccessSpecifier(self.x) } } + /// Is the cursor's referrent publically accessible in C++? + /// + /// Returns true if self.access_specifier() is `CX_CXXPublic` or + /// `CX_CXXInvalidAccessSpecifier`. + pub fn public_accessible(&self) -> bool { + let access = self.access_specifier(); + access == CX_CXXPublic || access == CX_CXXInvalidAccessSpecifier + } + /// Is this cursor's referent a field declaration that is marked as /// `mutable`? pub fn is_mutable_field(&self) -> bool { diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 194a461c6..cad2f47e5 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1271,10 +1271,11 @@ impl<'a> FieldCodegen<'a> for FieldData { } } - let is_private = self - .annotations() - .private_fields() - .unwrap_or(fields_should_be_private); + let is_private = (!self.is_public() && + ctx.options().respect_cxx_access_specs) || + self.annotations() + .private_fields() + .unwrap_or(fields_should_be_private); let accessor_kind = self.annotations().accessor_kind().unwrap_or(accessor_kind); @@ -1395,6 +1396,17 @@ impl Bitfield { } } +fn access_specifier( + ctx: &BindgenContext, + is_pub: bool, +) -> proc_macro2::TokenStream { + if is_pub || !ctx.options().respect_cxx_access_specs { + quote! { pub } + } else { + quote! {} + } +} + impl<'a> FieldCodegen<'a> for BitfieldUnit { type Extra = (); @@ -1455,11 +1467,6 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { let unit_field_name = format!("_bitfield_{}", self.nth()); let unit_field_ident = ctx.rust_ident(&unit_field_name); - let field = quote! { - pub #unit_field_ident : #field_ty , - }; - fields.extend(Some(field)); - let ctor_name = self.ctor_name(); let mut ctor_params = vec![]; let mut ctor_impl = quote! {}; @@ -1468,6 +1475,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { // implement AsRef<[u8]> / AsMut<[u8]> / etc. let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT; + let mut access_spec = !fields_should_be_private; for bf in self.bitfields() { // Codegen not allowed for anonymous bitfields if bf.name().is_none() { @@ -1478,6 +1486,7 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { continue; } + access_spec &= bf.is_public(); let mut bitfield_representable_as_int = true; bf.codegen( @@ -1511,10 +1520,17 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { ctor_impl = bf.extend_ctor_impl(ctx, param_name, ctor_impl); } + let access_spec = access_specifier(ctx, access_spec); + + let field = quote! { + #access_spec #unit_field_ident : #field_ty , + }; + fields.extend(Some(field)); + if generate_ctor { methods.extend(Some(quote! { #[inline] - pub fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_ty { + #access_spec fn #ctor_name ( #( #ctor_params ),* ) -> #unit_field_ty { let mut __bindgen_bitfield_unit: #unit_field_ty = Default::default(); #ctor_impl __bindgen_bitfield_unit @@ -1550,7 +1566,7 @@ impl<'a> FieldCodegen<'a> for Bitfield { fn codegen( &self, ctx: &BindgenContext, - _fields_should_be_private: bool, + fields_should_be_private: bool, _codegen_depth: usize, _accessor_kind: FieldAccessorKind, parent: &CompInfo, @@ -1590,13 +1606,16 @@ impl<'a> FieldCodegen<'a> for Bitfield { bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item); let offset = self.offset_into_unit(); - let width = self.width() as u8; + let access_spec = access_specifier( + ctx, + self.is_public() && !fields_should_be_private, + ); if parent.is_union() && !parent.can_be_rust_union(ctx) { methods.extend(Some(quote! { #[inline] - pub fn #getter_name(&self) -> #bitfield_ty { + #access_spec fn #getter_name(&self) -> #bitfield_ty { unsafe { ::#prefix::mem::transmute( self.#unit_field_ident.as_ref().get(#offset, #width) @@ -1606,7 +1625,7 @@ impl<'a> FieldCodegen<'a> for Bitfield { } #[inline] - pub fn #setter_name(&mut self, val: #bitfield_ty) { + #access_spec fn #setter_name(&mut self, val: #bitfield_ty) { unsafe { let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); self.#unit_field_ident.as_mut().set( @@ -1620,7 +1639,7 @@ impl<'a> FieldCodegen<'a> for Bitfield { } else { methods.extend(Some(quote! { #[inline] - pub fn #getter_name(&self) -> #bitfield_ty { + #access_spec fn #getter_name(&self) -> #bitfield_ty { unsafe { ::#prefix::mem::transmute( self.#unit_field_ident.get(#offset, #width) @@ -1630,7 +1649,7 @@ impl<'a> FieldCodegen<'a> for Bitfield { } #[inline] - pub fn #setter_name(&mut self, val: #bitfield_ty) { + #access_spec fn #setter_name(&mut self, val: #bitfield_ty) { unsafe { let val: #bitfield_int_ty = ::#prefix::mem::transmute(val); self.#unit_field_ident.set( @@ -1717,8 +1736,9 @@ impl CodeGenerator for CompInfo { struct_layout.saw_base(inner_item.expect_type()); + let access_spec = access_specifier(ctx, base.is_public()); fields.push(quote! { - pub #field_name: #inner, + #access_spec #field_name: #inner, }); } } diff --git a/src/ir/comp.rs b/src/ir/comp.rs index a0ca925c2..60b1e2f0f 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -148,6 +148,9 @@ pub trait FieldMethods { /// If this is a bitfield, how many bits does it need? fn bitfield_width(&self) -> Option; + /// Is this feild declared public? + fn is_public(&self) -> bool; + /// Get the annotations for this field. fn annotations(&self) -> &Annotations; @@ -412,6 +415,10 @@ impl FieldMethods for Bitfield { self.data.bitfield_width() } + fn is_public(&self) -> bool { + self.data.is_public() + } + fn annotations(&self) -> &Annotations { self.data.annotations() } @@ -436,6 +443,7 @@ impl RawField { comment: Option, annotations: Option, bitfield_width: Option, + public: bool, offset: Option, ) -> RawField { RawField(FieldData { @@ -444,6 +452,7 @@ impl RawField { comment, annotations: annotations.unwrap_or_default(), bitfield_width, + public, offset, }) } @@ -466,6 +475,10 @@ impl FieldMethods for RawField { self.0.bitfield_width() } + fn is_public(&self) -> bool { + self.0.is_public() + } + fn annotations(&self) -> &Annotations { self.0.annotations() } @@ -878,6 +891,9 @@ pub struct FieldData { /// If this field is a bitfield, and how many bits does it contain if it is. bitfield_width: Option, + /// If the C++ field is declared `public` + public: bool, + /// The offset of the field (in bits) offset: Option, } @@ -899,6 +915,10 @@ impl FieldMethods for FieldData { self.bitfield_width } + fn is_public(&self) -> bool { + self.public + } + fn annotations(&self) -> &Annotations { &self.annotations } @@ -934,6 +954,8 @@ pub struct Base { pub kind: BaseKind, /// Name of the field in which this base should be stored. pub field_name: String, + /// Whether this base is inherited from publically. + pub is_pub: bool, } impl Base { @@ -961,6 +983,11 @@ impl Base { true } + + /// Whether this base is inherited from publically. + pub fn is_public(&self) -> bool { + self.is_pub + } } /// A compound type. @@ -1230,7 +1257,7 @@ impl CompInfo { let mut maybe_anonymous_struct_field = None; cursor.visit(|cur| { if cur.kind() != CXCursor_FieldDecl { - if let Some((ty, clang_ty, offset)) = + if let Some((ty, clang_ty, public, offset)) = maybe_anonymous_struct_field.take() { if cur.kind() == CXCursor_TypedefDecl && @@ -1242,8 +1269,9 @@ impl CompInfo { // anonymous field. Detect that case here, and do // nothing. } else { - let field = - RawField::new(None, ty, None, None, None, offset); + let field = RawField::new( + None, ty, None, None, None, public, offset, + ); ci.fields.append_raw_field(field); } } @@ -1251,7 +1279,7 @@ impl CompInfo { match cur.kind() { CXCursor_FieldDecl => { - if let Some((ty, clang_ty, offset)) = + if let Some((ty, clang_ty, public, offset)) = maybe_anonymous_struct_field.take() { let mut used = false; @@ -1261,9 +1289,10 @@ impl CompInfo { } CXChildVisit_Continue }); + if !used { let field = RawField::new( - None, ty, None, None, None, offset, + None, ty, None, None, None, public, offset, ); ci.fields.append_raw_field(field); } @@ -1280,6 +1309,7 @@ impl CompInfo { let comment = cur.raw_comment(); let annotations = Annotations::new(&cur); let name = cur.spelling(); + let is_public = cur.public_accessible(); let offset = cur.offset_of_field().ok(); // Name can be empty if there are bitfields, for example, @@ -1297,6 +1327,7 @@ impl CompInfo { comment, annotations, bit_width, + is_public, offset, ); ci.fields.append_raw_field(field); @@ -1353,9 +1384,11 @@ impl CompInfo { cur.kind() != CXCursor_EnumDecl { let ty = cur.cur_type(); + let public = cur.public_accessible(); let offset = cur.offset_of_field().ok(); + maybe_anonymous_struct_field = - Some((inner, ty, offset)); + Some((inner, ty, public, offset)); } } CXCursor_PackedAttr => { @@ -1388,6 +1421,8 @@ impl CompInfo { ty: type_id, kind, field_name, + is_pub: cur.access_specifier() == + clang_sys::CX_CXXPublic, }); } CXCursor_Constructor | CXCursor_Destructor | @@ -1503,8 +1538,9 @@ impl CompInfo { CXChildVisit_Continue }); - if let Some((ty, _, offset)) = maybe_anonymous_struct_field { - let field = RawField::new(None, ty, None, None, None, offset); + if let Some((ty, _, public, offset)) = maybe_anonymous_struct_field { + let field = + RawField::new(None, ty, None, None, None, public, offset); ci.fields.append_raw_field(field); } diff --git a/src/lib.rs b/src/lib.rs index 2329dee98..8dcba3fb9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -545,6 +545,10 @@ impl Builder { output_vector.push(name.clone()); } + if self.options.respect_cxx_access_specs { + output_vector.push("--respect-cxx-access-specs".into()); + } + // Add clang arguments output_vector.push("--".into()); @@ -1518,6 +1522,12 @@ impl Builder { self.options.dynamic_library_name = Some(dynamic_library_name.into()); self } + + /// Generate bindings as `pub` only if the bound item is publically accessible by C++. + pub fn respect_cxx_access_specs(mut self, doit: bool) -> Self { + self.options.respect_cxx_access_specs = doit; + self + } } /// Configuration options for generated bindings. @@ -1805,6 +1815,10 @@ struct BindgenOptions { /// The name of the dynamic library (if we are generating bindings for a shared library). If /// this is None, no dynamic bindings are created. dynamic_library_name: Option, + + /// Only make generated bindings `pub` if the items would be publically accessible + /// by C++. + respect_cxx_access_specs: bool, } /// TODO(emilio): This is sort of a lie (see the error message that results from @@ -1941,6 +1955,7 @@ impl Default for BindgenOptions { array_pointers_in_arguments: false, wasm_import_module_name: None, dynamic_library_name: None, + respect_cxx_access_specs: false, } } } diff --git a/src/options.rs b/src/options.rs index 7d3e077ee..63e48dc83 100644 --- a/src/options.rs +++ b/src/options.rs @@ -493,6 +493,9 @@ where .long("dynamic-loading") .takes_value(true) .help("Use dynamic loading mode with the given library name."), + Arg::with_name("respect-cxx-access-specs") + .long("respect-cxx-access-specs") + .help("Makes generated bindings `pub` only for items if the items are publically accessible in C++."), ]) // .args() .get_matches_from(args); @@ -915,6 +918,10 @@ where builder = builder.dynamic_library_name(dynamic_library_name); } + if matches.is_present("respect-cxx-access-specs") { + builder = builder.respect_cxx_access_specs(true); + } + let verbose = matches.is_present("verbose"); Ok((builder, output, verbose)) diff --git a/tests/expectations/tests/no_debug_whitelisted.rs b/tests/expectations/tests/no_debug_whitelisted.rs index ac43e4ea5..e240d645f 100644 --- a/tests/expectations/tests/no_debug_whitelisted.rs +++ b/tests/expectations/tests/no_debug_whitelisted.rs @@ -25,6 +25,11 @@ fn bindgen_test_layout_NoDebug() { assert_eq!( unsafe { &(*(::std::ptr::null::())).i as *const _ as usize }, 0usize, - concat!("Offset of field: ", stringify!(NoDebug), "::", stringify!(i)) + concat!( + "Offset of field: ", + stringify!(NoDebug), + "::", + stringify!(i) + ) ); } diff --git a/tests/expectations/tests/private_fields.rs b/tests/expectations/tests/private_fields.rs new file mode 100644 index 000000000..f5edccae4 --- /dev/null +++ b/tests/expectations/tests/private_fields.rs @@ -0,0 +1,522 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +#[repr(C)] +#[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] +pub struct __BindgenBitfieldUnit { + storage: Storage, +} +impl __BindgenBitfieldUnit { + #[inline] + pub const fn new(storage: Storage) -> Self { + Self { storage } + } +} +impl __BindgenBitfieldUnit +where + Storage: AsRef<[u8]> + AsMut<[u8]>, +{ + #[inline] + pub fn get_bit(&self, index: usize) -> bool { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = self.storage.as_ref()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + byte & mask == mask + } + #[inline] + pub fn set_bit(&mut self, index: usize, val: bool) { + debug_assert!(index / 8 < self.storage.as_ref().len()); + let byte_index = index / 8; + let byte = &mut self.storage.as_mut()[byte_index]; + let bit_index = if cfg!(target_endian = "big") { + 7 - (index % 8) + } else { + index % 8 + }; + let mask = 1 << bit_index; + if val { + *byte |= mask; + } else { + *byte &= !mask; + } + } + #[inline] + pub fn get(&self, bit_offset: usize, bit_width: u8) -> u64 { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= + self.storage.as_ref().len() + ); + let mut val = 0; + for i in 0..(bit_width as usize) { + if self.get_bit(i + bit_offset) { + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + val |= 1 << index; + } + } + val + } + #[inline] + pub fn set(&mut self, bit_offset: usize, bit_width: u8, val: u64) { + debug_assert!(bit_width <= 64); + debug_assert!(bit_offset / 8 < self.storage.as_ref().len()); + debug_assert!( + (bit_offset + (bit_width as usize)) / 8 <= + self.storage.as_ref().len() + ); + for i in 0..(bit_width as usize) { + let mask = 1 << i; + let val_bit_is_set = val & mask == mask; + let index = if cfg!(target_endian = "big") { + bit_width as usize - 1 - i + } else { + i + }; + self.set_bit(index + bit_offset, val_bit_is_set); + } + } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct PubPriv { + pub x: ::std::os::raw::c_int, + y: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_PubPriv() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(PubPriv)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(PubPriv)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).x as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(PubPriv), + "::", + stringify!(x) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).y as *const _ as usize }, + 4usize, + concat!( + "Offset of field: ", + stringify!(PubPriv), + "::", + stringify!(y) + ) + ); +} +#[repr(C)] +#[repr(align(4))] +#[derive(Debug, Default, Copy, Clone)] +pub struct PrivateBitFields { + pub _bitfield_align_1: [u8; 0], + _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, + pub __bindgen_padding_0: [u8; 3usize], +} +#[test] +fn bindgen_test_layout_PrivateBitFields() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(PrivateBitFields)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(PrivateBitFields)) + ); +} +impl PrivateBitFields { + #[inline] + fn a(&self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(self._bitfield_1.get(0usize, 4u8) as u32) + } + } + #[inline] + fn set_a(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 4u8, val as u64) + } + } + #[inline] + fn b(&self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(self._bitfield_1.get(4usize, 4u8) as u32) + } + } + #[inline] + fn set_b(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(4usize, 4u8, val as u64) + } + } + #[inline] + fn new_bitfield_1( + a: ::std::os::raw::c_uint, + b: ::std::os::raw::c_uint, + ) -> __BindgenBitfieldUnit<[u8; 1usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = + Default::default(); + __bindgen_bitfield_unit.set(0usize, 4u8, { + let a: u32 = unsafe { ::std::mem::transmute(a) }; + a as u64 + }); + __bindgen_bitfield_unit.set(4usize, 4u8, { + let b: u32 = unsafe { ::std::mem::transmute(b) }; + b as u64 + }); + __bindgen_bitfield_unit + } +} +#[repr(C)] +#[repr(align(4))] +#[derive(Debug, Default, Copy, Clone)] +pub struct PublicBitFields { + pub _bitfield_align_1: [u8; 0], + pub _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, + pub __bindgen_padding_0: [u8; 3usize], +} +#[test] +fn bindgen_test_layout_PublicBitFields() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(PublicBitFields)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(PublicBitFields)) + ); +} +impl PublicBitFields { + #[inline] + pub fn a(&self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(self._bitfield_1.get(0usize, 4u8) as u32) + } + } + #[inline] + pub fn set_a(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 4u8, val as u64) + } + } + #[inline] + pub fn b(&self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(self._bitfield_1.get(4usize, 4u8) as u32) + } + } + #[inline] + pub fn set_b(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(4usize, 4u8, val as u64) + } + } + #[inline] + pub fn new_bitfield_1( + a: ::std::os::raw::c_uint, + b: ::std::os::raw::c_uint, + ) -> __BindgenBitfieldUnit<[u8; 1usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = + Default::default(); + __bindgen_bitfield_unit.set(0usize, 4u8, { + let a: u32 = unsafe { ::std::mem::transmute(a) }; + a as u64 + }); + __bindgen_bitfield_unit.set(4usize, 4u8, { + let b: u32 = unsafe { ::std::mem::transmute(b) }; + b as u64 + }); + __bindgen_bitfield_unit + } +} +#[repr(C)] +#[repr(align(4))] +#[derive(Debug, Default, Copy, Clone)] +pub struct MixedBitFields { + pub _bitfield_align_1: [u8; 0], + _bitfield_1: __BindgenBitfieldUnit<[u8; 1usize]>, + pub __bindgen_padding_0: [u8; 3usize], +} +#[test] +fn bindgen_test_layout_MixedBitFields() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(MixedBitFields)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(MixedBitFields)) + ); +} +impl MixedBitFields { + #[inline] + fn a(&self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(self._bitfield_1.get(0usize, 4u8) as u32) + } + } + #[inline] + fn set_a(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(0usize, 4u8, val as u64) + } + } + #[inline] + pub fn d(&self) -> ::std::os::raw::c_uint { + unsafe { + ::std::mem::transmute(self._bitfield_1.get(4usize, 4u8) as u32) + } + } + #[inline] + pub fn set_d(&mut self, val: ::std::os::raw::c_uint) { + unsafe { + let val: u32 = ::std::mem::transmute(val); + self._bitfield_1.set(4usize, 4u8, val as u64) + } + } + #[inline] + fn new_bitfield_1( + a: ::std::os::raw::c_uint, + d: ::std::os::raw::c_uint, + ) -> __BindgenBitfieldUnit<[u8; 1usize]> { + let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 1usize]> = + Default::default(); + __bindgen_bitfield_unit.set(0usize, 4u8, { + let a: u32 = unsafe { ::std::mem::transmute(a) }; + a as u64 + }); + __bindgen_bitfield_unit.set(4usize, 4u8, { + let d: u32 = unsafe { ::std::mem::transmute(d) }; + d as u64 + }); + __bindgen_bitfield_unit + } +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Base { + pub member: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_Base() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(Base)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(Base)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).member as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(Base), + "::", + stringify!(member) + ) + ); +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct InheritsPrivately { + _base: Base, +} +#[test] +fn bindgen_test_layout_InheritsPrivately() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(InheritsPrivately)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(InheritsPrivately)) + ); +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct InheritsPublically { + pub _base: Base, +} +#[test] +fn bindgen_test_layout_InheritsPublically() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(InheritsPublically)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(InheritsPublically)) + ); +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct WithAnonStruct { + __bindgen_anon_1: WithAnonStruct__bindgen_ty_1, + pub __bindgen_anon_2: WithAnonStruct__bindgen_ty_2, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct WithAnonStruct__bindgen_ty_1 { + pub a: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_WithAnonStruct__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(WithAnonStruct__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(WithAnonStruct__bindgen_ty_1)) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::())).a + as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(WithAnonStruct__bindgen_ty_1), + "::", + stringify!(a) + ) + ); +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct WithAnonStruct__bindgen_ty_2 { + pub b: ::std::os::raw::c_int, +} +#[test] +fn bindgen_test_layout_WithAnonStruct__bindgen_ty_2() { + assert_eq!( + ::std::mem::size_of::(), + 4usize, + concat!("Size of: ", stringify!(WithAnonStruct__bindgen_ty_2)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(WithAnonStruct__bindgen_ty_2)) + ); + assert_eq!( + unsafe { + &(*(::std::ptr::null::())).b + as *const _ as usize + }, + 0usize, + concat!( + "Offset of field: ", + stringify!(WithAnonStruct__bindgen_ty_2), + "::", + stringify!(b) + ) + ); +} +#[test] +fn bindgen_test_layout_WithAnonStruct() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(WithAnonStruct)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(WithAnonStruct)) + ); +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct WithAnonUnion { + __bindgen_anon_1: WithAnonUnion__bindgen_ty_1, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union WithAnonUnion__bindgen_ty_1 { + _bindgen_union_align: u8, + pub _address: u8, +} +#[test] +fn bindgen_test_layout_WithAnonUnion__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::(), + 1usize, + concat!("Size of: ", stringify!(WithAnonUnion__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(WithAnonUnion__bindgen_ty_1)) + ); +} +impl Default for WithAnonUnion__bindgen_ty_1 { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} +#[test] +fn bindgen_test_layout_WithAnonUnion() { + assert_eq!( + ::std::mem::size_of::(), + 1usize, + concat!("Size of: ", stringify!(WithAnonUnion)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(WithAnonUnion)) + ); +} +impl Default for WithAnonUnion { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} diff --git a/tests/headers/private_fields.hpp b/tests/headers/private_fields.hpp new file mode 100644 index 000000000..9d55ebcac --- /dev/null +++ b/tests/headers/private_fields.hpp @@ -0,0 +1,44 @@ +// bindgen-flags: --respect-cxx-access-specs +class PubPriv { + public: + int x; + private: + int y; +}; + +class PrivateBitFields { + unsigned int a : 4; + unsigned int b : 4; +}; +class PublicBitFields { + public: + unsigned int a : 4; + unsigned int b : 4; +}; +class MixedBitFields { + unsigned int a : 4; + public: + unsigned int d : 4; +}; + +class Base { + public: + int member; +}; + +class InheritsPrivately : Base {}; +class InheritsPublically : public Base {}; + +class WithAnonStruct { + struct { + int a; + }; + public: + struct { + int b; + }; +}; + +class WithAnonUnion { + union {}; +}; \ No newline at end of file