Skip to content

Commit bfc5b7f

Browse files
authored
Wrap va_list function as variadic function (#2502)
* 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
1 parent 4faa366 commit bfc5b7f

File tree

12 files changed

+351
-48
lines changed

12 files changed

+351
-48
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,8 @@
170170
instead of `&[u8]`. (Requires Rust 1.59 or higher.)
171171
* Added the `--generate-shell-completions` CLI flag to generate completions for
172172
different shells.
173+
* The `--wrap-static-fns` option can now wrap `va_list` functions as variadic functions
174+
with the experimental `wrap_as_variadic_fn` callback.
173175

174176
## Changed
175177

bindgen-integration/build.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,15 @@ impl Drop for MacroCallback {
149149
}
150150
}
151151

152+
#[derive(Debug)]
153+
struct WrappedVaListCallback;
154+
155+
impl ParseCallbacks for WrappedVaListCallback {
156+
fn wrap_as_variadic_fn(&self, name: &str) -> Option<String> {
157+
Some(name.to_owned() + "_wrapped")
158+
}
159+
}
160+
152161
fn setup_macro_test() {
153162
cc::Build::new()
154163
.cpp(true)
@@ -223,10 +232,12 @@ fn setup_wrap_static_fns_test() {
223232
let bindings = Builder::default()
224233
.header(input_header_file_path_str)
225234
.parse_callbacks(Box::new(CargoCallbacks))
235+
.parse_callbacks(Box::new(WrappedVaListCallback))
226236
.wrap_static_fns(true)
227237
.wrap_static_fns_path(
228238
out_path.join("wrap_static_fns").display().to_string(),
229239
)
240+
.clang_arg("-DUSE_VA_HEADER")
230241
.generate()
231242
.expect("Unable to generate bindings");
232243

@@ -242,6 +253,7 @@ fn setup_wrap_static_fns_test() {
242253
.arg("-o")
243254
.arg(&obj_path)
244255
.arg(out_path.join("wrap_static_fns.c"))
256+
.arg("-DUSE_VA_HEADER")
245257
.output()
246258
.expect("`clang` command error");
247259
if !clang_output.status.success() {

bindgen-integration/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,5 +320,13 @@ fn test_wrap_static_fns() {
320320
let tq =
321321
extern_bindings::takes_qualified(&(&5 as *const _) as *const _);
322322
assert_eq!(5, tq);
323+
324+
let wv1 = extern_bindings::wrap_as_variadic_fn1_wrapped(0);
325+
assert_eq!(0, wv1);
326+
327+
let wv1 = extern_bindings::wrap_as_variadic_fn1_wrapped(2, 5, 3);
328+
assert_eq!(8, wv1);
329+
330+
extern_bindings::wrap_as_variadic_fn2_wrapped(1, 2);
323331
}
324332
}

bindgen-tests/tests/expectations/tests/generated/wrap_static_fns.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,21 @@ int takes_alias__extern(func f) { return takes_alias(f); }
1111
int takes_qualified__extern(const int *const *arg) { return takes_qualified(arg); }
1212
enum foo takes_enum__extern(const enum foo f) { return takes_enum(f); }
1313
void nevermore__extern(void) { nevermore(); }
14+
void no_extra_argument__extern(__builtin_va_list va) { no_extra_argument(va); }
15+
int many_va_list__extern(int i, __builtin_va_list va1, __builtin_va_list va2) { return many_va_list(i, va1, va2); }
16+
int wrap_as_variadic_fn1__extern(int i, ...) {
17+
int ret;
18+
va_list ap;
19+
20+
va_start(ap, i);
21+
ret = wrap_as_variadic_fn1(i, ap);
22+
va_end(ap);
23+
return ret;
24+
}
25+
void wrap_as_variadic_fn2__extern(int i, ...) {
26+
va_list ap;
27+
28+
va_start(ap, i);
29+
wrap_as_variadic_fn2(i, ap);
30+
va_end(ap);
31+
}

bindgen-tests/tests/expectations/tests/wrap-static-fns.rs

Lines changed: 33 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bindgen-tests/tests/headers/wrap-static-fns.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
// bindgen-flags: --experimental --wrap-static-fns
2+
// bindgen-parse-callbacks: wrap-as-variadic-fn
3+
4+
// to avoid poluting theexpectation tests we put the stdarg.h behind a conditional
5+
// variable only used in bindgen-integration
6+
#ifdef USE_VA_HEADER
7+
#include <stdarg.h>
8+
#endif
29

310
static inline int foo() {
411
return 11;
@@ -48,3 +55,28 @@ static inline void nevermore() {
4855
static inline int variadic(int x, ...) {
4956
return x;
5057
}
58+
59+
static inline void no_extra_argument(__builtin_va_list va) {}
60+
61+
static inline int many_va_list(int i, __builtin_va_list va1, __builtin_va_list va2) {
62+
return i;
63+
}
64+
65+
#ifndef USE_VA_HEADER
66+
static inline int wrap_as_variadic_fn1(int i, __builtin_va_list va) {
67+
return i;
68+
}
69+
70+
static inline void wrap_as_variadic_fn2(int i, __builtin_va_list va) {}
71+
#else
72+
static inline int wrap_as_variadic_fn1(int i, va_list va) {
73+
int res = 0;
74+
75+
for (int j = 0; j < i; j++)
76+
res += (int) va_arg(va, int);
77+
78+
return res;
79+
}
80+
81+
static inline void wrap_as_variadic_fn2(int i, va_list va) {}
82+
#endif

bindgen-tests/tests/parse_callbacks/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ impl ParseCallbacks for FieldVisibility {
113113
}
114114
}
115115

116+
#[derive(Debug)]
117+
pub(super) struct WrapAsVariadicFn;
118+
119+
impl ParseCallbacks for WrapAsVariadicFn {
120+
fn wrap_as_variadic_fn(&self, name: &str) -> Option<String> {
121+
Some(name.to_owned() + "_wrapped")
122+
}
123+
}
124+
116125
pub fn lookup(cb: &str) -> Box<dyn ParseCallbacks> {
117126
fn try_strip_prefix<'a>(s: &'a str, prefix: &str) -> Option<&'a str> {
118127
if s.starts_with(prefix) {
@@ -127,6 +136,7 @@ pub fn lookup(cb: &str) -> Box<dyn ParseCallbacks> {
127136
"blocklisted-type-implements-trait" => {
128137
Box::new(BlocklistedTypeImplementsTrait)
129138
}
139+
"wrap-as-variadic-fn" => Box::new(WrapAsVariadicFn),
130140
call_back => {
131141
if let Some(prefix) =
132142
try_strip_prefix(call_back, "remove-function-prefix-")

bindgen-tests/tests/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,7 @@ fn test_wrap_static_fns() {
618618
.header("tests/headers/wrap-static-fns.h")
619619
.wrap_static_fns(true)
620620
.wrap_static_fns_path(generated_path.display().to_string())
621+
.parse_callbacks(Box::new(parse_callbacks::WrapAsVariadicFn))
621622
.generate()
622623
.expect("Failed to generate bindings");
623624

bindgen/callbacks.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,16 @@ pub trait ParseCallbacks: fmt::Debug {
146146
) -> Option<crate::FieldVisibilityKind> {
147147
None
148148
}
149+
150+
/// Process a function name that as exactly one `va_list` argument
151+
/// to be wrapped as a variadic function with the wrapped static function
152+
/// feature.
153+
///
154+
/// The returned string is new function name.
155+
#[cfg(feature = "experimental")]
156+
fn wrap_as_variadic_fn(&self, _name: &str) -> Option<String> {
157+
None
158+
}
149159
}
150160

151161
/// Relevant information about a type to which new derive attributes will be added using

0 commit comments

Comments
 (0)