codegen: Support new-type-alias constants
Fixes #3287
diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs
index c940c3e..1b7c2b3 100644
--- a/bindgen-integration/build.rs
+++ b/bindgen-integration/build.rs
@@ -251,6 +251,10 @@
.blocklist_function("my_prefixed_function_to_remove")
.constified_enum("my_prefixed_enum_to_be_constified")
.opaque_type("my_prefixed_templated_foo<my_prefixed_baz>")
+ .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 7f71210..25858b2 100644
--- a/bindgen-integration/cpp/Test.h
+++ b/bindgen-integration/cpp/Test.h
@@ -246,3 +246,16 @@
// 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 22dd224..8c31121 100755
--- a/bindgen-integration/src/lib.rs
+++ b/bindgen-integration/src/lib.rs
@@ -355,3 +355,11 @@
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 0000000..f63069c
--- /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 0000000..73de948
--- /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 585845b..1dc108f 100644
--- a/bindgen/codegen/mod.rs
+++ b/bindgen/codegen/mod.rs
@@ -681,13 +681,8 @@
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 @@
} 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 @@
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::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) };
}
- VarType::Char(c) => {
- result.push(quote! {
- #(#attrs)*
- pub const #canonical_ident : #ty = #c ;
- });
- }
+ result.push(quote! {
+ #(#attrs)*
+ pub const #canonical_ident : #ty = #val ;
+ });
}
} else {
let symbol: &str = self.link_name().unwrap_or_else(|| {
@@ -1005,15 +1000,7 @@
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 47aa248..eea02cc 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 @@
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<T> IsOpaque for T