From 953ca92c2114eb7141d96d5053f8051573903b71 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 6 Sep 2022 16:06:04 -0500 Subject: [PATCH] add `--unsafe-blocks` option --- Cargo.toml | 2 +- src/lib.rs | 81 ++++++++++++++++++++++- src/options.rs | 7 ++ tests/expectations/tests/unsafe_blocks.rs | 78 ++++++++++++++++++++++ tests/headers/unsafe_blocks.h | 5 ++ 5 files changed, 171 insertions(+), 2 deletions(-) create mode 100644 tests/expectations/tests/unsafe_blocks.rs create mode 100644 tests/headers/unsafe_blocks.h diff --git a/Cargo.toml b/Cargo.toml index 311110b3ec..8f9d06b76d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ lazycell = "1" lazy_static = "1" peeking_take_while = "0.1.2" quote = { version = "1", default-features = false } -syn = { version = "1.0.99", features = ["full", "extra-traits"]} +syn = { version = "1.0.99", features = ["full", "extra-traits", "visit-mut"]} regex = { version = "1.5", default-features = false , features = ["std", "unicode"] } which = { version = "4.2.1", optional = true, default-features = false } shlex = "1" diff --git a/src/lib.rs b/src/lib.rs index fb02fe16f5..aaaab754a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -592,6 +592,10 @@ impl Builder { output_vector.push("--sort-semantically".into()); } + if self.options.unsafe_blocks { + output_vector.push("--unsafe-blocks".into()); + } + // Add clang arguments output_vector.push("--".into()); @@ -1489,6 +1493,12 @@ impl Builder { self } + /// If true, wraps all the bodies of generated `unsafe` functions in `unsafe` blocks. + pub fn unsafe_blocks(mut self, doit: bool) -> Self { + self.options.unsafe_blocks = doit; + self + } + /// Generate the Rust bindings using the options built up thus far. pub fn generate(mut self) -> Result { // Add any extra arguments from the environment to the clang command line. @@ -2021,6 +2031,9 @@ struct BindgenOptions { /// Sort the code generation sort_semantically: bool, + + /// Wrap the bodies of `unsafe` functions in `unsafe` blocks + unsafe_blocks: bool, } /// TODO(emilio): This is sort of a lie (see the error message that results from @@ -2031,7 +2044,7 @@ impl ::std::panic::UnwindSafe for BindgenOptions {} impl BindgenOptions { /// Whether any of the enabled options requires `syn`. fn require_syn(&self) -> bool { - self.sort_semantically + self.sort_semantically || self.unsafe_blocks } fn build(&mut self) { @@ -2175,6 +2188,7 @@ impl Default for BindgenOptions { force_explicit_padding: false, vtable_generation: false, sort_semantically: false, + unsafe_blocks: Default::default(), } } } @@ -2503,6 +2517,71 @@ impl Bindings { }); } + if options.unsafe_blocks { + struct UnsafeBlocksVisitor; + + impl UnsafeBlocksVisitor { + fn add_unsafe_block( + &self, + sig: &syn::Signature, + block: &mut syn::Block, + ) { + if sig.unsafety.is_some() { + let inner_block = std::mem::replace( + block, + syn::Block { + brace_token: Default::default(), + stmts: Default::default(), + }, + ); + + block.stmts.push(syn::Stmt::Expr( + syn::Expr::Unsafe(syn::ExprUnsafe { + attrs: Default::default(), + block: inner_block, + unsafe_token: Default::default(), + }), + )); + } + } + } + + impl syn::visit_mut::VisitMut for UnsafeBlocksVisitor { + fn visit_item_fn_mut(&mut self, item: &mut syn::ItemFn) { + self.add_unsafe_block(&item.sig, &mut item.block); + + syn::visit_mut::visit_item_fn_mut(self, item) + } + + fn visit_impl_item_method_mut( + &mut self, + item: &mut syn::ImplItemMethod, + ) { + self.add_unsafe_block(&item.sig, &mut item.block); + + syn::visit_mut::visit_impl_item_method_mut(self, item) + } + + fn visit_trait_item_method_mut( + &mut self, + item: &mut syn::TraitItemMethod, + ) { + if let Some(ref mut block) = item.default { + self.add_unsafe_block(&item.sig, block); + } + + syn::visit_mut::visit_trait_item_method_mut(self, item) + } + } + + for item in &mut syn_parsed_items { + syn::visit_mut::visit_item_mut( + &mut UnsafeBlocksVisitor, + item, + ); + } + } + let synful_items = syn_parsed_items .into_iter() .map(|item| item.into_token_stream()); diff --git a/src/options.rs b/src/options.rs index 83da21f42f..4038b37d33 100644 --- a/src/options.rs +++ b/src/options.rs @@ -518,6 +518,9 @@ where Arg::new("sort-semantically") .long("sort-semantically") .help("Enables sorting of code generation in a predefined manner."), + Arg::new("unsafe-blocks") + .long("unsafe-blocks") + .help("Wrap all the bodies of generated `unsafe` functions in `unsafe` blocks."), Arg::new("V") .long("version") .help("Prints the version, and exits"), @@ -1007,5 +1010,9 @@ where builder = builder.sort_semantically(true); } + if matches.is_present("unsafe-blocks") { + builder = builder.unsafe_blocks(true); + } + Ok((builder, output, verbose)) } diff --git a/tests/expectations/tests/unsafe_blocks.rs b/tests/expectations/tests/unsafe_blocks.rs new file mode 100644 index 0000000000..3bfa9c25b2 --- /dev/null +++ b/tests/expectations/tests/unsafe_blocks.rs @@ -0,0 +1,78 @@ +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +extern crate libloading; +pub struct TestLib { + __library: ::libloading::Library, + pub foo: Result< + unsafe extern "C" fn( + x: ::std::os::raw::c_int, + y: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub bar: Result< + unsafe extern "C" fn( + x: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int, + ::libloading::Error, + >, + pub baz: Result< + unsafe extern "C" fn() -> ::std::os::raw::c_int, + ::libloading::Error, + >, +} +impl TestLib { + pub unsafe fn new

(path: P) -> Result + where + P: AsRef<::std::ffi::OsStr>, + { + unsafe { + let library = ::libloading::Library::new(path)?; + Self::from_library(library) + } + } + pub unsafe fn from_library( + library: L, + ) -> Result + where + L: Into<::libloading::Library>, + { + unsafe { + let __library = library.into(); + let foo = __library.get(b"foo\0").map(|sym| *sym); + let bar = __library.get(b"bar\0").map(|sym| *sym); + let baz = __library.get(b"baz\0").map(|sym| *sym); + Ok(TestLib { + __library, + foo, + bar, + baz, + }) + } + } + pub unsafe fn foo( + &self, + x: ::std::os::raw::c_int, + y: ::std::os::raw::c_int, + ) -> ::std::os::raw::c_int { + unsafe { + (self.foo.as_ref().expect("Expected function, got error."))(x, y) + } + } + pub unsafe fn bar( + &self, + x: *mut ::std::os::raw::c_void, + ) -> ::std::os::raw::c_int { + unsafe { + (self.bar.as_ref().expect("Expected function, got error."))(x) + } + } + pub unsafe fn baz(&self) -> ::std::os::raw::c_int { + unsafe { (self.baz.as_ref().expect("Expected function, got error."))() } + } +} diff --git a/tests/headers/unsafe_blocks.h b/tests/headers/unsafe_blocks.h new file mode 100644 index 0000000000..63cb418203 --- /dev/null +++ b/tests/headers/unsafe_blocks.h @@ -0,0 +1,5 @@ +// bindgen-flags: --dynamic-loading TestLib --unsafe-blocks + +int foo(int x, int y); +int bar(void *x); +int baz();