diff --git a/bindgen-tests/tests/expectations/tests/enum_unnamed.rs b/bindgen-tests/tests/expectations/tests/enum_unnamed.rs new file mode 100644 index 0000000000..05868f4ccf --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/enum_unnamed.rs @@ -0,0 +1,7 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub const A: bindgen_enum_98a4e4a38f13856d = 1; +pub const B: bindgen_enum_98a4e4a38f13856d = 2; +pub type bindgen_enum_98a4e4a38f13856d = ::std::os::raw::c_uint; +pub const C: bindgen_enum_bb1a5d36cda6e84c = -3; +pub const D: bindgen_enum_bb1a5d36cda6e84c = 4; +pub type bindgen_enum_bb1a5d36cda6e84c = ::std::os::raw::c_int; diff --git a/bindgen-tests/tests/headers/enum_unnamed.h b/bindgen-tests/tests/headers/enum_unnamed.h new file mode 100644 index 0000000000..af67d4ca2a --- /dev/null +++ b/bindgen-tests/tests/headers/enum_unnamed.h @@ -0,0 +1,10 @@ +// bindgen-flags: --hash-unnamed-enum + +enum { + A = 1, + B = 2 +}; +enum { + C = -3, + D = 4, +}; \ No newline at end of file diff --git a/bindgen/ir/enum_ty.rs b/bindgen/ir/enum_ty.rs index 9b08da3bce..79e139dd64 100644 --- a/bindgen/ir/enum_ty.rs +++ b/bindgen/ir/enum_ty.rs @@ -235,6 +235,19 @@ impl Enum { ctx.options().default_enum_style } } + /// generate hash from enum variants + pub(crate) fn variants_name_hash(&self) -> u64 { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + let mut hasher = DefaultHasher::new(); + + for variant in self.variants() { + variant.name().hash(&mut hasher); + } + + hasher.finish() + } } /// A single enum variant, to be contained only in an enum. diff --git a/bindgen/ir/ty.rs b/bindgen/ir/ty.rs index 5819f1118f..1a86cdafcf 100644 --- a/bindgen/ir/ty.rs +++ b/bindgen/ir/ty.rs @@ -271,7 +271,25 @@ impl Type { .sanitized_name(ctx) .map(|name| format!("{prefix}_{name}").into()) } else { - self.name().map(Self::sanitize_name) + match self.name() { + Some(name) => Some(Self::sanitize_name(name)), + None => match self.kind() { + TypeKind::Enum(inner) => { + if ctx.options().hash_unnamed_enum { + Some( + format!( + "bindgen_enum_{:x}", + inner.variants_name_hash() + ) + .into(), + ) + } else { + None + } + } + _ => None, + }, + } } } diff --git a/bindgen/options/cli.rs b/bindgen/options/cli.rs index bce7faed35..92c3f7bdb5 100644 --- a/bindgen/options/cli.rs +++ b/bindgen/options/cli.rs @@ -321,6 +321,8 @@ struct BindgenCommand { /// Do not prepend the enum name to constant or newtype variants. #[arg(long)] no_prepend_enum_name: bool, + #[arg(long)] + hash_unnamed_enum: bool, /// Do not try to detect default include paths #[arg(long)] no_include_path_detection: bool, @@ -611,6 +613,7 @@ where ignore_methods, no_convert_floats, no_prepend_enum_name, + hash_unnamed_enum, no_include_path_detection, fit_macro_constant_types, opaque_type, @@ -898,6 +901,7 @@ where with_derive_ord => Builder::derive_ord, no_derive_default => |b, _| b.derive_default(false), no_prepend_enum_name => |b, _| b.prepend_enum_name(false), + hash_unnamed_enum => |b,_|b.hash_unnamed_enum(), no_include_path_detection => |b, _| b.detect_include_paths(false), fit_macro_constant_types => Builder::fit_macro_constants, time_phases, diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs index b876b4d5b3..c1fd9b3744 100644 --- a/bindgen/options/mod.rs +++ b/bindgen/options/mod.rs @@ -2283,4 +2283,17 @@ options! { }, as_args: "--generate-private-functions", }, + /// use hash name for unnamed enum + hash_unnamed_enum: bool { + default: false, + methods: { + /// Generate a hash-based name for unnamed enums, + /// using the hash of their variant names. + pub fn hash_unnamed_enum(mut self) -> Self { + self.options.hash_unnamed_enum = true; + self + } + }, + as_args: "--hash-unnamed-enum", + } }