summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilio Cobos Álvarez <emilio@crisal.io>2018-09-26 12:26:38 +0200
committerEmilio Cobos Álvarez <emilio@crisal.io>2018-09-26 12:33:50 +0200
commitc75b62d1a19b79a053996642f4915269e38f877c (patch)
tree4a4dcb262f29838cc6d20c396ddf0ae6880ac265
parent4a3eec8c4f996b78a1f7ae4ff8fee06bebd963b6 (diff)
A better fix for the calling convention madness.
Seems like a better fix, which allows us to preserve typedefs properly, and also to find the calling convention. Fixes #1402.
-rw-r--r--src/ir/function.rs11
-rw-r--r--src/ir/ty.rs27
-rw-r--r--tests/expectations/tests/call-conv-typedef.rs13
-rw-r--r--tests/headers/call-conv-typedef.h5
4 files changed, 29 insertions, 27 deletions
diff --git a/src/ir/function.rs b/src/ir/function.rs
index f7f4398b..3f2c8254 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -442,7 +442,16 @@ impl FunctionSig {
ty.ret_type().ok_or(ParseError::Continue)?
};
let ret = Item::from_ty_or_ref(ty_ret_type, cursor, None, ctx);
- let call_conv = ty.call_conv();
+
+ // Clang plays with us at "find the calling convention", see #549 and
+ // co. This seems to be a better fix than that commit.
+ let mut call_conv = ty.call_conv();
+ if let Some(ty) = cursor.cur_type().canonical_type().pointee_type() {
+ let cursor_call_conv = ty.call_conv();
+ if cursor_call_conv != CXCallingConv_Invalid {
+ call_conv = cursor_call_conv;
+ }
+ }
let abi = get_abi(call_conv);
if abi.is_unknown() {
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index 13153429..22ccdaa1 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -1054,32 +1054,7 @@ impl Type {
CXType_ObjCObjectPointer |
CXType_MemberPointer |
CXType_Pointer => {
- // Fun fact: the canonical type of a pointer type may sometimes
- // contain information we need but isn't present in the concrete
- // type (yeah, I'm equally wat'd).
- //
- // Yet we still have trouble if we unconditionally trust the
- // canonical type, like too-much desugaring (sigh).
- //
- // See tests/headers/call-conv-field.h for an example.
- //
- // Since for now the only identifier cause of breakage is the
- // ABI for function pointers, and different ABI mixed with
- // problematic stuff like that one is _extremely_ unlikely and
- // can be bypassed via blacklisting, we do the check explicitly
- // (as hacky as it is).
- //
- // Yet we should probably (somehow) get the best of both worlds,
- // presumably special-casing function pointers as a whole, yet
- // someone is going to need to care about typedef'd function
- // pointers, etc, which isn't trivial given function pointers
- // are mostly unexposed. I don't have the time for it right now.
- let mut pointee = ty.pointee_type().unwrap();
- let canonical_pointee =
- canonical_ty.pointee_type().unwrap();
- if pointee.call_conv() != canonical_pointee.call_conv() {
- pointee = canonical_pointee;
- }
+ let pointee = ty.pointee_type().unwrap();
let inner =
Item::from_ty_or_ref(pointee, location, None, ctx);
TypeKind::Pointer(inner)
diff --git a/tests/expectations/tests/call-conv-typedef.rs b/tests/expectations/tests/call-conv-typedef.rs
new file mode 100644
index 00000000..f30d2356
--- /dev/null
+++ b/tests/expectations/tests/call-conv-typedef.rs
@@ -0,0 +1,13 @@
+/* automatically generated by rust-bindgen */
+
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+#![cfg(not(test))]
+
+pub type void_fn = ::std::option::Option<unsafe extern "stdcall" fn()>;
+pub type fn_ =
+ ::std::option::Option<unsafe extern "stdcall" fn(id: ::std::os::raw::c_int) -> void_fn>;
diff --git a/tests/headers/call-conv-typedef.h b/tests/headers/call-conv-typedef.h
new file mode 100644
index 00000000..3b911dda
--- /dev/null
+++ b/tests/headers/call-conv-typedef.h
@@ -0,0 +1,5 @@
+// bindgen-flags: --raw-line "#![cfg(not(test))]" -- --target=i686-pc-win32
+
+
+typedef void (__stdcall *void_fn)();
+typedef void_fn (__stdcall *fn)(int id);