Repository: rust-lang/rust-bindgen (Rust)

Issue:
`new_type_alias` breaks constant generation
Today, we write in a header

```C++
typedef uint64_t Foo;
static const Foo Foo_A = 0x1;
```

and invoke `bindgen` with `--new-type-alias Foo`, we'll get:

```rust
#[repr(transparent)]
#[derive(Debug, Default, Copy, Clone, PartialEq)]
pub struct Foo(pub u64);
pub const  Foo_A: Foo = 1;
```

which won't compile. If we've decided to apply newtype to an alias, we should wrap constants in the appropriate constructor to make it work.


Discussion:

Patch:
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<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 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/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<T> IsOpaque for T


Test patch:
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;