From 66caf51e13c9d05515045b134f60bae244dc56b9 Mon Sep 17 00:00:00 2001 From: Yuri Astrakhan Date: Thu, 28 Nov 2024 14:18:55 -0500 Subject: [PATCH] Automatic support for C-String literals When `generate_cstr` is enabled, and the target rust version is >= 1.77, generate `c"..."` literals instead of the unsafe `from_bytes_with_nul_unchecked` calls. --- Cargo.lock | 4 +- .../tests/expectations/tests/strings_cstr2.rs | 4 ++ bindgen-tests/tests/headers/strings_cstr2.h | 5 ++ bindgen/codegen/mod.rs | 48 ++++++++++++------- bindgen/features.rs | 5 +- 5 files changed, 45 insertions(+), 21 deletions(-) create mode 100644 bindgen-tests/tests/expectations/tests/strings_cstr2.rs create mode 100644 bindgen-tests/tests/headers/strings_cstr2.h diff --git a/Cargo.lock b/Cargo.lock index 251244184c..e5918dcc6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -436,9 +436,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.60" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] diff --git a/bindgen-tests/tests/expectations/tests/strings_cstr2.rs b/bindgen-tests/tests/expectations/tests/strings_cstr2.rs new file mode 100644 index 0000000000..2ce21f4374 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/strings_cstr2.rs @@ -0,0 +1,4 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub const MY_STRING_UTF8: &::std::ffi::CStr = c"Hello, world!"; +pub const MY_STRING_INTERIOR_NULL: &::std::ffi::CStr = c"Hello,"; +pub const MY_STRING_NON_UTF8: &::std::ffi::CStr = c"ABCDE\xFF"; diff --git a/bindgen-tests/tests/headers/strings_cstr2.h b/bindgen-tests/tests/headers/strings_cstr2.h new file mode 100644 index 0000000000..2cd7e6222d --- /dev/null +++ b/bindgen-tests/tests/headers/strings_cstr2.h @@ -0,0 +1,5 @@ +// bindgen-flags: --rust-target=1.77 --generate-cstr + +const char* MY_STRING_UTF8 = "Hello, world!"; +const char* MY_STRING_INTERIOR_NULL = "Hello,\0World!"; +const char* MY_STRING_NON_UTF8 = "ABCDE\xFF"; diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 943d8c7513..9f25369479 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -717,26 +717,38 @@ impl CodeGenerator for Var { let len = proc_macro2::Literal::usize_unsuffixed( cstr_bytes.len(), ); + let cstr = + if options.generate_cstr && rust_features.const_cstr { + CStr::from_bytes_with_nul(&cstr_bytes).ok() + } else { + None + }; - // TODO: Here we ignore the type we just made up, probably - // we should refactor how the variable type and ty ID work. - let array_ty = quote! { [u8; #len] }; - let cstr_ty = quote! { ::#prefix::ffi::CStr }; - - let bytes = proc_macro2::Literal::byte_string(&cstr_bytes); - - if options.generate_cstr && - rust_features.const_cstr && - CStr::from_bytes_with_nul(&cstr_bytes).is_ok() - { - result.push(quote! { - #(#attrs)* - #[allow(unsafe_code)] - pub const #canonical_ident: &#cstr_ty = unsafe { - #cstr_ty::from_bytes_with_nul_unchecked(#bytes) - }; - }); + if let Some(cstr) = cstr { + let cstr_ty = quote! { ::#prefix::ffi::CStr }; + if rust_features.literal_cstr { + let cstr = proc_macro2::Literal::c_string(&cstr); + result.push(quote! { + #(#attrs)* + pub const #canonical_ident: &#cstr_ty = #cstr; + }); + } else { + let bytes = + proc_macro2::Literal::byte_string(&cstr_bytes); + result.push(quote! { + #(#attrs)* + #[allow(unsafe_code)] + pub const #canonical_ident: &#cstr_ty = unsafe { + #cstr_ty::from_bytes_with_nul_unchecked(#bytes) + }; + }); + } } else { + // TODO: Here we ignore the type we just made up, probably + // we should refactor how the variable type and ty ID work. + let array_ty = quote! { [u8; #len] }; + let bytes = + proc_macro2::Literal::byte_string(&cstr_bytes); let lifetime = if true { None } else { Some(quote! { 'static }) } .into_iter(); diff --git a/bindgen/features.rs b/bindgen/features.rs index 9991522497..174491fae0 100644 --- a/bindgen/features.rs +++ b/bindgen/features.rs @@ -159,7 +159,10 @@ define_rust_targets! { ptr_metadata: #81513, layout_for_ptr: #69835, }, - Stable_1_77(77) => { offset_of: #106655 }, + Stable_1_77(77) => { + offset_of: #106655, + literal_cstr: #117472, + }, Stable_1_73(73) => { thiscall_abi: #42202 }, Stable_1_71(71) => { c_unwind_abi: #106075 }, Stable_1_68(68) => { abi_efiapi: #105795 },