diff --git a/src/ir/context.rs b/src/ir/context.rs index 3f69aca18b..f349033267 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -514,12 +514,19 @@ const HOST_TARGET: &'static str = fn find_effective_target(clang_args: &[String]) -> (String, bool) { use std::env; - for opt in clang_args { + let mut args = clang_args.iter(); + while let Some(opt) = args.next() { if opt.starts_with("--target=") { let mut split = opt.split('='); split.next(); return (split.next().unwrap().to_owned(), true); } + + if opt == "-target" { + if let Some(target) = args.next() { + return (target.clone(), true); + } + } } // If we're running from a build script, try to find the cargo target. @@ -576,7 +583,10 @@ If you encounter an error missing from this list, please file an issue or a PR!" { if let Some(ref ti) = target_info { if effective_target == HOST_TARGET { - assert_eq!(ti.pointer_width / 8, mem::size_of::<*mut ()>()); + assert_eq!( + ti.pointer_width / 8, mem::size_of::<*mut ()>(), + "{:?} {:?}", effective_target, HOST_TARGET + ); } } } diff --git a/src/ir/function.rs b/src/ir/function.rs index f7f4398bf6..3f2c825472 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 13153429f6..22ccdaa12e 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 0000000000..f30d235689 --- /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; +pub type fn_ = + ::std::option::Option void_fn>; diff --git a/tests/headers/call-conv-typedef.h b/tests/headers/call-conv-typedef.h new file mode 100644 index 0000000000..3b911ddae5 --- /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);