Skip to content

Commit

Permalink
Wrap va_list function as variadic function (#2502)
Browse files Browse the repository at this point in the history
* Add more generic version of fnsig_arguments based on iterator

* Wrap va_list function as variadic function

* Add tests for wrapped va_list fn as variadic

* Add tests for wrapped va_list in bindgen-integration

* Make an exception for including stdarg.h in the tests

* Add wrap_as_variadic_fn in the CHANGELOG.md
  • Loading branch information
Urgau authored Jun 5, 2023
1 parent 4faa366 commit bfc5b7f
Show file tree
Hide file tree
Showing 12 changed files with 351 additions and 48 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@
instead of `&[u8]`. (Requires Rust 1.59 or higher.)
* Added the `--generate-shell-completions` CLI flag to generate completions for
different shells.
* The `--wrap-static-fns` option can now wrap `va_list` functions as variadic functions
with the experimental `wrap_as_variadic_fn` callback.

## Changed

Expand Down
12 changes: 12 additions & 0 deletions bindgen-integration/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,15 @@ impl Drop for MacroCallback {
}
}

#[derive(Debug)]
struct WrappedVaListCallback;

impl ParseCallbacks for WrappedVaListCallback {
fn wrap_as_variadic_fn(&self, name: &str) -> Option<String> {
Some(name.to_owned() + "_wrapped")
}
}

fn setup_macro_test() {
cc::Build::new()
.cpp(true)
Expand Down Expand Up @@ -223,10 +232,12 @@ fn setup_wrap_static_fns_test() {
let bindings = Builder::default()
.header(input_header_file_path_str)
.parse_callbacks(Box::new(CargoCallbacks))
.parse_callbacks(Box::new(WrappedVaListCallback))
.wrap_static_fns(true)
.wrap_static_fns_path(
out_path.join("wrap_static_fns").display().to_string(),
)
.clang_arg("-DUSE_VA_HEADER")
.generate()
.expect("Unable to generate bindings");

Expand All @@ -242,6 +253,7 @@ fn setup_wrap_static_fns_test() {
.arg("-o")
.arg(&obj_path)
.arg(out_path.join("wrap_static_fns.c"))
.arg("-DUSE_VA_HEADER")
.output()
.expect("`clang` command error");
if !clang_output.status.success() {
Expand Down
8 changes: 8 additions & 0 deletions bindgen-integration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -320,5 +320,13 @@ fn test_wrap_static_fns() {
let tq =
extern_bindings::takes_qualified(&(&5 as *const _) as *const _);
assert_eq!(5, tq);

let wv1 = extern_bindings::wrap_as_variadic_fn1_wrapped(0);
assert_eq!(0, wv1);

let wv1 = extern_bindings::wrap_as_variadic_fn1_wrapped(2, 5, 3);
assert_eq!(8, wv1);

extern_bindings::wrap_as_variadic_fn2_wrapped(1, 2);
}
}
18 changes: 18 additions & 0 deletions bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,21 @@ int takes_alias__extern(func f) { return takes_alias(f); }
int takes_qualified__extern(const int *const *arg) { return takes_qualified(arg); }
enum foo takes_enum__extern(const enum foo f) { return takes_enum(f); }
void nevermore__extern(void) { nevermore(); }
void no_extra_argument__extern(__builtin_va_list va) { no_extra_argument(va); }
int many_va_list__extern(int i, __builtin_va_list va1, __builtin_va_list va2) { return many_va_list(i, va1, va2); }
int wrap_as_variadic_fn1__extern(int i, ...) {
int ret;
va_list ap;

va_start(ap, i);
ret = wrap_as_variadic_fn1(i, ap);
va_end(ap);
return ret;
}
void wrap_as_variadic_fn2__extern(int i, ...) {
va_list ap;

va_start(ap, i);
wrap_as_variadic_fn2(i, ap);
va_end(ap);
}
33 changes: 33 additions & 0 deletions bindgen-tests/tests/expectations/tests/wrap-static-fns.rs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

32 changes: 32 additions & 0 deletions bindgen-tests/tests/headers/wrap-static-fns.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
// bindgen-flags: --experimental --wrap-static-fns
// bindgen-parse-callbacks: wrap-as-variadic-fn

// to avoid poluting theexpectation tests we put the stdarg.h behind a conditional
// variable only used in bindgen-integration
#ifdef USE_VA_HEADER
#include <stdarg.h>
#endif

static inline int foo() {
return 11;
Expand Down Expand Up @@ -48,3 +55,28 @@ static inline void nevermore() {
static inline int variadic(int x, ...) {
return x;
}

static inline void no_extra_argument(__builtin_va_list va) {}

static inline int many_va_list(int i, __builtin_va_list va1, __builtin_va_list va2) {
return i;
}

#ifndef USE_VA_HEADER
static inline int wrap_as_variadic_fn1(int i, __builtin_va_list va) {
return i;
}

static inline void wrap_as_variadic_fn2(int i, __builtin_va_list va) {}
#else
static inline int wrap_as_variadic_fn1(int i, va_list va) {
int res = 0;

for (int j = 0; j < i; j++)
res += (int) va_arg(va, int);

return res;
}

static inline void wrap_as_variadic_fn2(int i, va_list va) {}
#endif
10 changes: 10 additions & 0 deletions bindgen-tests/tests/parse_callbacks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,15 @@ impl ParseCallbacks for FieldVisibility {
}
}

#[derive(Debug)]
pub(super) struct WrapAsVariadicFn;

impl ParseCallbacks for WrapAsVariadicFn {
fn wrap_as_variadic_fn(&self, name: &str) -> Option<String> {
Some(name.to_owned() + "_wrapped")
}
}

pub fn lookup(cb: &str) -> Box<dyn ParseCallbacks> {
fn try_strip_prefix<'a>(s: &'a str, prefix: &str) -> Option<&'a str> {
if s.starts_with(prefix) {
Expand All @@ -127,6 +136,7 @@ pub fn lookup(cb: &str) -> Box<dyn ParseCallbacks> {
"blocklisted-type-implements-trait" => {
Box::new(BlocklistedTypeImplementsTrait)
}
"wrap-as-variadic-fn" => Box::new(WrapAsVariadicFn),
call_back => {
if let Some(prefix) =
try_strip_prefix(call_back, "remove-function-prefix-")
Expand Down
1 change: 1 addition & 0 deletions bindgen-tests/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ fn test_wrap_static_fns() {
.header("tests/headers/wrap-static-fns.h")
.wrap_static_fns(true)
.wrap_static_fns_path(generated_path.display().to_string())
.parse_callbacks(Box::new(parse_callbacks::WrapAsVariadicFn))
.generate()
.expect("Failed to generate bindings");

Expand Down
10 changes: 10 additions & 0 deletions bindgen/callbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,16 @@ pub trait ParseCallbacks: fmt::Debug {
) -> Option<crate::FieldVisibilityKind> {
None
}

/// Process a function name that as exactly one `va_list` argument
/// to be wrapped as a variadic function with the wrapped static function
/// feature.
///
/// The returned string is new function name.
#[cfg(feature = "experimental")]
fn wrap_as_variadic_fn(&self, _name: &str) -> Option<String> {
None
}
}

/// Relevant information about a type to which new derive attributes will be added using
Expand Down
Loading

0 comments on commit bfc5b7f

Please sign in to comment.