From f36909680292d1ba247fc9cef5dc171137fe65e8 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Thu, 4 Sep 2025 22:05:31 +0000 Subject: [PATCH] codegen: Support new-type-alias constants Fixes #3287 --- bindgen-integration/build.rs | 4 ++ bindgen-integration/cpp/Test.h | 13 +++++ bindgen-integration/src/lib.rs | 8 +++ .../expectations/tests/new-type-alias.rs | 20 +++++++ bindgen-tests/tests/headers/new-type-alias.h | 22 ++++++++ bindgen/codegen/mod.rs | 53 +++++++------------ bindgen/ir/item.rs | 18 ++++++- 7 files changed, 104 insertions(+), 34 deletions(-) create mode 100644 bindgen-tests/tests/expectations/tests/new-type-alias.rs create mode 100644 bindgen-tests/tests/headers/new-type-alias.h diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs index c940c3e9fa..1b7c2b3b82 100644 --- a/bindgen-integration/build.rs +++ b/bindgen-integration/build.rs @@ -251,6 +251,10 @@ fn setup_macro_test() { .blocklist_function("my_prefixed_function_to_remove") .constified_enum("my_prefixed_enum_to_be_constified") .opaque_type("my_prefixed_templated_foo") + .new_type_alias("MyInt") + .new_type_alias("MyBool") + .new_type_alias("MyFloat") + .new_type_alias("MyChar") .new_type_alias("TestDeriveOnAlias") .depfile(out_rust_file_relative.display().to_string(), &out_dep_file) .generate() diff --git a/bindgen-integration/cpp/Test.h b/bindgen-integration/cpp/Test.h index 7f71210cdd..25858b2790 100644 --- a/bindgen-integration/cpp/Test.h +++ b/bindgen-integration/cpp/Test.h @@ -246,3 +246,16 @@ enum MyOrderedEnum { // Used to test custom derives on new-type alias. See `test_custom_derive`. typedef int TestDeriveOnAlias; + +// Used to test new-type alias constants. See `test_new_type_alias_const`. +typedef int MyInt; +const MyInt MY_INT = 5; + +typedef bool MyBool; +const MyBool MY_BOOL = true; + +typedef float MyFloat; +const MyFloat MY_FLOAT = 1.23f; + +typedef char MyChar; +const MyChar MY_CHAR = 'a'; diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs index 22dd224ae8..8c31121b4b 100755 --- a/bindgen-integration/src/lib.rs +++ b/bindgen-integration/src/lib.rs @@ -355,3 +355,11 @@ fn test_colon_define() { let gold: u32 = (1u32 << 16) | 2; assert_eq!(gold, bindings::TESTMACRO_COLON_VALUE); } + +#[test] +fn test_new_type_alias_const() { + assert_eq!(bindings::MY_INT.0, 5); + assert_eq!(bindings::MY_BOOL.0, true); + assert_eq!(bindings::MY_FLOAT.0, 1.23f32); + assert_eq!(bindings::MY_CHAR.0, b'a' as std::ffi::c_char); +} diff --git a/bindgen-tests/tests/expectations/tests/new-type-alias.rs b/bindgen-tests/tests/expectations/tests/new-type-alias.rs new file mode 100644 index 0000000000..f63069cbe2 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/new-type-alias.rs @@ -0,0 +1,20 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub const true_: u32 = 1; +#[repr(transparent)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Foo(pub u64); +pub const Foo_A: Foo = Foo(1); +#[repr(transparent)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Bar(pub ::std::os::raw::c_char); +pub const Bar_A: Bar = Bar(97); +#[repr(transparent)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Baz(pub f32); +pub const Baz_A: Baz = Baz(3.25); +#[repr(transparent)] +#[derive(Debug, Default, Copy, Clone)] +pub struct Bang(pub bool); +pub const Bang_A: Bang = Bang(true); +pub type Boom = u64; +pub const Boom_A: Boom = 2; diff --git a/bindgen-tests/tests/headers/new-type-alias.h b/bindgen-tests/tests/headers/new-type-alias.h new file mode 100644 index 0000000000..73de94884c --- /dev/null +++ b/bindgen-tests/tests/headers/new-type-alias.h @@ -0,0 +1,22 @@ +// bindgen-flags: --new-type-alias (Foo|Bar|Baz|Bang) + +// Fake stdint.h and stdbool.h +typedef __UINT64_TYPE__ uint64_t; +#define bool _Bool +#define true 1 + +typedef uint64_t Foo; +static const Foo Foo_A = 1; + +typedef char Bar; +static const Bar Bar_A = 'a'; + +typedef float Baz; +static const Baz Baz_A = 3.25; + +typedef bool Bang; +static const Bang Bang_A = true; + +// Not wrapped +typedef uint64_t Boom; +static const Boom Boom_A = 2; diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 585845baeb..1dc108f62a 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -681,13 +681,8 @@ impl CodeGenerator for Var { let ty = var_ty.to_rust_ty_or_opaque(ctx, &()); if let Some(val) = self.val() { - match *val { - VarType::Bool(val) => { - result.push(quote! { - #(#attrs)* - pub const #canonical_ident : #ty = #val ; - }); - } + let const_expr = match *val { + VarType::Bool(val) => Some(val.to_token_stream()), VarType::Int(val) => { let int_kind = var_ty .into_resolver() @@ -702,10 +697,7 @@ impl CodeGenerator for Var { } else { helpers::ast_ty::uint_expr(val as _) }; - result.push(quote! { - #(#attrs)* - pub const #canonical_ident : #ty = #val ; - }); + Some(val) } VarType::String(ref bytes) => { let prefix = ctx.trait_prefix(); @@ -758,21 +750,24 @@ impl CodeGenerator for Var { pub const #canonical_ident: &#(#lifetime )*#array_ty = #bytes ; }); } + None } - VarType::Float(f) => { - if let Ok(expr) = helpers::ast_ty::float_expr(f) { - result.push(quote! { - #(#attrs)* - pub const #canonical_ident : #ty = #expr ; - }); - } - } - VarType::Char(c) => { - result.push(quote! { - #(#attrs)* - pub const #canonical_ident : #ty = #c ; - }); + VarType::Float(f) => helpers::ast_ty::float_expr(f).ok(), + VarType::Char(c) => Some(c.to_token_stream()), + }; + + if let Some(mut val) = const_expr { + let var_ty_item = ctx.resolve_item(var_ty); + if matches!( + var_ty_item.alias_style(ctx), + AliasVariation::NewType | AliasVariation::NewTypeDeref + ) { + val = quote! { #ty(#val) }; } + result.push(quote! { + #(#attrs)* + pub const #canonical_ident : #ty = #val ; + }); } } else { let symbol: &str = self.link_name().unwrap_or_else(|| { @@ -1005,15 +1000,7 @@ impl CodeGenerator for Type { quote! {} }; - let alias_style = if ctx.options().type_alias.matches(&name) { - AliasVariation::TypeAlias - } else if ctx.options().new_type_alias.matches(&name) { - AliasVariation::NewType - } else if ctx.options().new_type_alias_deref.matches(&name) { - AliasVariation::NewTypeDeref - } else { - ctx.options().default_alias_style - }; + let alias_style = item.alias_style(ctx); // We prefer using `pub use` over `pub type` because of: // https://github.com/rust-lang/rust/issues/26264 diff --git a/bindgen/ir/item.rs b/bindgen/ir/item.rs index 47aa248688..eea02cce6c 100644 --- a/bindgen/ir/item.rs +++ b/bindgen/ir/item.rs @@ -1,6 +1,8 @@ //! Bindgen's core intermediate representation type. -use super::super::codegen::{EnumVariation, CONSTIFIED_ENUM_MODULE_REPR_NAME}; +use super::super::codegen::{ + AliasVariation, EnumVariation, CONSTIFIED_ENUM_MODULE_REPR_NAME, +}; use super::analysis::{HasVtable, HasVtableResult, Sizedness, SizednessResult}; use super::annotations::Annotations; use super::comp::{CompKind, MethodKind}; @@ -1103,6 +1105,20 @@ impl Item { pub(crate) fn must_use(&self, ctx: &BindgenContext) -> bool { self.annotations().must_use_type() || ctx.must_use_type_by_name(self) } + + /// Get the alias style for this item. + pub(crate) fn alias_style(&self, ctx: &BindgenContext) -> AliasVariation { + let name = self.canonical_name(ctx); + if ctx.options().type_alias.matches(&name) { + AliasVariation::TypeAlias + } else if ctx.options().new_type_alias.matches(&name) { + AliasVariation::NewType + } else if ctx.options().new_type_alias_deref.matches(&name) { + AliasVariation::NewTypeDeref + } else { + ctx.options().default_alias_style + } + } } impl IsOpaque for T