Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Va list fn pointer typedef edge case fix #969

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 28 additions & 19 deletions src/bindgen/ir/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::borrow::Cow;
use {quote::ToTokens, std::borrow::Cow};

use syn::ext::IdentExt;

Expand Down Expand Up @@ -417,27 +417,36 @@ impl Type {
}
syn::Type::BareFn(ref function) => {
let mut wildcard_counter = 0;
let args = function.inputs.iter().try_skip_map(|x| {
Type::load(&x.ty).map(|opt_ty| {
opt_ty.map(|ty| {
(
x.name.as_ref().map(|(ref ident, _)| {
if ident == "_" {
wildcard_counter += 1;
if wildcard_counter == 1 {
"_".to_owned()
let var_args = function.variadic.as_ref().map(|v| syn::BareFnArg {
attrs: v.attrs.clone(),
name: None,
ty: syn::Type::Verbatim(v.dots.into_token_stream()),
});
let args = function
.inputs
.iter()
.chain(var_args.iter())
.try_skip_map(|x| {
Type::load(&x.ty).map(|opt_ty| {
opt_ty.map(|ty| {
(
x.name.as_ref().map(|(ref ident, _)| {
if ident == "_" {
wildcard_counter += 1;
if wildcard_counter == 1 {
"_".to_owned()
} else {
format!("_{}", wildcard_counter - 1)
}
} else {
format!("_{}", wildcard_counter - 1)
ident.unraw().to_string()
}
} else {
ident.unraw().to_string()
}
}),
ty,
)
}),
ty,
)
})
})
})
})?;
})?;
let (ret, never_return) = Type::load_from_output(&function.output)?;
Type::FuncPtr {
ret: Box::new(ret),
Expand Down
15 changes: 15 additions & 0 deletions tests/expectations/va_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,21 @@
#include <stdint.h>
#include <stdlib.h>

typedef int32_t (*VaListFnPtr)(va_list);

typedef int32_t (*VaListFnPtr2)(va_list);

typedef struct {
int32_t (*fn1)(va_list);
} Interface_______i32_______va_list;

int32_t va_list_test(va_list ap);

int32_t va_list_test2(va_list ap);

void va_list_fn_ptrs(int32_t (*fn1)(va_list),
int32_t (*fn2)(va_list),
VaListFnPtr fn3,
VaListFnPtr2 fn4,
Interface_______i32_______va_list fn5,
Interface_______i32_______va_list fn6);
15 changes: 15 additions & 0 deletions tests/expectations/va_list.compat.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@
#include <stdint.h>
#include <stdlib.h>

typedef int32_t (*VaListFnPtr)(va_list);

typedef int32_t (*VaListFnPtr2)(va_list);

typedef struct {
int32_t (*fn1)(va_list);
} Interface_______i32_______va_list;

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
Expand All @@ -11,6 +19,13 @@ int32_t va_list_test(va_list ap);

int32_t va_list_test2(va_list ap);

void va_list_fn_ptrs(int32_t (*fn1)(va_list),
int32_t (*fn2)(va_list),
VaListFnPtr fn3,
VaListFnPtr2 fn4,
Interface_______i32_______va_list fn5,
Interface_______i32_______va_list fn6);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
16 changes: 16 additions & 0 deletions tests/expectations/va_list.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,26 @@
#include <ostream>
#include <new>

using VaListFnPtr = int32_t(*)(va_list);

using VaListFnPtr2 = int32_t(*)(va_list);

template<typename T>
struct Interface {
T fn1;
};

extern "C" {

int32_t va_list_test(va_list ap);

int32_t va_list_test2(va_list ap);

void va_list_fn_ptrs(int32_t (*fn1)(va_list),
int32_t (*fn2)(va_list),
VaListFnPtr fn3,
VaListFnPtr2 fn4,
Interface<int32_t(*)(va_list)> fn5,
Interface<int32_t(*)(va_list)> fn6);

} // extern "C"
14 changes: 14 additions & 0 deletions tests/expectations/va_list.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ cdef extern from *:

cdef extern from *:

ctypedef int32_t (*VaListFnPtr)(va_list);

ctypedef int32_t (*VaListFnPtr2)(va_list);

ctypedef struct Interface_______i32_______va_list:
int32_t (*fn1)(va_list);

int32_t va_list_test(va_list ap);

int32_t va_list_test2(va_list ap);

void va_list_fn_ptrs(int32_t (*fn1)(va_list),
int32_t (*fn2)(va_list),
VaListFnPtr fn3,
VaListFnPtr2 fn4,
Interface_______i32_______va_list fn5,
Interface_______i32_______va_list fn6);
23 changes: 23 additions & 0 deletions tests/expectations/va_list_both.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef int32_t (*VaListFnPtr)(va_list);

typedef int32_t (*VaListFnPtr2)(va_list);

typedef struct Interface_______i32_______va_list {
int32_t (*fn1)(va_list);
} Interface_______i32_______va_list;

int32_t va_list_test(va_list ap);

int32_t va_list_test2(va_list ap);

void va_list_fn_ptrs(int32_t (*fn1)(va_list),
int32_t (*fn2)(va_list),
VaListFnPtr fn3,
VaListFnPtr2 fn4,
struct Interface_______i32_______va_list fn5,
struct Interface_______i32_______va_list fn6);
31 changes: 31 additions & 0 deletions tests/expectations/va_list_both.compat.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef int32_t (*VaListFnPtr)(va_list);

typedef int32_t (*VaListFnPtr2)(va_list);

typedef struct Interface_______i32_______va_list {
int32_t (*fn1)(va_list);
} Interface_______i32_______va_list;

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

int32_t va_list_test(va_list ap);

int32_t va_list_test2(va_list ap);

void va_list_fn_ptrs(int32_t (*fn1)(va_list),
int32_t (*fn2)(va_list),
VaListFnPtr fn3,
VaListFnPtr2 fn4,
struct Interface_______i32_______va_list fn5,
struct Interface_______i32_______va_list fn6);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
23 changes: 23 additions & 0 deletions tests/expectations/va_list_tag.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef int32_t (*VaListFnPtr)(va_list);

typedef int32_t (*VaListFnPtr2)(va_list);

struct Interface_______i32_______va_list {
int32_t (*fn1)(va_list);
};

int32_t va_list_test(va_list ap);

int32_t va_list_test2(va_list ap);

void va_list_fn_ptrs(int32_t (*fn1)(va_list),
int32_t (*fn2)(va_list),
VaListFnPtr fn3,
VaListFnPtr2 fn4,
struct Interface_______i32_______va_list fn5,
struct Interface_______i32_______va_list fn6);
31 changes: 31 additions & 0 deletions tests/expectations/va_list_tag.compat.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

typedef int32_t (*VaListFnPtr)(va_list);

typedef int32_t (*VaListFnPtr2)(va_list);

struct Interface_______i32_______va_list {
int32_t (*fn1)(va_list);
};

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

int32_t va_list_test(va_list ap);

int32_t va_list_test2(va_list ap);

void va_list_fn_ptrs(int32_t (*fn1)(va_list),
int32_t (*fn2)(va_list),
VaListFnPtr fn3,
VaListFnPtr2 fn4,
struct Interface_______i32_______va_list fn5,
struct Interface_______i32_______va_list fn6);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
25 changes: 25 additions & 0 deletions tests/expectations/va_list_tag.pyx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t
from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t
cdef extern from *:
ctypedef bint bool
ctypedef struct va_list

cdef extern from *:

ctypedef int32_t (*VaListFnPtr)(va_list);

ctypedef int32_t (*VaListFnPtr2)(va_list);

cdef struct Interface_______i32_______va_list:
int32_t (*fn1)(va_list);

int32_t va_list_test(va_list ap);

int32_t va_list_test2(va_list ap);

void va_list_fn_ptrs(int32_t (*fn1)(va_list),
int32_t (*fn2)(va_list),
VaListFnPtr fn3,
VaListFnPtr2 fn4,
Interface_______i32_______va_list fn5,
Interface_______i32_______va_list fn6);
19 changes: 19 additions & 0 deletions tests/rust/va_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,22 @@ pub unsafe extern "C" fn va_list_test(mut ap: VaList) -> int32_t {
pub unsafe extern "C" fn va_list_test2(mut ap: ...) -> int32_t {
ap.arg()
}

type VaListFnPtr = Option<unsafe extern "C" fn(VaList) -> int32_t>;
type VaListFnPtr2 = Option<unsafe extern "C" fn(...) -> int32_t>;

#[repr(C)]
struct Interface<T> {
fn1: T,
}

#[no_mangle]
pub extern "C" fn va_list_fn_ptrs(
fn1: Option<unsafe extern "C" fn(VaList) -> int32_t>,
fn2: Option<unsafe extern "C" fn(...) -> int32_t>,
fn3: VaListFnPtr,
fn4: VaListFnPtr2,
fn5: Interface<Option<unsafe extern "C" fn(VaList) -> int32_t>>,
fn6: Interface<Option<unsafe extern "C" fn(...) -> int32_t>>,
) {
}
Loading