From 9b95ce6a76d32a1c152bd3719d6cf46dd872b630 Mon Sep 17 00:00:00 2001 From: Liran Ringel Date: Mon, 9 Oct 2017 02:38:29 +0200 Subject: [PATCH] Add support for the thiscall ABI --- src/codegen/mod.rs | 22 +++++++-- src/features.rs | 3 ++ src/ir/function.rs | 4 ++ .../expectations/tests/win32-thiscall_1_0.rs | 29 +++++++++++ .../tests/win32-thiscall_nightly.rs | 48 +++++++++++++++++++ tests/headers/win32-thiscall_1_0.hpp | 7 +++ tests/headers/win32-thiscall_nightly.hpp | 7 +++ 7 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 tests/expectations/tests/win32-thiscall_1_0.rs create mode 100644 tests/expectations/tests/win32-thiscall_nightly.rs create mode 100644 tests/headers/win32-thiscall_1_0.hpp create mode 100644 tests/headers/win32-thiscall_nightly.hpp diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index ea9fec4158..ca982b6bf6 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1945,6 +1945,10 @@ impl MethodCodegen for Method { _ => panic!("How in the world?"), }; + if let (Abi::ThisCall, false) = (signature.abi(), ctx.options().rust_features().thiscall_abi()) { + return; + } + // Do not generate variadic methods, since rust does not allow // implementing them, and we don't do a good job at it anyway. if signature.is_variadic() { @@ -3058,9 +3062,17 @@ impl TryToRustTy for FunctionSig { let arguments = utils::fnsig_arguments(ctx, &self); let abi = self.abi(); - Ok(quote! { - unsafe extern #abi fn ( #( #arguments ),* ) #ret - }) + match abi { + Abi::ThisCall if !ctx.options().rust_features().thiscall_abi() => { + warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target"); + Ok(quote::Tokens::new()) + } + _ => { + Ok(quote! { + unsafe extern #abi fn ( #( #arguments ),* ) #ret + }) + } + } } } @@ -3132,6 +3144,10 @@ impl CodeGenerator for Function { } let abi = match signature.abi() { + Abi::ThisCall if !ctx.options().rust_features().thiscall_abi() => { + warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target"); + return; + } Abi::Unknown(unknown_abi) => { panic!( "Invalid or unknown abi {:?} for function {:?} ({:?})", diff --git a/src/features.rs b/src/features.rs index 29e60ab735..b89185fd9b 100644 --- a/src/features.rs +++ b/src/features.rs @@ -140,6 +140,8 @@ rust_feature_def!( => untagged_union; /// Constant function ([RFC 911](https://github.com/rust-lang/rfcs/blob/master/text/0911-const-fn.md)) => const_fn; + /// `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202)) + => thiscall_abi; ); impl From for RustFeatures { @@ -152,6 +154,7 @@ impl From for RustFeatures { if rust_target >= RustTarget::Nightly { features.const_fn = true; + features.thiscall_abi = true; } features diff --git a/src/ir/function.rs b/src/ir/function.rs index b637f9f12b..2eab663835 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -142,6 +142,8 @@ pub enum Abi { Stdcall, /// The "fastcall" ABI. Fastcall, + /// The "thiscall" ABI. + ThisCall, /// The "aapcs" ABI. Aapcs, /// The "win64" ABI. @@ -166,6 +168,7 @@ impl quote::ToTokens for Abi { Abi::C => quote! { "C" }, Abi::Stdcall => quote! { "stdcall" }, Abi::Fastcall => quote! { "fastcall" }, + Abi::ThisCall => quote! { "thiscall" }, Abi::Aapcs => quote! { "aapcs" }, Abi::Win64 => quote! { "win64" }, Abi::Unknown(cc) => panic!( @@ -200,6 +203,7 @@ fn get_abi(cc: CXCallingConv) -> Abi { CXCallingConv_C => Abi::C, CXCallingConv_X86StdCall => Abi::Stdcall, CXCallingConv_X86FastCall => Abi::Fastcall, + CXCallingConv_X86ThisCall => Abi::ThisCall, CXCallingConv_AAPCS => Abi::Aapcs, CXCallingConv_X86_64Win64 => Abi::Win64, other => Abi::Unknown(other), diff --git a/tests/expectations/tests/win32-thiscall_1_0.rs b/tests/expectations/tests/win32-thiscall_1_0.rs new file mode 100644 index 0000000000..f84a70055b --- /dev/null +++ b/tests/expectations/tests/win32-thiscall_1_0.rs @@ -0,0 +1,29 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct Foo { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_Foo() { + assert_eq!( + ::std::mem::size_of::(), + 1usize, + concat!("Size of: ", stringify!(Foo)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(Foo)) + ); +} +impl Clone for Foo { + fn clone(&self) -> Self { + *self + } +} diff --git a/tests/expectations/tests/win32-thiscall_nightly.rs b/tests/expectations/tests/win32-thiscall_nightly.rs new file mode 100644 index 0000000000..0fd1c00ddc --- /dev/null +++ b/tests/expectations/tests/win32-thiscall_nightly.rs @@ -0,0 +1,48 @@ +/* automatically generated by rust-bindgen */ + + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#![cfg(feature = "nightly")] +#![feature(abi_thiscall)] + +#[repr(C)] +#[derive(Debug, Default, Copy)] +pub struct Foo { + pub _address: u8, +} +#[test] +fn bindgen_test_layout_Foo() { + assert_eq!( + ::std::mem::size_of::(), + 1usize, + concat!("Size of: ", stringify!(Foo)) + ); + assert_eq!( + ::std::mem::align_of::(), + 1usize, + concat!("Alignment of ", stringify!(Foo)) + ); +} +extern "thiscall" { + #[link_name = "\u{1}?test@Foo@@QAEXXZ"] + pub fn Foo_test(this: *mut Foo); +} +extern "thiscall" { + #[link_name = "\u{1}?test2@Foo@@QAEHH@Z"] + pub fn Foo_test2(this: *mut Foo, var: ::std::os::raw::c_int) -> ::std::os::raw::c_int; +} +impl Clone for Foo { + fn clone(&self) -> Self { + *self + } +} +impl Foo { + #[inline] + pub unsafe fn test(&mut self) { + Foo_test(self) + } + #[inline] + pub unsafe fn test2(&mut self, var: ::std::os::raw::c_int) -> ::std::os::raw::c_int { + Foo_test2(self, var) + } +} diff --git a/tests/headers/win32-thiscall_1_0.hpp b/tests/headers/win32-thiscall_1_0.hpp new file mode 100644 index 0000000000..5907c76eaf --- /dev/null +++ b/tests/headers/win32-thiscall_1_0.hpp @@ -0,0 +1,7 @@ +// bindgen-flags: --rust-target 1.0 -- --target=i686-pc-windows-msvc + +class Foo { + public: + void test(); + int test2(int var); +}; diff --git a/tests/headers/win32-thiscall_nightly.hpp b/tests/headers/win32-thiscall_nightly.hpp new file mode 100644 index 0000000000..2c9f2f1748 --- /dev/null +++ b/tests/headers/win32-thiscall_nightly.hpp @@ -0,0 +1,7 @@ +// bindgen-flags: --rust-target nightly --raw-line '#![cfg(feature = "nightly")]' --raw-line '#![feature(abi_thiscall)]' -- --target=i686-pc-windows-msvc + +class Foo { + public: + void test(); + int test2(int var); +};