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/extern-fn-block-attrs-many.rs b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs-many.rs new file mode 100644 index 0000000000..5aa9e45ec2 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs-many.rs @@ -0,0 +1,6 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[allow(dead_code)] +#[cfg_attr(not(windows), link(wasm_import_module = "test-module"))] +unsafe extern "C" { + pub fn test_function(); +} diff --git a/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs-wasm.rs b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs-wasm.rs new file mode 100644 index 0000000000..388594b27e --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs-wasm.rs @@ -0,0 +1,6 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[link(wasm_import_module = "test-module")] +#[allow(dead_code)] +unsafe extern "C" { + pub fn test_function(); +} diff --git a/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs.rs b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs.rs new file mode 100644 index 0000000000..657cec106a --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/extern-fn-block-attrs.rs @@ -0,0 +1,5 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[allow(dead_code)] +unsafe extern "C" { + pub fn test_function(); +} diff --git a/bindgen-tests/tests/expectations/tests/infinite-macro.rs b/bindgen-tests/tests/expectations/tests/infinite-macro.rs index f19879fb17..cf2b32f0ed 100644 --- a/bindgen-tests/tests/expectations/tests/infinite-macro.rs +++ b/bindgen-tests/tests/expectations/tests/infinite-macro.rs @@ -1,3 +1,7 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] -pub const INFINITY: f64 = f64::INFINITY; -pub const NAN: f64 = f64::NAN; +pub const INFINITY: f64 = f64::INFINITY as _; +pub const NEG_INFINITY: f64 = f64::NEG_INFINITY as _; +pub const NAN: f64 = f64::NAN as _; +pub const F32_INFINITY: f32 = f64::INFINITY as _; +pub const F32_NEG_INFINITY: f32 = f64::NEG_INFINITY as _; +pub const F32_NAN: f32 = f64::NAN as _; diff --git a/bindgen-tests/tests/expectations/tests/issue-2618.rs b/bindgen-tests/tests/expectations/tests/issue-2618.rs new file mode 100644 index 0000000000..ecac1ec81e --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/issue-2618.rs @@ -0,0 +1,13 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub const val1: u32 = 2147483647; +pub const val2: u32 = 2147483648; +pub const val3: u32 = 4294967295; +pub const val4: u64 = 9223372036854775807; +pub const val5: u64 = 9223372036854775808; +pub const val6: u64 = 18446744073709551615; +pub const val7: u32 = 2147483647; +pub const val8: u32 = 2147483648; +pub const val9: u32 = 4294967295; +pub const val10: u64 = 9223372036854775807; +pub const val11: u64 = 9223372036854775808; +pub const val12: u64 = 18446744073709551615; 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/expectations/tests/references.rs b/bindgen-tests/tests/expectations/tests/references.rs new file mode 100644 index 0000000000..799e855793 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/references.rs @@ -0,0 +1,61 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Container { + pub normalPointer: *mut ::std::os::raw::c_int, + pub constPointer: *const ::std::os::raw::c_int, + pub normalRef: ::std::ptr::NonNull<::std::os::raw::c_int>, + pub constRef: ::std::ptr::NonNull<::std::os::raw::c_int>, + pub pointerRef: ::std::ptr::NonNull<*mut ::std::os::raw::c_int>, + pub constPointerRef: ::std::ptr::NonNull<*const ::std::os::raw::c_int>, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + ["Size of Container"][::std::mem::size_of::() - 48usize]; + ["Alignment of Container"][::std::mem::align_of::() - 8usize]; + [ + "Offset of field: Container::normalPointer", + ][::std::mem::offset_of!(Container, normalPointer) - 0usize]; + [ + "Offset of field: Container::constPointer", + ][::std::mem::offset_of!(Container, constPointer) - 8usize]; + [ + "Offset of field: Container::normalRef", + ][::std::mem::offset_of!(Container, normalRef) - 16usize]; + [ + "Offset of field: Container::constRef", + ][::std::mem::offset_of!(Container, constRef) - 24usize]; + [ + "Offset of field: Container::pointerRef", + ][::std::mem::offset_of!(Container, pointerRef) - 32usize]; + [ + "Offset of field: Container::constPointerRef", + ][::std::mem::offset_of!(Container, constPointerRef) - 40usize]; +}; +impl Default for Container { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +unsafe extern "C" { + #[link_name = "\u{1}_Z20refReturningFunctionv"] + pub fn refReturningFunction() -> ::std::ptr::NonNull<::std::os::raw::c_int>; +} +unsafe extern "C" { + #[link_name = "\u{1}_Z20functionConsumingRefRifRKi"] + pub fn functionConsumingRef( + someRef: ::std::ptr::NonNull<::std::os::raw::c_int>, + normalArgument: f32, + constRef: ::std::ptr::NonNull<::std::os::raw::c_int>, + ); +} +unsafe extern "C" { + #[link_name = "\u{1}_Z27functionConsumingPointerRefRPi"] + pub fn functionConsumingPointerRef( + pointerRef: ::std::ptr::NonNull<*mut ::std::os::raw::c_int>, + ); +} diff --git a/bindgen-tests/tests/headers/extern-fn-block-attrs-many.h b/bindgen-tests/tests/headers/extern-fn-block-attrs-many.h new file mode 100644 index 0000000000..0de6eebb36 --- /dev/null +++ b/bindgen-tests/tests/headers/extern-fn-block-attrs-many.h @@ -0,0 +1,3 @@ +// bindgen-flags: --extern-fn-block-attrs '#[allow(dead_code)]' --extern-fn-block-attrs '#[cfg_attr(not(windows), link(wasm_import_module = "test-module"))]' + +void test_function(); \ No newline at end of file diff --git a/bindgen-tests/tests/headers/extern-fn-block-attrs-wasm.h b/bindgen-tests/tests/headers/extern-fn-block-attrs-wasm.h new file mode 100644 index 0000000000..2f475f1ed1 --- /dev/null +++ b/bindgen-tests/tests/headers/extern-fn-block-attrs-wasm.h @@ -0,0 +1,3 @@ +// bindgen-flags: --extern-fn-block-attrs '#[allow(dead_code)]' --wasm-import-module-name test-module + +void test_function(); \ No newline at end of file diff --git a/bindgen-tests/tests/headers/extern-fn-block-attrs.h b/bindgen-tests/tests/headers/extern-fn-block-attrs.h new file mode 100644 index 0000000000..26480e2ef0 --- /dev/null +++ b/bindgen-tests/tests/headers/extern-fn-block-attrs.h @@ -0,0 +1,3 @@ +// bindgen-flags: --extern-fn-block-attrs '#[allow(dead_code)]' + +void test_function(); \ No newline at end of file diff --git a/bindgen-tests/tests/headers/infinite-macro.h b/bindgen-tests/tests/headers/infinite-macro.h deleted file mode 100644 index ab352c5785..0000000000 --- a/bindgen-tests/tests/headers/infinite-macro.h +++ /dev/null @@ -1,2 +0,0 @@ -#define INFINITY (1.0f/0.0f) -#define NAN (0.0f/0.0f) diff --git a/bindgen-tests/tests/headers/infinite-macro.hpp b/bindgen-tests/tests/headers/infinite-macro.hpp new file mode 100644 index 0000000000..32c8b61911 --- /dev/null +++ b/bindgen-tests/tests/headers/infinite-macro.hpp @@ -0,0 +1,7 @@ +#define INFINITY (1.0f/0.0f) +#define NEG_INFINITY (-1.0f/0.0f) +#define NAN (0.0f/0.0f) + +static const float F32_INFINITY = 1.0f / 0.0f; +static const float F32_NEG_INFINITY = -1.0f / 0.0f; +static const float F32_NAN = 0.0f / 0.0f; diff --git a/bindgen-tests/tests/headers/issue-2618.h b/bindgen-tests/tests/headers/issue-2618.h new file mode 100644 index 0000000000..841ff61d77 --- /dev/null +++ b/bindgen-tests/tests/headers/issue-2618.h @@ -0,0 +1,18 @@ +// bindgen-flags: --allowlist-var "val[0-9]+" + +typedef __UINT32_TYPE__ uint32_t; +typedef __UINT64_TYPE__ uint64_t; + +static const uint32_t val1 = 0x7fffffff; +static const uint32_t val2 = 0x80000000; +static const uint32_t val3 = 0xffffffff; +static const uint64_t val4 = 0x7fffffffffffffff; +static const uint64_t val5 = 0x8000000000000000; +static const uint64_t val6 = 0xffffffffffffffff; + +static const uint32_t val7 = (0x7fffffff); +static const uint32_t val8 = (0x80000000); +static const uint32_t val9 = (0xffffffff); +static const uint64_t val10 = (0x7fffffffffffffff); +static const uint64_t val11 = (0x8000000000000000); +static const uint64_t val12 = (0xffffffffffffffff); 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-tests/tests/headers/references.hpp b/bindgen-tests/tests/headers/references.hpp new file mode 100644 index 0000000000..6b56823d12 --- /dev/null +++ b/bindgen-tests/tests/headers/references.hpp @@ -0,0 +1,17 @@ +// bindgen-flags: --nonnull-references + +struct Container { + int *normalPointer; + const int *constPointer; + int &normalRef; + const int &constRef; + int *&pointerRef; + const int *&constPointerRef; +}; + +int &refReturningFunction(); + +void functionConsumingRef(int &someRef, float normalArgument, + const int &constRef); + +void functionConsumingPointerRef(int* &pointerRef); diff --git a/bindgen/clang.rs b/bindgen/clang.rs index 1e8326ed82..9e614da9f8 100644 --- a/bindgen/clang.rs +++ b/bindgen/clang.rs @@ -2351,10 +2351,11 @@ impl EvalResult { if unsafe { clang_EvalResult_isUnsignedInt(self.x) } != 0 { let value = unsafe { clang_EvalResult_getAsUnsigned(self.x) }; - if value > i64::MAX as c_ulonglong { + if value > u64::MAX as c_ulonglong { return None; } + // Do a wrapping cast to i64. This will be losslessly cast back to u64 later. return Some(value as i64); } diff --git a/bindgen/codegen/helpers.rs b/bindgen/codegen/helpers.rs index 49928cce3a..9b86ba47b0 100644 --- a/bindgen/codegen/helpers.rs +++ b/bindgen/codegen/helpers.rs @@ -320,14 +320,14 @@ pub(crate) mod ast_ty { } if f.is_nan() { - return Ok(quote! { f64::NAN }); + return Ok(quote! { f64::NAN as _ }); } if f.is_infinite() { let tokens = if f.is_sign_positive() { - quote! { f64::INFINITY } + quote! { f64::INFINITY as _ } } else { - quote! { f64::NEG_INFINITY } + quote! { f64::NEG_INFINITY as _ } }; return Ok(tokens); } diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 585845baeb..eee4f46121 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 @@ -4384,6 +4371,12 @@ impl TryToRustTy for Type { if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer { Ok(ty) + } else if ctx.options().generate_cxx_nonnull_references && + matches!(self.kind(), TypeKind::Reference(_)) + { + // It's UB to pass null values in place of C++ references + let prefix = ctx.trait_prefix(); + Ok(syn::parse_quote! { ::#prefix::ptr::NonNull<#ty> }) } else { Ok(ty.to_ptr(is_const)) } @@ -4672,13 +4665,19 @@ impl CodeGenerator for Function { } } - // Unfortunately this can't piggyback on the `attributes` list because - // the #[link(wasm_import_module)] needs to happen before the `extern - // "C"` block. It doesn't get picked up properly otherwise - let wasm_link_attribute = - ctx.options().wasm_import_module_name.as_ref().map(|name| { - quote! { #[link(wasm_import_module = #name)] } + let mut block_attributes = quote! {}; + for attr in &ctx.options().extern_fn_block_attrs { + let parsed_attr = proc_macro2::TokenStream::from_str(attr).unwrap_or_else( + |err| { + panic!( + "Error parsing extern fn block attribute `{attr}`: {err}" + ) + }, + ); + block_attributes.extend(quote! { + #parsed_attr }); + } let should_wrap = is_internal && ctx.options().wrap_static_fns && @@ -4732,7 +4731,7 @@ impl CodeGenerator for Function { .then(|| quote!(unsafe)); let tokens = quote! { - #wasm_link_attribute + #block_attributes #safety extern #abi { #(#attributes)* pub fn #ident ( #( #args ),* ) #ret; diff --git a/bindgen/ir/int.rs b/bindgen/ir/int.rs index ed18a99949..217fc11efa 100644 --- a/bindgen/ir/int.rs +++ b/bindgen/ir/int.rs @@ -120,9 +120,4 @@ impl IntKind { _ => return None, }) } - - /// Whether this type's signedness matches the value. - pub(crate) fn signedness_matches(&self, val: i64) -> bool { - val >= 0 || self.is_signed() - } } 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 diff --git a/bindgen/ir/var.rs b/bindgen/ir/var.rs index 45f4ba1ba0..9d72dcf06e 100644 --- a/bindgen/ir/var.rs +++ b/bindgen/ir/var.rs @@ -341,7 +341,7 @@ impl ClangSubItemParser for Var { }; let mut val = cursor.evaluate().and_then(|v| v.as_int()); - if val.is_none() || !kind.signedness_matches(val.unwrap()) { + if val.is_none() { val = get_integer_literal_from_cursor(&cursor); } diff --git a/bindgen/options/cli.rs b/bindgen/options/cli.rs index b60de39603..972b487c25 100644 --- a/bindgen/options/cli.rs +++ b/bindgen/options/cli.rs @@ -258,6 +258,9 @@ struct BindgenCommand { /// Use extern crate instead of use for objc. #[arg(long)] objc_extern_crate: bool, + /// Use `NonNull` in place of raw pointers for C++ references. + #[arg(long)] + nonnull_references: bool, /// Generate block signatures instead of void pointers. #[arg(long)] generate_block: bool, @@ -420,6 +423,9 @@ struct BindgenCommand { /// The NAME to be used in a #[link(wasm_import_module = ...)] statement #[arg(long, value_name = "NAME")] wasm_import_module_name: Option, + /// Attributes to apply to the extern function block. + #[arg(long, value_name = "ATTRS")] + extern_fn_block_attrs: Vec, /// Use dynamic loading mode with the given library NAME. #[arg(long, value_name = "NAME")] dynamic_loading: Option, @@ -590,6 +596,7 @@ where no_doc_comments, no_recursive_allowlist, objc_extern_crate, + nonnull_references, generate_block, generate_cstr, block_extern_crate, @@ -643,6 +650,7 @@ where enable_function_attribute_detection, use_array_pointers_in_arguments, wasm_import_module_name, + extern_fn_block_attrs, dynamic_loading, dynamic_link_require_all, prefix_link_name, @@ -903,6 +911,7 @@ where time_phases, use_array_pointers_in_arguments => Builder::array_pointers_in_arguments, wasm_import_module_name, + extern_fn_block_attrs => Builder::extern_fn_block_attrs, ctypes_prefix, anon_fields_prefix, generate => Builder::with_codegen_config, @@ -921,6 +930,7 @@ where no_doc_comments => |b, _| b.generate_comments(false), no_recursive_allowlist => |b, _| b.allowlist_recursively(false), objc_extern_crate, + nonnull_references => |b, _| b.generate_cxx_nonnull_references(true), generate_block, generate_cstr, block_extern_crate, diff --git a/bindgen/options/mod.rs b/bindgen/options/mod.rs index 767be03e35..b9b33a850b 100644 --- a/bindgen/options/mod.rs +++ b/bindgen/options/mod.rs @@ -541,6 +541,11 @@ options! { /// /// This is similar to the [`Builder::rustified_enum`] style, but the `enum` is /// tagged with the `#[non_exhaustive]` attribute. + /// + /// **Use this with caution**, creating an instance of a Rust `enum` with an + /// invalid value will cause undefined behaviour, even if it's tagged with + /// `#[non_exhaustive]`. To avoid this, use the [`Builder::newtype_enum`] style + /// instead. pub fn rustified_non_exhaustive_enum>(mut self, arg: T) -> Builder { self.options.rustified_non_exhaustive_enums.insert(arg); self @@ -1474,6 +1479,26 @@ options! { }, as_args: |value, args| (!value).as_args(args, "--no-doc-comments"), }, + /// Whether to generate [`NonNull`] pointers for C++ references. + /// + /// [`NonNull`]: core::ptr::NonNull + generate_cxx_nonnull_references: bool { + default: false, + methods: { + /// Generate `NonNull` pointers in place of raw pointers for C++ + /// references. + /// + /// This option is disabled by default: + /// + /// Enabling it erases information about constness in generated + /// code, and `NonNull` is more cumbersome to use than raw pointers. + pub fn generate_cxx_nonnull_references(mut self, doit: bool) -> Self { + self.options.generate_cxx_nonnull_references = doit; + self + } + }, + as_args: |value, args| value.as_args(args, "--nonnull-references"), + }, /// Whether to generate inline functions. generate_inline_functions: bool { methods: { @@ -1891,6 +1916,25 @@ options! { }, as_args: "--use-array-pointers-in-arguments", }, + /// Attributes to add to all `extern` blocks. + extern_fn_block_attrs: Vec { + methods: { + /// Add an attribute to all the `extern` blocks generated by `bindgen`. + /// + /// This can be used to add attributes such as `#[link(...)]` to all + /// the `extern` blocks. + pub fn extern_fn_block_attrs>(mut self, attr: T) -> Self { + self.options.extern_fn_block_attrs.push(attr.into()); + self + } + }, + as_args: |attrs, args| { + for attr in attrs { + args.push("--extern-fn-block-attrs".to_owned()); + args.push(attr.clone()); + } + }, + }, /// The name of the `wasm_import_module`. wasm_import_module_name: Option { methods: { @@ -1902,7 +1946,9 @@ options! { mut self, import_name: T, ) -> Self { - self.options.wasm_import_module_name = Some(import_name.into()); + self.options.extern_fn_block_attrs.push(format!( + "#[link(wasm_import_module = \"{}\")]", import_name.into() + )); self } },