From c2232d286b2c9479426e461cccc12b708320a056 Mon Sep 17 00:00:00 2001 From: David Coles Date: Sat, 31 Jan 2026 01:07:52 -0800 Subject: [PATCH] Allow marking individual global bitfield enums While it's possible to use `default_enum_style` to get bitfield global enums, this implements bitfield operations for all default enums. This new option allows creating global bitfield enums on a per-type basis similar to the behaviour of `newtype_global_enum`. --- CHANGELOG.md | 1 + .../tests/bitfield-global-enum-basic.rs | 139 ++++++++++++++++++ .../headers/bitfield-global-enum-basic.hpp | 27 ++++ bindgen/ir/enum_ty.rs | 9 ++ bindgen/lib.rs | 4 +- bindgen/options/cli.rs | 5 + bindgen/options/mod.rs | 16 ++ 7 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 bindgen-tests/tests/expectations/tests/bitfield-global-enum-basic.rs create mode 100644 bindgen-tests/tests/headers/bitfield-global-enum-basic.hpp diff --git a/CHANGELOG.md b/CHANGELOG.md index 74ff973751..482bdce3f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -227,6 +227,7 @@ -------------------------------------------------------------------------------- # Unreleased ## Added +- Added `--bitfield-global-enum` for parity with `--newtype-global-enum` ## Changed ## Removed - Removed support for generating code for rustc versions < 1.51. diff --git a/bindgen-tests/tests/expectations/tests/bitfield-global-enum-basic.rs b/bindgen-tests/tests/expectations/tests/bitfield-global-enum-basic.rs new file mode 100644 index 0000000000..71081d05ed --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/bitfield-global-enum-basic.rs @@ -0,0 +1,139 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub const Foo_Bar: Foo = Foo(2); +pub const Foo_Baz: Foo = Foo(4); +pub const Foo_Duplicated: Foo = Foo(4); +pub const Foo_Negative: Foo = Foo(-3); +impl ::std::ops::BitOr for Foo { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + Foo(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for Foo { + #[inline] + fn bitor_assign(&mut self, rhs: Foo) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for Foo { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + Foo(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for Foo { + #[inline] + fn bitand_assign(&mut self, rhs: Foo) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Foo(pub ::std::os::raw::c_int); +pub const Buz_Bar: Buz = Buz(2); +pub const Buz_Baz: Buz = Buz(4); +pub const Buz_Duplicated: Buz = Buz(4); +pub const Buz_Negative: Buz = Buz(-3); +impl ::std::ops::BitOr for Buz { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + Buz(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for Buz { + #[inline] + fn bitor_assign(&mut self, rhs: Buz) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for Buz { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + Buz(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for Buz { + #[inline] + fn bitand_assign(&mut self, rhs: Buz) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Buz(pub ::std::os::raw::c_schar); +pub const NS_FOO: _bindgen_ty_1 = _bindgen_ty_1(1); +pub const NS_BAR: _bindgen_ty_1 = _bindgen_ty_1(2); +impl ::std::ops::BitOr<_bindgen_ty_1> for _bindgen_ty_1 { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + _bindgen_ty_1(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for _bindgen_ty_1 { + #[inline] + fn bitor_assign(&mut self, rhs: _bindgen_ty_1) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd<_bindgen_ty_1> for _bindgen_ty_1 { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + _bindgen_ty_1(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for _bindgen_ty_1 { + #[inline] + fn bitand_assign(&mut self, rhs: _bindgen_ty_1) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct _bindgen_ty_1(pub ::std::os::raw::c_uint); +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Dummy { + pub _address: u8, +} +pub const Dummy_DUMMY_FOO: Dummy__bindgen_ty_1 = Dummy__bindgen_ty_1(1); +pub const Dummy_DUMMY_BAR: Dummy__bindgen_ty_1 = Dummy__bindgen_ty_1(2); +impl ::std::ops::BitOr for Dummy__bindgen_ty_1 { + type Output = Self; + #[inline] + fn bitor(self, other: Self) -> Self { + Dummy__bindgen_ty_1(self.0 | other.0) + } +} +impl ::std::ops::BitOrAssign for Dummy__bindgen_ty_1 { + #[inline] + fn bitor_assign(&mut self, rhs: Dummy__bindgen_ty_1) { + self.0 |= rhs.0; + } +} +impl ::std::ops::BitAnd for Dummy__bindgen_ty_1 { + type Output = Self; + #[inline] + fn bitand(self, other: Self) -> Self { + Dummy__bindgen_ty_1(self.0 & other.0) + } +} +impl ::std::ops::BitAndAssign for Dummy__bindgen_ty_1 { + #[inline] + fn bitand_assign(&mut self, rhs: Dummy__bindgen_ty_1) { + self.0 &= rhs.0; + } +} +#[repr(transparent)] +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Dummy__bindgen_ty_1(pub ::std::os::raw::c_uint); +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of Dummy"][::std::mem::size_of::() - 1usize]; + ["Alignment of Dummy"][::std::mem::align_of::() - 1usize]; +}; diff --git a/bindgen-tests/tests/headers/bitfield-global-enum-basic.hpp b/bindgen-tests/tests/headers/bitfield-global-enum-basic.hpp new file mode 100644 index 0000000000..77a16599bd --- /dev/null +++ b/bindgen-tests/tests/headers/bitfield-global-enum-basic.hpp @@ -0,0 +1,27 @@ +// bindgen-flags: --bitfield-global-enum "Foo|Buz|NS_.*|DUMMY_.*" --rustified-enum ".*" -- -std=c++11 + +enum Foo { + Bar = 1 << 1, + Baz = 1 << 2, + Duplicated = 1 << 2, + Negative = -3, +}; + +enum class Buz : signed char { + Bar = 1 << 1, + Baz = 1 << 2, + Duplicated = 1 << 2, + Negative = -3, +}; + +enum { + NS_FOO = 1 << 0, + NS_BAR = 1 << 1, +}; + +class Dummy { + enum { + DUMMY_FOO = 1 << 0, + DUMMY_BAR = 1 << 1, + }; +}; diff --git a/bindgen/ir/enum_ty.rs b/bindgen/ir/enum_ty.rs index 9b08da3bce..f091444c06 100644 --- a/bindgen/ir/enum_ty.rs +++ b/bindgen/ir/enum_ty.rs @@ -194,6 +194,15 @@ impl Enum { is_bitfield: true, is_global: false, } + } else if self.is_matching_enum( + ctx, + &ctx.options().bitfield_global_enums, + item, + ) { + EnumVariation::NewType { + is_bitfield: true, + is_global: true, + } } else if self.is_matching_enum(ctx, &ctx.options().newtype_enums, item) { EnumVariation::NewType { diff --git a/bindgen/lib.rs b/bindgen/lib.rs index 0305b5cd7b..8b4136d760 100644 --- a/bindgen/lib.rs +++ b/bindgen/lib.rs @@ -463,7 +463,7 @@ impl Builder { impl BindgenOptions { fn build(&mut self) { - const REGEX_SETS_LEN: usize = 29; + const REGEX_SETS_LEN: usize = 30; let regex_sets: [_; REGEX_SETS_LEN] = [ &mut self.blocklisted_types, @@ -478,6 +478,7 @@ impl BindgenOptions { &mut self.allowlisted_files, &mut self.allowlisted_items, &mut self.bitfield_enums, + &mut self.bitfield_global_enums, &mut self.constified_enums, &mut self.constified_enum_modules, &mut self.newtype_enums, @@ -515,6 +516,7 @@ impl BindgenOptions { "--allowlist-file", "--allowlist-item", "--bitfield-enum", + "--bitfield-global-enum", "--newtype-enum", "--newtype-global-enum", "--rustified-enum", diff --git a/bindgen/options/cli.rs b/bindgen/options/cli.rs index 5304862584..a6dc736652 100644 --- a/bindgen/options/cli.rs +++ b/bindgen/options/cli.rs @@ -181,6 +181,9 @@ struct BindgenCommand { /// Mark any enum whose name matches REGEX as a set of bitfield flags. #[arg(long, value_name = "REGEX")] bitfield_enum: Vec, + /// Mark any enum whose name matches REGEX as a set of global bitfield flags. + #[arg(long, value_name = "REGEX")] + bitfield_global_enum: Vec, /// Mark any enum whose name matches REGEX as a newtype. #[arg(long, value_name = "REGEX")] newtype_enum: Vec, @@ -590,6 +593,7 @@ where depfile, default_enum_style, bitfield_enum, + bitfield_global_enum, newtype_enum, newtype_global_enum, rustified_enum, @@ -902,6 +906,7 @@ where rust_edition, default_enum_style, bitfield_enum, + bitfield_global_enum, newtype_enum, newtype_global_enum, rustified_enum, diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs index baa541c5ac..c45da315ef 100644 --- a/bindgen/options/mod.rs +++ b/bindgen/options/mod.rs @@ -479,6 +479,22 @@ options! { }, as_args: "--bitfield-enum", }, + /// `enum`s marked as bitfield-like. This is, global newtypes with bitwise operations. + bitfield_global_enums: RegexSet { + methods: { + regex_option! { + /// Mark the given `enum` as being bitfield-like. + /// + /// This is similar to the [`Builder::newtype_global_enum`] style, but with the bitwise + /// operators implemented. + pub fn bitfield_global_enum>(mut self, arg: T) -> Builder { + self.options.bitfield_global_enums.insert(arg); + self + } + } + }, + as_args: "--bitfield-global-enum", + }, /// `enum`s marked as newtypes. newtype_enums: RegexSet { methods: {