Skip to content

Commit 56021b2

Browse files
committed
Fix calling convention propagation for function pointers.
This sucks, but works. The full solution is a refactoring that needs more thought than the time I'm able to dedicate to bindgen right now, see the comment for details. Signed-off-by: Emilio Cobos Álvarez <[email protected]>
1 parent 4e4f092 commit 56021b2

File tree

4 files changed

+74
-2
lines changed

4 files changed

+74
-2
lines changed

src/clang.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -633,9 +633,10 @@ impl Eq for Type {}
633633
impl fmt::Debug for Type {
634634
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
635635
write!(fmt,
636-
"Type({}, kind: {}, decl: {:?}, canon: {:?})",
636+
"Type({}, kind: {}, cconv: {}, decl: {:?}, canon: {:?})",
637637
self.spelling(),
638638
type_to_str(self.kind()),
639+
self.call_conv(),
639640
self.declaration(),
640641
self.declaration().canonical())
641642
}
@@ -1520,6 +1521,8 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
15201521
return;
15211522
}
15221523

1524+
print_indent(depth, format!(" {}cconv = {}", prefix, ty.call_conv()));
1525+
15231526
print_indent(depth,
15241527
format!(" {}spelling = \"{}\"", prefix, ty.spelling()));
15251528
let num_template_args =

src/ir/ty.rs

+27-1
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,7 @@ impl Type {
877877
let kind = match ty_kind {
878878
CXType_Unexposed if *ty != canonical_ty &&
879879
canonical_ty.kind() != CXType_Invalid &&
880+
ty.ret_type().is_none() &&
880881
// Sometime clang desugars some types more than
881882
// what we need, specially with function
882883
// pointers.
@@ -1132,7 +1133,32 @@ impl Type {
11321133
CXType_ObjCObjectPointer |
11331134
CXType_MemberPointer |
11341135
CXType_Pointer => {
1135-
let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(),
1136+
// Fun fact: the canonical type of a pointer type may sometimes
1137+
// contain information we need but isn't present in the concrete
1138+
// type (yeah, I'm equally wat'd).
1139+
//
1140+
// Yet we still have trouble if we unconditionally trust the
1141+
// canonical type, like too-much desugaring (sigh).
1142+
//
1143+
// See tests/headers/call-conv-field.h for an example.
1144+
//
1145+
// Since for now the only identifier cause of breakage is the
1146+
// ABI for function pointers, and different ABI mixed with
1147+
// problematic stuff like that one is _extremely_ unlikely and
1148+
// can be bypassed via blacklisting, we do the check explicitly
1149+
// (as hacky as it is).
1150+
//
1151+
// Yet we should probably (somehow) get the best of both worlds,
1152+
// presumably special-casing function pointers as a whole, yet
1153+
// someone is going to need to care about typedef'd function
1154+
// pointers, etc, which isn't trivial given function pointers
1155+
// are mostly unexposed. I don't have the time for it right now.
1156+
let mut pointee = ty.pointee_type().unwrap();
1157+
let canonical_pointee = canonical_ty.pointee_type().unwrap();
1158+
if pointee.call_conv() != canonical_pointee.call_conv() {
1159+
pointee = canonical_pointee;
1160+
}
1161+
let inner = Item::from_ty_or_ref(pointee,
11361162
location,
11371163
None,
11381164
ctx);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
4+
#![allow(non_snake_case)]
5+
6+
7+
#[repr(C)]
8+
#[derive(Debug, Copy)]
9+
pub struct JNINativeInterface_ {
10+
pub GetVersion: ::std::option::Option<unsafe extern "stdcall" fn(env:
11+
*mut ::std::os::raw::c_void)
12+
-> ::std::os::raw::c_int>,
13+
}
14+
#[test]
15+
fn bindgen_test_layout_JNINativeInterface_() {
16+
assert_eq!(::std::mem::size_of::<JNINativeInterface_>() , 4usize , concat
17+
! ( "Size of: " , stringify ! ( JNINativeInterface_ ) ));
18+
assert_eq! (::std::mem::align_of::<JNINativeInterface_>() , 4usize ,
19+
concat ! (
20+
"Alignment of " , stringify ! ( JNINativeInterface_ ) ));
21+
assert_eq! (unsafe {
22+
& ( * ( 0 as * const JNINativeInterface_ ) ) . GetVersion as *
23+
const _ as usize } , 0usize , concat ! (
24+
"Alignment of field: " , stringify ! ( JNINativeInterface_ ) ,
25+
"::" , stringify ! ( GetVersion ) ));
26+
}
27+
impl Clone for JNINativeInterface_ {
28+
fn clone(&self) -> Self { *self }
29+
}
30+
impl Default for JNINativeInterface_ {
31+
fn default() -> Self { unsafe { ::std::mem::zeroed() } }
32+
}
33+
extern "stdcall" {
34+
#[link_name = "_bar@0"]
35+
pub fn bar();
36+
}

tests/headers/call-conv-field.h

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// bindgen-flags: -- -target i686-pc-win32
2+
3+
struct JNINativeInterface_ {
4+
int (__stdcall *GetVersion)(void *env);
5+
};
6+
7+
__stdcall void bar();

0 commit comments

Comments
 (0)