diff --git a/Cargo.lock b/Cargo.lock index 7f4f0f5c..15f3fb22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,7 @@ dependencies = [ "clap", "heck", "indexmap", + "indoc", "log", "pretty_assertions", "proc-macro2", @@ -184,6 +185,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indoc" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" + [[package]] name = "is_terminal_polyfill" version = "1.70.0" diff --git a/Cargo.toml b/Cargo.toml index a545477b..5f94cb8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,6 +29,7 @@ toml = "0.8.8" proc-macro2 = "1.0.60" quote = "1" heck = "0.4" +indoc = "2.0.5" [dependencies.syn] version = "2.0.64" diff --git a/docs.md b/docs.md index c8ce9f4f..4c85b994 100644 --- a/docs.md +++ b/docs.md @@ -773,6 +773,18 @@ rename_args = "PascalCase" # default: "None" sort_by = "Name" +# This rule specifies whether calling conventions specified in Rust should be +# translated and emitted in C-like outputs. +# +# For example, `extern "cdecl" fn foo() {}` will be emitted as `void +# __cbindgen_abi_cdecl foo();` and a compiler-specific definition (for Clang, GCC, ICX, +# and MSVC) will be emitted at the top of the file defining `__cbindgen_abi_cdecl` to +# the appropriate form for the compiler in the case of `cdecl`, this is `__cdecl` for +# Clang, ICX, and MSVC and `__attribute__((cdecl))` for GCC. +# +# default: true +emit_calling_convention = true + [struct] # A rule to use to rename struct field names. The renaming assumes the input is # the Rust standard snake_case, however it acccepts all the different rename_args diff --git a/src/bindgen/bindings.rs b/src/bindgen/bindings.rs index 029cfc66..9456014e 100644 --- a/src/bindgen/bindings.rs +++ b/src/bindgen/bindings.rs @@ -18,6 +18,7 @@ use crate::bindgen::ir::{ use crate::bindgen::language_backend::{ CLikeLanguageBackend, CythonLanguageBackend, LanguageBackend, }; +use crate::bindgen::predefines::Predefines; use crate::bindgen::writer::SourceWriter; /// A bindings header that can be written. @@ -28,6 +29,10 @@ pub struct Bindings { struct_map: ItemMap, typedef_map: ItemMap, struct_fileds_memo: RefCell>>>, + /// Raw code that needs to be inserted at the top of the generated bindings, usually + /// based on some condition found in the code itself (motivating example being + /// defining compiler and platform independent calling conventions) + pub predefines: Predefines, pub globals: Vec, pub constants: Vec, pub items: Vec, @@ -46,6 +51,7 @@ impl Bindings { struct_map: ItemMap, typedef_map: ItemMap, constants: Vec, + predefines: Predefines, globals: Vec, items: Vec, functions: Vec, @@ -58,6 +64,7 @@ impl Bindings { struct_map, typedef_map, struct_fileds_memo: Default::default(), + predefines, globals, constants, items, diff --git a/src/bindgen/builder.rs b/src/bindgen/builder.rs index d47919b9..64350929 100644 --- a/src/bindgen/builder.rs +++ b/src/bindgen/builder.rs @@ -360,6 +360,7 @@ impl Builder { Default::default(), Default::default(), Default::default(), + Default::default(), true, String::new(), )); diff --git a/src/bindgen/cdecl.rs b/src/bindgen/cdecl.rs index 3ba543ac..faaf3e0b 100644 --- a/src/bindgen/cdecl.rs +++ b/src/bindgen/cdecl.rs @@ -11,6 +11,8 @@ use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::writer::{ListType, SourceWriter}; use crate::bindgen::{Config, Language}; +use super::ir::FunctionAbi; + // This code is for translating Rust types into C declarations. // See Section 6.7, Declarations, in the C standard for background. // http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf @@ -40,6 +42,7 @@ struct CDecl { type_name: String, type_generic_args: Vec, declarators: Vec, + abi: Option, type_ctype: Option, deprecated: Option, } @@ -51,6 +54,7 @@ impl CDecl { type_name: String::new(), type_generic_args: Vec::new(), declarators: Vec::new(), + abi: None, type_ctype: None, deprecated: None, } @@ -103,6 +107,7 @@ impl CDecl { never_return: f.never_return, }); self.deprecated.clone_from(&f.annotations.deprecated); + self.abi = Some(f.abi.clone()); self.build_type(&f.ret, false, config); } @@ -267,6 +272,14 @@ impl CDecl { } } + if config.language != Language::Cython && config.function.emit_calling_convention { + if let Some(ref abi) = self.abi { + if let Some(attribute) = abi.as_attribute() { + write!(out, "{} ", attribute); + } + } + } + // Write the identifier if let Some(ident) = ident { write!(out, "{}", ident); diff --git a/src/bindgen/config.rs b/src/bindgen/config.rs index 31316503..c8a57824 100644 --- a/src/bindgen/config.rs +++ b/src/bindgen/config.rs @@ -430,6 +430,8 @@ pub struct FunctionConfig { pub sort_by: Option, /// Optional text to output after functions which return `!`. pub no_return: Option, + /// Whether to emit calling convention attributes for functions which declare them + pub emit_calling_convention: bool, } impl Default for FunctionConfig { @@ -445,6 +447,7 @@ impl Default for FunctionConfig { swift_name_macro: None, sort_by: None, no_return: None, + emit_calling_convention: true, } } } diff --git a/src/bindgen/ir/function.rs b/src/bindgen/ir/function.rs index 79adfce9..d1a2edcf 100644 --- a/src/bindgen/ir/function.rs +++ b/src/bindgen/ir/function.rs @@ -6,6 +6,8 @@ use std::collections::HashMap; use syn::ext::IdentExt; +use indoc::indoc; + use crate::bindgen::config::{Config, Language}; use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; use crate::bindgen::dependencies::Dependencies; @@ -16,6 +18,571 @@ use crate::bindgen::rename::{IdentifierType, RenameRule}; use crate::bindgen::reserved; use crate::bindgen::utilities::IterHelpers; +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +/// A function ABI in Rust. Rust ABIs are defined in: +/// +/// https://github.com/rust-lang/rust/blob/9c3bc805dd9cb84019c124b9a50fdff1e62a7ec9/compiler/rustc_target/src/spec/abi/mod.r +/// +/// There are a few more ABIs, but only stable ABIs are supported currently. +/// +/// See the compiler explorer for a test of all the ABIs: +/// https://godbolt.org/z/PsEPzGz1P +/// +pub enum FunctionAbi { + /// No specified ABI, same as extern "C" + None, + /// The default the C compiler supports + C, + /// CDecl, the default for x86_32 C code + CDecl, + /// The default for the Win32 API on x86_32 + StdCall, + /// The default for C code on x86_64 windows + Win64, + /// The default for C code on non-windows x86_64 + SystemV64, + /// Same as extern "C" except on Win32, where it is "stdcall" + System, + /// The default for the ARM architecture + AApcs, + /// MSVC's __fastcall/__attribute__((fastcall)) + FastCall, + /// MSVC's __thiscall/__attribute__((thiscall)) + ThisCall, + /// ABI used for UEFI + EfiApi, + /// Same as "C" but with unwinding + CUnwind, + /// Same as "cdecl" but with unwinding + CDeclUnwind, + /// Same as "stdcall" but with unwinding + StdCallUnwind, + /// Same as "win64" but with unwinding + Win64Unwind, + /// Same as "systemv64" but with unwinding + SystemV64Unwind, + /// Same as "system" but with unwinding + SystemUnwind, + /// Same as "aapcs" but with unwinding + AApcsUnwind, + /// Same as "fastcall" but with unwinding + FastCallUnwind, + /// Same as "thiscall" but with unwinding + ThisCallUnwind, +} + +impl FunctionAbi { + pub(crate) fn none() -> Self { + FunctionAbi::None + } + + pub(crate) fn abi(abi: &syn::Abi) -> Self { + abi.name + .as_ref() + .map_or_else(FunctionAbi::none, |name| match name.value().as_str() { + "C" => FunctionAbi::C, + "cdecl" => FunctionAbi::CDecl, + "stdcall" => FunctionAbi::StdCall, + "win64" => FunctionAbi::Win64, + "systemv64" => FunctionAbi::SystemV64, + "system" => FunctionAbi::System, + "aapcs" => FunctionAbi::AApcs, + "fastcall" => FunctionAbi::FastCall, + "thiscall" => FunctionAbi::ThisCall, + "efiapi" => FunctionAbi::EfiApi, + "C-unwind" => FunctionAbi::CUnwind, + "cdecl-unwind" => FunctionAbi::CDeclUnwind, + "stdcall-unwind" => FunctionAbi::StdCallUnwind, + "win64-unwind" => FunctionAbi::Win64Unwind, + "systemv64-unwind" => FunctionAbi::SystemV64Unwind, + "system-unwind" => FunctionAbi::SystemUnwind, + "aapcs-unwind" => FunctionAbi::AApcsUnwind, + "fastcall-unwind" => FunctionAbi::FastCallUnwind, + "thiscall-unwind" => FunctionAbi::ThisCallUnwind, + _ => FunctionAbi::none(), + }) + } + + /// Convert to an attribute that can be applied to a function declaration in the MSVC + /// format. We emit a define for the attribute in the generated code like, but only if the + /// attribute is actually used. + /// + /// ```c + /// #if defined(_MSC_VER) + /// #define __cbindgen_cdecl __cdecl + /// #else + /// #define __cbindgen_cdecl __attribute__((cdecl)) + /// #endif + /// ``` + /// + /// `__cbindgen_` is used as a prefix to avoid conflicts with other attributes and + /// to make it clear that this is a bindgen-specific attribute, as well as to avoid + /// conflicts with possible redefinitions of the attribute. + pub(crate) fn as_attribute(&self) -> Option<&'static str> { + match *self { + // Blank is equivalent to "C" and is the default for the compiler, so it is not explicitly specified + // C is the default C abi for the compiler, so it is not expliclty specified + FunctionAbi::None | FunctionAbi::C | FunctionAbi::CUnwind => None, + // CDecl is a specific ABI, so it is specified. + // CDecl is available as: + // - __cdecl in MSVC + // - __attribute__((cdecl)) in GCC/Clang + FunctionAbi::CDecl => Some("__cbindgen_abi_cdecl"), + // Stdcall is a specific ABI, so it is specified. + // Stdcall is available as: + // - __stdcall in MSVC + // - __attribute__((stdcall)) in GCC/Clang + FunctionAbi::StdCall => Some("__cbindgen_abi_stdcall"), + // Win64 can't be specified specifically), but is used when ms_abi is + // specified for 64-bit targets. It can't be used on 32-bit targets), so it + // should be safe to emit it without further conditions when requested. It is the + // default for MSVC), so it is explicitly defined as empty on that target. + FunctionAbi::Win64 => Some("__cbindgen_abi_win64"), + // Sysv is a specific ABI), so it is specified. It is not available on MSVC however), + // so it is defined as empty on that target. + FunctionAbi::SystemV64 => Some("__cbindgen_abi_sysv64"), + // Means "C" on all but 32-bit windows targets), where it means "stdcall" + FunctionAbi::System => Some("__cbindgen_abi_system"), + // The default on aarch64), but not available as a specific attribute. That + // means it should be safe to emit an empty attribute), and it will be + // compiled as the default cconv on that platform. + FunctionAbi::AApcs => Some("__cbindgen_abi_aapcs"), + // Fastcall is a specific ABI), so it is specified. + // Fastcall is available as: + // - __fastcall in MSVC + // - __attribute__((fastcall)) in GCC/Clang + FunctionAbi::FastCall => Some("__cbindgen_abi_fastcall"), + FunctionAbi::ThisCall => Some("__cbindgen_abi_thiscall"), + FunctionAbi::EfiApi => Some("__cbindgen_abi_efiapi"), + FunctionAbi::CDeclUnwind => Some("__cbindgen_abi_cdecl"), + FunctionAbi::StdCallUnwind => Some("__cbindgen_abi_stdcall"), + FunctionAbi::Win64Unwind => Some("__cbindgen_abi_win64"), + FunctionAbi::SystemV64Unwind => Some("__cbindgen_abi_sysv64"), + FunctionAbi::SystemUnwind => Some("__cbindgen_abi_system"), + FunctionAbi::AApcsUnwind => Some("__cbindgen_abi_aapcs"), + FunctionAbi::FastCallUnwind => Some("__cbindgen_abi_fastcall"), + FunctionAbi::ThisCallUnwind => Some("__cbindgen_abi_thiscall"), + } + } + + pub fn as_clike_definition(&self) -> Option<&'static str> { + match *self { + FunctionAbi::None | FunctionAbi::C | FunctionAbi::CUnwind => None, + FunctionAbi::CDecl => Some(indoc! {r#" + // Compiler-specific cdecl calling convention definition + #if defined(_MSC_VER) || defined(_ARCH_IA32) + // CDecl is defined on MSVC and on IA32 gcc/clang/icx + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#cdecl + #define __cbindgen_abi_cdecl __cdecl + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_cdecl __cdecl + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32 + #define __cbindgen_abi_cdecl __attribute__((cdecl)) + #elif defined(_MSC_VER) + // MSVC: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 + #define __cbindgen_abi_cdecl __cdecl + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"cdecl\" may break at runtime." ) + #define __cbindgen_abi_cdecl + #endif + #else + #pragma message ( "The CDecl ABI is not available in non-MSVC/non-IA32 builds but has been requested. This may result in code which breaks at runtime." ) + #define __cbindgen_abi_cdecl + #endif + + "#}), + FunctionAbi::CDeclUnwind => Some(indoc! {r#" + // Compiler-specific cdecl calling convention definition + #if defined(_MSC_VER) || defined(_ARCH_IA32) + // CDecl is defined on MSVC and on IA32 gcc/clang/icx + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#cdecl + #define __cbindgen_abi_cdecl_unwind __cdecl + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_cdecl_unwind __cdecl + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32 + #define __cbindgen_abi_cdecl_unwind __attribute__((cdecl)) + #elif defined(_MSC_VER) + // MSVC: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 + #define __cbindgen_abi_cdecl_unwind __cdecl + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"cdecl\" may break at runtime." ) + #define __cbindgen_abi_cdec_unwind + #endif + #else + #pragma message ( "The CDecl ABI is not available in non-MSVC/non-IA32 builds but has been requested. This may result in code which breaks at runtime." ) + #define __cbindgen_abi_cdecl + #endif + "#}), + FunctionAbi::StdCall => Some(indoc! {r#" + // Compiler-specific stdcall calling convention definition + #if defined(_MSC_VER) || defined(_ARCH_IA32) + // Stdcall is defined on MSVC and on IA32 gcc/clang/icx + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#stdcall + #define __cbindgen_abi_stdcall __stdcall + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_stdcall __stdcall + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32 + #define __cbindgen_abi_stdcall __attribute__((stdcall)) + #elif defined(_MSC_VER) + // MSVC: https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 + #define __cbindgen_abi_stdcall __stdcall + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"stdcall\" may break at runtime." ) + #define __cbindgen_abi_stdcall + #endif + #else + #pragma message ( "The StdCall ABI is not available in non-MSVC/non-IA32 builds but has been requested. This may result in code which breaks at runtime." ) + #define __cbindgen_abi_stdcall + #endif + "#}), + FunctionAbi::StdCallUnwind => Some(indoc! {r#" + // Compiler-specific stdcall calling convention definition + #if defined(_MSC_VER) || defined(_ARCH_IA32) + // Stdcall is defined on MSVC and on IA32 gcc/clang/icx + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#stdcall + #define __cbindgen_abi_stdcall_unwind __stdcall + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_stdcall_unwind __stdcall + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32 + #define __cbindgen_abi_stdcall_unwind __attribute__((stdcall)) + #elif defined(_MSC_VER) + // MSVC: https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 + #define __cbindgen_abi_stdcall_unwind __stdcall + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"stdcall\" may break at runtime." ) + #define __cbindgen_abi_stdcall_unwind + #endif + #else + #pragma message ( "The StdCall ABI is not available in non-MSVC/non-IA32 builds but has been requested. This may result in code which breaks at runtime." ) + #define __cbindgen_abi_stdcall + #endif + "#}), + FunctionAbi::Win64 => Some(indoc! {r#" + // Compiler-specific win64 calling convention definition + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi + #define __cbindgen_abi_win64 __attribute__((ms_abi)) + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_win64 __attribute__((ms_abi)) + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 + #define __cbindgen_abi_win64 __attribute__((ms_abi)) + #elif defined(_MSC_VER) + // MSVC: ms_abi is the default ABI on MSVC and does not need to be specified + #define __cbindgen_abi_win64 + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"win64\" may break at runtime." ) + #define __cbindgen_abi_win64 + #endif + "#}), + FunctionAbi::Win64Unwind => Some(indoc! {r#" + // Compiler-specific win64 calling convention definition + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi + #define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 + #define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) + #elif defined(_MSC_VER) + // MSVC: ms_abi is the default ABI on MSVC and does not need to be specified + #define __cbindgen_abi_win64_unwind + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"win64\" may break at runtime." ) + #define __cbindgen_abi_win64 + #endif + "#}), + FunctionAbi::SystemV64 => Some(indoc! {r#" + // Compiler-specific sysv64 calling convention definition + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#sysv-abi + #define __cbindgen_abi_sysv64 __attribute__((sysv_abi)) + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_sysv64 __attribute__((sysv_abi)) + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 + #define __cbindgen_abi_sysv64 __attribute__((sysv_abi)) + #elif defined(_MSC_VER) + // MSVC: SystemV ABI is not available on MSVC, so we generate an error if it is used + // as this will result in code that compiles, but may break at runtime + #pragma message ( "The SystemV ABI is not available in MSVC but has been requested. This may result in code which breaks at runtime." ) + #define __cbindgen_abi_sysv64 + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"sysv64\" may break at runtime." ) + #define __cbindgen_abi_sysv64 + #endif + "#}), + FunctionAbi::SystemV64Unwind => Some(indoc! {r#" + // Compiler-specific sysv64 calling convention definition + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#sysv-abi + #define __cbindgen_abi_sysv64_unwind __attribute__((sysv_abi)) + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_sysv64_unwind __attribute__((sysv_abi)) + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 + #define __cbindgen_abi_sysv64_unwind __attribute__((sysv_abi)) + #elif defined(_MSC_VER) + // MSVC: SystemV ABI is not available on MSVC, so we generate an error if it is used + // as this will result in code that compiles, but may break at runtime + #pragma message ( "The SystemV ABI is not available in MSVC but has been requested. This may result in code which breaks at runtime." ) + #define __cbindgen_abi_sysv64_unwind + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"sysv64\" may break at runtime." ) + #define __cbindgen_abi_sysv64_unwind + #endif + "#}), + FunctionAbi::System => Some(indoc! {r#" + // Compiler-specific system calling convention definition + #if (defined(_WIN32) || defined(__WIN32__) || defined(__WIN32)) && (defined(__i386__) || defined(_M_IX86)) + // If we are targeting 32-bit windows, "system" is "stdcall" + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#system + #define __cbindgen_abi_system __stdcall + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_system __stdcall + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-system-function-attribute_002c-x86-32 + #define __cbindgen_abi_system __attribute__((stdcall)) + #elif defined(_MSC_VER) + // MSVC: https://learn.microsoft.com/en-us/cpp/cpp/system?view=msvc-170 + #define __cbindgen_abi_system __stdcall + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"system\" may break at runtime." ) + #define __cbindgen_abi_system + #endif + #else + // Otherwise, it is equivalent to "C" AKA empty + #define __cbindgen_abi_system + #endif + "#}), + FunctionAbi::SystemUnwind => Some(indoc! {r#" + // Compiler-specific system calling convention definition + #if (defined(_WIN32) || defined(__WIN32__) || defined(__WIN32)) && (defined(__i386__) || defined(_M_IX86)) + // If we are targeting 32-bit windows, "system" is "stdcall" + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#system + #define __cbindgen_abi_system_unwind __stdcall + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_system_unwind __stdcall + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-system-function-attribute_002c-x86-32 + #define __cbindgen_abi_system_unwind __attribute__((stdcall)) + #elif defined(_MSC_VER) + // MSVC: https://learn.microsoft.com/en-us/cpp/cpp/system?view=msvc-170 + #define __cbindgen_abi_system_unwind __stdcall + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"system\" may break at runtime." ) + #define __cbindgen_abi_system_unwind + #endif + #else + // Otherwise, it is equivalent to "C" AKA empty + #define __cbindgen_abi_system_unwind + #endif + "#}), + FunctionAbi::AApcs => Some(indoc! {r#" + // Compiler-specific aapcs calling convention definition + #if defined(__arm__) || defined(_M_ARM) + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs + #define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM + #define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) + #elif defined(_MSC_VER) + // MSVC: Does not support an attribute for AAPCS, but it is the default + // as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 + #define __cbindgen_abi_aapcs + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"aapcs\" may break at runtime." ) + #define __cbindgen_abi_aapcs + #endif + #else + #pragma message ( "The AAPCS ABI is not available on non-ARM platforms but has been requested. This may result in code which breaks at runtime." ) + #define __cbindgen_abi_aapcs + #endif + "#}), + FunctionAbi::AApcsUnwind => Some(indoc! {r#" + // Compiler-specific aapcs calling convention definition + #if defined(__arm__) || defined(_M_ARM) + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs + #define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM + #define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) + #elif defined(_MSC_VER) + // MSVC: Does not support an attribute for AAPCS, but it is the default + // as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 + #define __cbindgen_abi_aapcs_unwind + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"aapcs\" may break at runtime." ) + #define __cbindgen_abi_aapcs_unwind + #endif + #else + #pragma message ( "The AAPCS ABI is not available on non-ARM platforms but has been requested. This may result in code which breaks at runtime." ) + #define __cbindgen_abi_aapcs_unwind + #endif + "#}), + FunctionAbi::FastCall => Some(indoc! {r#" + // Compiler-specific fastcall calling convention definition + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#fastcall + #define __cbindgen_abi_fastcall __fastcall + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_fastcall __fastcall + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-fastcall-function-attribute_002c-x86-32 + #define __cbindgen_abi_fastcall __attribute__((fastcall)) + #elif defined(_MSC_VER) + // MSVC: https://learn.microsoft.com/en-us/cpp/cpp/fastcall?view=msvc-170 + #define __cbindgen_abi_fastcall __fastcall + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"fastcall\" may break at runtime." ) + #define __cbindgen_abi_fastcall + #endif + "#}), + FunctionAbi::FastCallUnwind => Some(indoc! {r#" + // Compiler-specific fastcall calling convention definition + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#fastcall + #define __cbindgen_abi_fastcall_unwind __fastcall + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_fastcall_unwind __fastcall + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-fastcall-function-attribute_002c-x86-32 + #define __cbindgen_abi_fastcall_unwind __attribute__((fastcall)) + #elif defined(_MSC_VER) + // MSVC: https://learn.microsoft.com/en-us/cpp/cpp/fastcall?view=msvc-170 + #define __cbindgen_abi_fastcall_unwind __fastcall + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"fastcall\" may break at runtime." ) + #define __cbindgen_abi_fastcall_unwind + #endif + "#}), + FunctionAbi::ThisCall => Some(indoc! {r#" + // Compiler-specific thiscall calling convention definition + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#thiscall + #define __cbindgen_abi_thiscall __thiscall + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_thiscall __thiscall + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-thiscall-function-attribute_002c-x86-32 + #define __cbindgen_abi_thiscall __attribute__((thiscall)) + #elif defined(_MSC_VER) + // MSVC: https://learn.microsoft.com/en-us/cpp/cpp/thiscall?view=msvc-170 + #define __cbindgen_abi_thiscall __thiscall + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"thiscall\" may break at runtime." ) + #define __cbindgen_abi_thiscall + #endif + "#}), + FunctionAbi::ThisCallUnwind => Some(indoc! {r#" + // Compiler-specific thiscall calling convention definition + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#thiscall + #define __cbindgen_abi_thiscall_unwind __thiscall + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_thiscall_unwind __thiscall + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-thiscall-function-attribute_002c-x86-32 + #define __cbindgen_abi_thiscall_unwind __attribute__((thiscall)) + #elif defined(_MSC_VER) + // MSVC: https://learn.microsoft.com/en-us/cpp/cpp/thiscall?view=msvc-170 + #define __cbindgen_abi_thiscall_unwind __thiscall + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"thiscall\" may break at runtime." ) + #define __cbindgen_abi_thiscall_unwind + #endif + "#}), + FunctionAbi::EfiApi => Some(indoc! {r#" + // Compiler-specific efiapi calling convention definition + #if (defined(__arm__) && !defined(__aarch64__)) || defined(_M_ARM) + // On ARM, EFIAPI is the same as AAPCS + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs + #define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM + #define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) + #elif defined(_MSC_VER) + // MSVC: Does not support an attribute for AAPCS, but it is the default + // as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) + #define __cbindgen_abi_efiapi + #endif + #elif defined(__x86_64__) || defined(_M_X64) + // On x86_64, EFIAPI is MS_ABI + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + // Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi + #define __cbindgen_abi_efiapi __attribute__((ms_abi)) + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + // ICX: See Clang + #define __cbindgen_abi_efiapi __attribute__((ms_abi)) + #elif defined(__GNUC__) || defined(__GNUG__) + // GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 + #define __cbindgen_abi_efiapi __attribute__((ms_abi)) + #elif defined(_MSC_VER) + // MSVC: ms_abi is the default ABI on MSVC and does not need to be specified + #define __cbindgen_abi_efiapi + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) + #define __cbindgen_abi_efiapi + #endif + #else + // On all other architectures, EFIAPI is a no-op + #if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) + #define __cbindgen_abi_efiapi + #elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) + #define __cbindgen_abi_efiapi + #elif defined(__GNUC__) || defined(__GNUG__) + #define __cbindgen_abi_efiapi + #elif defined(_MSC_VER) + #define __cbindgen_abi_efiapi + #else + #pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) + #define __cbindgen_abi_efiapi + #endif + #endif + "#}), + } + } +} + #[derive(Debug, Clone)] pub struct FunctionArgument { pub name: Option, @@ -31,7 +598,10 @@ pub struct Function { pub self_type_path: Option, pub ret: Type, pub args: Vec, + /// Whether the declaration needs an "extern" keyword pub extern_decl: bool, + /// The ABI of the declaration + pub abi: FunctionAbi, pub cfg: Option, pub annotations: AnnotationSet, pub documentation: Documentation, @@ -44,6 +614,7 @@ impl Function { self_type_path: Option<&Path>, sig: &syn::Signature, extern_decl: bool, + abi: FunctionAbi, attrs: &[syn::Attribute], mod_cfg: Option<&Cfg>, ) -> Result { @@ -71,6 +642,7 @@ impl Function { ret, args, extern_decl, + abi, cfg: Cfg::append(mod_cfg, Cfg::load(attrs)), annotations: AnnotationSet::load(attrs)?, documentation: Documentation::load(attrs), diff --git a/src/bindgen/language_backend/clike.rs b/src/bindgen/language_backend/clike.rs index 5da079c3..5b75066d 100644 --- a/src/bindgen/language_backend/clike.rs +++ b/src/bindgen/language_backend/clike.rs @@ -1,12 +1,15 @@ -use crate::bindgen::ir::{ - to_known_assoc_constant, ConditionWrite, DeprecatedNoteKind, Documentation, Enum, EnumVariant, - Field, GenericParams, Item, Literal, OpaqueItem, ReprAlign, Static, Struct, ToCondition, Type, - Typedef, Union, -}; use crate::bindgen::language_backend::LanguageBackend; use crate::bindgen::rename::IdentifierType; use crate::bindgen::writer::{ListType, SourceWriter}; use crate::bindgen::{cdecl, Bindings, Config, Language}; +use crate::bindgen::{ + ir::{ + to_known_assoc_constant, ConditionWrite, DeprecatedNoteKind, Documentation, Enum, + EnumVariant, Field, GenericParams, Item, Literal, OpaqueItem, ReprAlign, Static, Struct, + ToCondition, Type, Typedef, Union, + }, + predefines::Predefines, +}; use crate::bindgen::{DocumentationLength, DocumentationStyle}; use std::io::Write; @@ -445,6 +448,17 @@ impl LanguageBackend for CLikeLanguageBackend<'_> { } } + fn write_predefines(&self, out: &mut SourceWriter, predefines: &Predefines) { + if self.config.function.emit_calling_convention { + predefines.calling_conventions().iter().for_each(|abi| { + if let Some(c_definition) = abi.as_clike_definition() { + out.write(c_definition); + out.new_line(); + } + }); + } + } + fn open_namespaces(&mut self, out: &mut SourceWriter) { self.open_close_namespaces(out, true); } diff --git a/src/bindgen/language_backend/cython.rs b/src/bindgen/language_backend/cython.rs index 5c85b2d0..7852f90e 100644 --- a/src/bindgen/language_backend/cython.rs +++ b/src/bindgen/language_backend/cython.rs @@ -104,6 +104,13 @@ impl LanguageBackend for CythonLanguageBackend<'_> { } } + fn write_predefines( + &self, + _out: &mut SourceWriter, + _predefines: &crate::bindgen::predefines::Predefines, + ) { + } + fn open_namespaces(&mut self, out: &mut SourceWriter) { out.new_line(); let header = &self.config.cython.header.as_deref().unwrap_or("*"); diff --git a/src/bindgen/language_backend/mod.rs b/src/bindgen/language_backend/mod.rs index adb7d850..094e15fa 100644 --- a/src/bindgen/language_backend/mod.rs +++ b/src/bindgen/language_backend/mod.rs @@ -1,7 +1,8 @@ use crate::bindgen::ir::{ - cfg::ConditionWrite, DeprecatedNoteKind, Documentation, Enum, Function, ItemContainer, Literal, - OpaqueItem, Static, Struct, ToCondition, Type, Typedef, Union, + cfg::ConditionWrite, DeprecatedNoteKind, Documentation, Enum, Function, FunctionAbi, + ItemContainer, Literal, OpaqueItem, Static, Struct, ToCondition, Type, Typedef, Union, }; +use crate::bindgen::predefines::Predefines; use crate::bindgen::writer::SourceWriter; use crate::bindgen::{cdecl, Bindings, Layout}; use crate::Config; @@ -17,6 +18,7 @@ pub use cython::CythonLanguageBackend; pub trait LanguageBackend: Sized { fn open_namespaces(&mut self, out: &mut SourceWriter); fn close_namespaces(&mut self, out: &mut SourceWriter); + fn write_predefines(&self, out: &mut SourceWriter, predefines: &Predefines); fn write_headers(&self, out: &mut SourceWriter, package_version: &str); fn write_footers(&mut self, out: &mut SourceWriter); fn write_enum(&mut self, out: &mut SourceWriter, e: &Enum); @@ -94,7 +96,7 @@ pub trait LanguageBackend: Sized { } cdecl::write_func(self, out, func, layout, config); - if !func.extern_decl { + if !matches!(func.abi, FunctionAbi::None) { if let Some(ref postfix) = postfix { write_space(layout, out); write!(out, "{}", postfix); @@ -118,6 +120,7 @@ pub trait LanguageBackend: Sized { fn write_bindings(&mut self, out: &mut SourceWriter, b: &Bindings) { self.write_headers(out, &b.package_version); + self.write_predefines(out, &b.predefines); self.open_namespaces(out); self.write_primitive_constants(out, b); self.write_items(out, b); diff --git a/src/bindgen/library.rs b/src/bindgen/library.rs index 9d61257f..79d54495 100644 --- a/src/bindgen/library.rs +++ b/src/bindgen/library.rs @@ -13,6 +13,7 @@ use crate::bindgen::error::Error; use crate::bindgen::ir::{Constant, Enum, Function, Item, ItemContainer, ItemMap}; use crate::bindgen::ir::{OpaqueItem, Path, Static, Struct, Typedef, Union}; use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::predefines::Predefines; use crate::bindgen::ItemType; #[derive(Debug, Clone)] @@ -134,11 +135,14 @@ impl Library { vec![] }; + let predefines = Predefines::new(&functions); + Ok(Bindings::new( self.config, self.structs, self.typedefs, constants, + predefines, globals, items, functions, diff --git a/src/bindgen/mod.rs b/src/bindgen/mod.rs index 5d788211..db9dcbe0 100644 --- a/src/bindgen/mod.rs +++ b/src/bindgen/mod.rs @@ -51,6 +51,7 @@ mod library; mod mangle; mod monomorph; mod parser; +mod predefines; mod rename; mod reserved; mod utilities; diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index eb2ef2dc..7e245559 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -15,8 +15,8 @@ use crate::bindgen::cargo::{Cargo, PackageRef}; use crate::bindgen::config::{Config, ParseConfig}; use crate::bindgen::error::Error; use crate::bindgen::ir::{ - AnnotationSet, AnnotationValue, Cfg, Constant, Documentation, Enum, Function, GenericParam, - GenericParams, ItemMap, OpaqueItem, Path, Static, Struct, Type, Typedef, Union, + AnnotationSet, AnnotationValue, Cfg, Constant, Documentation, Enum, Function, FunctionAbi, + GenericParam, GenericParams, ItemMap, OpaqueItem, Path, Static, Struct, Type, Typedef, Union, }; use crate::bindgen::utilities::{SynAbiHelpers, SynAttributeHelpers, SynItemHelpers}; @@ -600,7 +600,7 @@ impl Parse { ); } - /// Enters a `extern "C" { }` declaration and loads function declarations. + /// Enters a `extern "" { }` declaration and loads function declarations. fn load_syn_foreign_mod( &mut self, config: &Config, @@ -609,8 +609,8 @@ impl Parse { mod_cfg: Option<&Cfg>, item: &syn::ItemForeignMod, ) { - if !item.abi.is_c() && !item.abi.is_omitted() { - info!("Skip {} - (extern block must be extern C).", crate_name); + if !item.abi.is_any_c_abi() && !item.abi.is_omitted() { + info!("Skip {} - (extern block must be an extern C ABI https://doc.rust-lang.org/reference/items/external-blocks.html).", crate_name); return; } @@ -633,6 +633,7 @@ impl Parse { None, &function.sig, true, + FunctionAbi::abi(&item.abi), &function.attrs, mod_cfg.as_ref(), ) { @@ -728,13 +729,23 @@ impl Parse { items.join("::") }; - let is_extern_c = sig.abi.is_omitted() || sig.abi.is_c(); + let is_extern_c = sig.abi.is_omitted() || sig.abi.is_any_c_abi(); let exported_name = named_symbol.exported_name(); match (is_extern_c, exported_name) { (true, Some(exported_name)) => { let path = Path::new(exported_name); - match Function::load(path, self_type, sig, false, attrs, mod_cfg) { + match Function::load( + path, + self_type, + sig, + false, + sig.abi + .as_ref() + .map_or_else(FunctionAbi::none, FunctionAbi::abi), + attrs, + mod_cfg, + ) { Ok(func) => { info!("Take {}.", loggable_item_name()); self.functions.push(func); @@ -751,7 +762,7 @@ impl Parse { ); } (false, Some(_exported_name)) => { - warn!("Skipping {} - (not `extern \"C\"`)", loggable_item_name()); + warn!("Skipping {} - (not a valid extern fn https://doc.rust-lang.org/reference/items/external-blocks.html)", loggable_item_name()); } (false, None) => {} } diff --git a/src/bindgen/predefines.rs b/src/bindgen/predefines.rs new file mode 100644 index 00000000..0c802519 --- /dev/null +++ b/src/bindgen/predefines.rs @@ -0,0 +1,36 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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::collections::HashSet; + +use crate::bindgen::ir::{Function, FunctionAbi}; + +#[derive(Debug, Clone, Default)] +/// Loosely-defined set of things that may need to be defined at the top of a file. +/// Motivation is whether to emit compiler-specific calling conventions based on +/// whether they are used. +pub struct Predefines { + calling_conventions: HashSet, +} + +impl Predefines { + pub(crate) fn new(functions: &[Function]) -> Self { + Self { + calling_conventions: functions + .iter() + .map(|f| &f.abi) + .collect::>() + .into_iter() + .cloned() + .collect(), + } + } + + pub(crate) fn calling_conventions(&self) -> Vec<&FunctionAbi> { + // Sort the calling conventions + let mut conventions = self.calling_conventions.iter().collect::>(); + conventions.sort(); + conventions + } +} diff --git a/src/bindgen/utilities.rs b/src/bindgen/utilities.rs index 5cab65be..c8e8117b 100644 --- a/src/bindgen/utilities.rs +++ b/src/bindgen/utilities.rs @@ -319,20 +319,139 @@ impl_syn_item_helper!(syn::ItemMacro); impl_syn_item_helper!(syn::ItemTraitAlias); /// Helper function for accessing Abi information +/// +/// External blocks can have an ABI, the options for which are enumerated at: +/// https://doc.rust-lang.org/reference/items/external-blocks.html +/// +/// They can also have an "unwind" API, specified in the c_unwind unstable feature #74990: +/// https://doc.rust-lang.org/beta/unstable-book/language-features/c-unwind.html pub trait SynAbiHelpers { - fn is_c(&self) -> bool; + fn is_any_c_abi(&self) -> bool { + // Check if the ABI is any of the below + self.is_c() + || self.is_cdecl() + || self.is_stdcall() + || self.is_win64() + || self.is_sysv64() + || self.is_system() + || self.is_aapcs() + || self.is_fastcall() + || self.is_vectorcall() + || self.is_thiscall() + || self.is_efiapi() + || self.is_c_unwind() + || self.is_cdecl_unwind() + || self.is_stdcall_unwind() + || self.is_win64_unwind() + || self.is_sysv64_unwind() + || self.is_system_unwind() + || self.is_aapcs_unwind() + || self.is_fastcall_unwind() + || self.is_vectorcall_unwind() + || self.is_thiscall_unwind() + } + + fn is(&self, name: &str) -> bool; + fn is_omitted(&self) -> bool; + + fn is_c(&self) -> bool { + self.is("C") + } + + fn is_cdecl(&self) -> bool { + self.is("cdecl") + } + + fn is_stdcall(&self) -> bool { + self.is("stdcall") + } + + fn is_win64(&self) -> bool { + self.is("win64") + } + + fn is_sysv64(&self) -> bool { + self.is("sysv64") + } + + fn is_system(&self) -> bool { + self.is("system") + } + + fn is_aapcs(&self) -> bool { + self.is("aapcs") + } + + fn is_fastcall(&self) -> bool { + self.is("fastcall") + } + + fn is_vectorcall(&self) -> bool { + self.is("vectorcall") + } + + fn is_thiscall(&self) -> bool { + self.is("thiscall") + } + + fn is_efiapi(&self) -> bool { + self.is("efiapi") + } + + fn is_c_unwind(&self) -> bool { + self.is("C-unwind") + } + + fn is_cdecl_unwind(&self) -> bool { + self.is("cdecl-unwind") + } + + fn is_stdcall_unwind(&self) -> bool { + self.is("stdcall-unwind") + } + + fn is_win64_unwind(&self) -> bool { + self.is("win64-unwind") + } + + fn is_sysv64_unwind(&self) -> bool { + self.is("sysv64-unwind") + } + + fn is_system_unwind(&self) -> bool { + self.is("system-unwind") + } + + fn is_aapcs_unwind(&self) -> bool { + self.is("aapcs-unwind") + } + + fn is_fastcall_unwind(&self) -> bool { + self.is("fastcall-unwind") + } + + fn is_vectorcall_unwind(&self) -> bool { + self.is("vectorcall-unwind") + } + + fn is_thiscall_unwind(&self) -> bool { + self.is("thiscall-unwind") + } + + // NOTE: There is no efiapi-unwind, omission is not an error } impl SynAbiHelpers for Option { - fn is_c(&self) -> bool { + fn is(&self, name: &str) -> bool { if let Some(ref abi) = *self { if let Some(ref lit_string) = abi.name { - return matches!(lit_string.value().as_str(), "C" | "C-unwind"); + return lit_string.value().as_str() == name; } } false } + fn is_omitted(&self) -> bool { if let Some(ref abi) = *self { abi.name.is_none() @@ -343,9 +462,9 @@ impl SynAbiHelpers for Option { } impl SynAbiHelpers for syn::Abi { - fn is_c(&self) -> bool { + fn is(&self, name: &str) -> bool { if let Some(ref lit_string) = self.name { - matches!(lit_string.value().as_str(), "C" | "C-unwind") + return lit_string.value().as_str() == name; } else { false } diff --git a/template.toml b/template.toml index a2f18a68..08ccda9e 100644 --- a/template.toml +++ b/template.toml @@ -86,6 +86,7 @@ rename_args = "None" # postfix = "END_FUNC" args = "auto" sort_by = "Name" +# emit_calling_convention = true diff --git a/tests/expectations/cconv.c b/tests/expectations/cconv.c new file mode 100644 index 00000000..cf3af8b6 --- /dev/null +++ b/tests/expectations/cconv.c @@ -0,0 +1,373 @@ +#include +#include +#include +#include +// Compiler-specific cdecl calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#cdecl +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32 +#define __cbindgen_abi_cdecl __attribute__((cdecl)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 +#define __cbindgen_abi_cdecl __cdecl +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"cdecl\" may break at runtime." ) +#define __cbindgen_abi_cdecl +#endif + +// Compiler-specific stdcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#stdcall +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_stdcall __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 +#define __cbindgen_abi_stdcall __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"stdcall\" may break at runtime." ) +#define __cbindgen_abi_stdcall +#endif + +// Compiler-specific win64 calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi +#define __cbindgen_abi_win64 __attribute__((ms_abi)) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_win64 __attribute__((ms_abi)) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 +#define __cbindgen_abi_win64 __attribute__((ms_abi)) +#elif defined(_MSC_VER) +// MSVC: ms_abi is the default ABI on MSVC and does not need to be specified +#define __cbindgen_abi_win64 +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"win64\" may break at runtime." ) +#define __cbindgen_abi_win64 +#endif + +// Compiler-specific system calling convention definition +#if (defined(_WIN32) || defined(__WIN32__) || defined(__WIN32)) && (defined(__i386__) || defined(_M_IX86)) +// If we are targeting 32-bit windows, "system" is "stdcall" +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#system +#define __cbindgen_abi_system __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_system __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-system-function-attribute_002c-x86-32 +#define __cbindgen_abi_system __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/system?view=msvc-170 +#define __cbindgen_abi_system __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"system\" may break at runtime." ) +#define __cbindgen_abi_system +#endif +#else +// Otherwise, it is equivalent to "C" AKA empty +#define __cbindgen_abi_system +#endif + +// Compiler-specific aapcs calling convention definition +#if defined(__arm__) || defined(_M_ARM) +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs +#define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM +#define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) +#elif defined(_MSC_VER) +// MSVC: Does not support an attribute for AAPCS, but it is the default +// as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 +#define __cbindgen_abi_aapcs +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"aapcs\" may break at runtime." ) +#define __cbindgen_abi_aapcs +#endif +#else +#pragma message ( "The AAPCS ABI is not available on non-ARM platforms but has been requested. This may result in code which breaks at runtime." ) +#define __cbindgen_abi_aapcs +#endif + +// Compiler-specific fastcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#fastcall +#define __cbindgen_abi_fastcall __fastcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_fastcall __fastcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-fastcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_fastcall __attribute__((fastcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/fastcall?view=msvc-170 +#define __cbindgen_abi_fastcall __fastcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"fastcall\" may break at runtime." ) +#define __cbindgen_abi_fastcall +#endif + +// Compiler-specific thiscall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#thiscall +#define __cbindgen_abi_thiscall __thiscall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_thiscall __thiscall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-thiscall-function-attribute_002c-x86-32 +#define __cbindgen_abi_thiscall __attribute__((thiscall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/thiscall?view=msvc-170 +#define __cbindgen_abi_thiscall __thiscall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"thiscall\" may break at runtime." ) +#define __cbindgen_abi_thiscall +#endif + +// Compiler-specific efiapi calling convention definition +#if (defined(__arm__) && !defined(__aarch64__)) || defined(_M_ARM) +// On ARM, EFIAPI is the same as AAPCS +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs +#define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM +#define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) +#elif defined(_MSC_VER) +// MSVC: Does not support an attribute for AAPCS, but it is the default +// as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) +#define __cbindgen_abi_efiapi +#endif +#elif defined(__x86_64__) || defined(_M_X64) +// On x86_64, EFIAPI is MS_ABI +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi +#define __cbindgen_abi_efiapi __attribute__((ms_abi)) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_efiapi __attribute__((ms_abi)) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 +#define __cbindgen_abi_efiapi __attribute__((ms_abi)) +#elif defined(_MSC_VER) +// MSVC: ms_abi is the default ABI on MSVC and does not need to be specified +#define __cbindgen_abi_efiapi +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) +#define __cbindgen_abi_efiapi +#endif +#else +// On all other architectures, EFIAPI is a no-op +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +#define __cbindgen_abi_efiapi +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +#define __cbindgen_abi_efiapi +#elif defined(__GNUC__) || defined(__GNUG__) +#define __cbindgen_abi_efiapi +#elif defined(_MSC_VER) +#define __cbindgen_abi_efiapi +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) +#define __cbindgen_abi_efiapi +#endif +#endif + +// Compiler-specific cdecl calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#cdecl +#define __cbindgen_abi_cdecl_unwind __cdecl +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_cdecl_unwind __cdecl +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32 +#define __cbindgen_abi_cdecl_unwind __attribute__((cdecl)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 +#define __cbindgen_abi_cdecl_unwind __cdecl +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"cdecl\" may break at runtime." ) +#define __cbindgen_abi_cdec_unwindl +#endif + +// Compiler-specific stdcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#stdcall +#define __cbindgen_abi_stdcall_unwind __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_stdcall_unwind __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_stdcall_unwind __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 +#define __cbindgen_abi_stdcall_unwind __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"stdcall\" may break at runtime." ) +#define __cbindgen_abi_stdcall_unwind +#endif + +// Compiler-specific win64 calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi +#define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 +#define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) +#elif defined(_MSC_VER) +// MSVC: ms_abi is the default ABI on MSVC and does not need to be specified +#define __cbindgen_abi_win64_unwind +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"win64\" may break at runtime." ) +#define __cbindgen_abi_win64 +#endif + +// Compiler-specific system calling convention definition +#if (defined(_WIN32) || defined(__WIN32__) || defined(__WIN32)) && (defined(__i386__) || defined(_M_IX86)) +// If we are targeting 32-bit windows, "system" is "stdcall" +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#system +#define __cbindgen_abi_system_unwind __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_system_unwind __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-system-function-attribute_002c-x86-32 +#define __cbindgen_abi_system_unwind __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/system?view=msvc-170 +#define __cbindgen_abi_system_unwind __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"system\" may break at runtime." ) +#define __cbindgen_abi_system_unwind +#endif +#else +// Otherwise, it is equivalent to "C" AKA empty +#define __cbindgen_abi_system_unwind +#endif + +// Compiler-specific aapcs calling convention definition +#if defined(__arm__) || defined(_M_ARM) +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs +#define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM +#define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) +#elif defined(_MSC_VER) +// MSVC: Does not support an attribute for AAPCS, but it is the default +// as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 +#define __cbindgen_abi_aapcs_unwind +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"aapcs\" may break at runtime." ) +#define __cbindgen_abi_aapcs_unwind +#endif +#else +#pragma message ( "The AAPCS ABI is not available on non-ARM platforms but has been requested. This may result in code which breaks at runtime." ) +#define __cbindgen_abi_aapcs_unwind +#endif + +// Compiler-specific fastcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#fastcall +#define __cbindgen_abi_fastcall_unwind __fastcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_fastcall_unwind __fastcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-fastcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_fastcall_unwind __attribute__((fastcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/fastcall?view=msvc-170 +#define __cbindgen_abi_fastcall_unwind __fastcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"fastcall\" may break at runtime." ) +#define __cbindgen_abi_fastcall_unwind +#endif + +// Compiler-specific thiscall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#thiscall +#define __cbindgen_abi_thiscall_unwind __thiscall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_thiscall_unwind __thiscall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-thiscall-function-attribute_002c-x86-32 +#define __cbindgen_abi_thiscall_unwind __attribute__((thiscall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/thiscall?view=msvc-170 +#define __cbindgen_abi_thiscall_unwind __thiscall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"thiscall\" may break at runtime." ) +#define __cbindgen_abi_thiscall_unwind +#endif + + +void test_none(void); + +void test_c(void); + +void __cbindgen_abi_cdecl test_cdecl(void); + +void __cbindgen_abi_stdcall test_stdcall(void); + +void __cbindgen_abi_win64 test_win64(void); + +void test_sysv64(void); + +void __cbindgen_abi_system test_rust(void); + +void __cbindgen_abi_aapcs test_aapcs(void); + +void __cbindgen_abi_fastcall test_fastcall(void); + +void __cbindgen_abi_thiscall test_thiscall(void); + +void __cbindgen_abi_efiapi test_efiapi(void); + +void test_c(void); + +void __cbindgen_abi_cdecl test_cdecl(void); + +void __cbindgen_abi_stdcall test_stdcall(void); + +void __cbindgen_abi_win64 test_win64(void); + +void test_sysv64(void); + +void __cbindgen_abi_system test_rust(void); + +void __cbindgen_abi_aapcs test_aapcs(void); + +void __cbindgen_abi_fastcall test_fastcall(void); + +void __cbindgen_abi_thiscall test_thiscall(void); diff --git a/tests/expectations/cconv.compat.c b/tests/expectations/cconv.compat.c new file mode 100644 index 00000000..e847bf91 --- /dev/null +++ b/tests/expectations/cconv.compat.c @@ -0,0 +1,381 @@ +#include +#include +#include +#include +// Compiler-specific cdecl calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#cdecl +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32 +#define __cbindgen_abi_cdecl __attribute__((cdecl)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 +#define __cbindgen_abi_cdecl __cdecl +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"cdecl\" may break at runtime." ) +#define __cbindgen_abi_cdecl +#endif + +// Compiler-specific stdcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#stdcall +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_stdcall __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 +#define __cbindgen_abi_stdcall __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"stdcall\" may break at runtime." ) +#define __cbindgen_abi_stdcall +#endif + +// Compiler-specific win64 calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi +#define __cbindgen_abi_win64 __attribute__((ms_abi)) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_win64 __attribute__((ms_abi)) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 +#define __cbindgen_abi_win64 __attribute__((ms_abi)) +#elif defined(_MSC_VER) +// MSVC: ms_abi is the default ABI on MSVC and does not need to be specified +#define __cbindgen_abi_win64 +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"win64\" may break at runtime." ) +#define __cbindgen_abi_win64 +#endif + +// Compiler-specific system calling convention definition +#if (defined(_WIN32) || defined(__WIN32__) || defined(__WIN32)) && (defined(__i386__) || defined(_M_IX86)) +// If we are targeting 32-bit windows, "system" is "stdcall" +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#system +#define __cbindgen_abi_system __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_system __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-system-function-attribute_002c-x86-32 +#define __cbindgen_abi_system __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/system?view=msvc-170 +#define __cbindgen_abi_system __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"system\" may break at runtime." ) +#define __cbindgen_abi_system +#endif +#else +// Otherwise, it is equivalent to "C" AKA empty +#define __cbindgen_abi_system +#endif + +// Compiler-specific aapcs calling convention definition +#if defined(__arm__) || defined(_M_ARM) +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs +#define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM +#define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) +#elif defined(_MSC_VER) +// MSVC: Does not support an attribute for AAPCS, but it is the default +// as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 +#define __cbindgen_abi_aapcs +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"aapcs\" may break at runtime." ) +#define __cbindgen_abi_aapcs +#endif +#else +#pragma message ( "The AAPCS ABI is not available on non-ARM platforms but has been requested. This may result in code which breaks at runtime." ) +#define __cbindgen_abi_aapcs +#endif + +// Compiler-specific fastcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#fastcall +#define __cbindgen_abi_fastcall __fastcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_fastcall __fastcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-fastcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_fastcall __attribute__((fastcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/fastcall?view=msvc-170 +#define __cbindgen_abi_fastcall __fastcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"fastcall\" may break at runtime." ) +#define __cbindgen_abi_fastcall +#endif + +// Compiler-specific thiscall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#thiscall +#define __cbindgen_abi_thiscall __thiscall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_thiscall __thiscall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-thiscall-function-attribute_002c-x86-32 +#define __cbindgen_abi_thiscall __attribute__((thiscall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/thiscall?view=msvc-170 +#define __cbindgen_abi_thiscall __thiscall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"thiscall\" may break at runtime." ) +#define __cbindgen_abi_thiscall +#endif + +// Compiler-specific efiapi calling convention definition +#if (defined(__arm__) && !defined(__aarch64__)) || defined(_M_ARM) +// On ARM, EFIAPI is the same as AAPCS +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs +#define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM +#define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) +#elif defined(_MSC_VER) +// MSVC: Does not support an attribute for AAPCS, but it is the default +// as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) +#define __cbindgen_abi_efiapi +#endif +#elif defined(__x86_64__) || defined(_M_X64) +// On x86_64, EFIAPI is MS_ABI +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi +#define __cbindgen_abi_efiapi __attribute__((ms_abi)) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_efiapi __attribute__((ms_abi)) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 +#define __cbindgen_abi_efiapi __attribute__((ms_abi)) +#elif defined(_MSC_VER) +// MSVC: ms_abi is the default ABI on MSVC and does not need to be specified +#define __cbindgen_abi_efiapi +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) +#define __cbindgen_abi_efiapi +#endif +#else +// On all other architectures, EFIAPI is a no-op +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +#define __cbindgen_abi_efiapi +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +#define __cbindgen_abi_efiapi +#elif defined(__GNUC__) || defined(__GNUG__) +#define __cbindgen_abi_efiapi +#elif defined(_MSC_VER) +#define __cbindgen_abi_efiapi +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) +#define __cbindgen_abi_efiapi +#endif +#endif + +// Compiler-specific cdecl calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#cdecl +#define __cbindgen_abi_cdecl_unwind __cdecl +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_cdecl_unwind __cdecl +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32 +#define __cbindgen_abi_cdecl_unwind __attribute__((cdecl)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 +#define __cbindgen_abi_cdecl_unwind __cdecl +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"cdecl\" may break at runtime." ) +#define __cbindgen_abi_cdec_unwindl +#endif + +// Compiler-specific stdcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#stdcall +#define __cbindgen_abi_stdcall_unwind __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_stdcall_unwind __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_stdcall_unwind __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 +#define __cbindgen_abi_stdcall_unwind __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"stdcall\" may break at runtime." ) +#define __cbindgen_abi_stdcall_unwind +#endif + +// Compiler-specific win64 calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi +#define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 +#define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) +#elif defined(_MSC_VER) +// MSVC: ms_abi is the default ABI on MSVC and does not need to be specified +#define __cbindgen_abi_win64_unwind +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"win64\" may break at runtime." ) +#define __cbindgen_abi_win64 +#endif + +// Compiler-specific system calling convention definition +#if (defined(_WIN32) || defined(__WIN32__) || defined(__WIN32)) && (defined(__i386__) || defined(_M_IX86)) +// If we are targeting 32-bit windows, "system" is "stdcall" +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#system +#define __cbindgen_abi_system_unwind __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_system_unwind __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-system-function-attribute_002c-x86-32 +#define __cbindgen_abi_system_unwind __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/system?view=msvc-170 +#define __cbindgen_abi_system_unwind __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"system\" may break at runtime." ) +#define __cbindgen_abi_system_unwind +#endif +#else +// Otherwise, it is equivalent to "C" AKA empty +#define __cbindgen_abi_system_unwind +#endif + +// Compiler-specific aapcs calling convention definition +#if defined(__arm__) || defined(_M_ARM) +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs +#define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM +#define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) +#elif defined(_MSC_VER) +// MSVC: Does not support an attribute for AAPCS, but it is the default +// as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 +#define __cbindgen_abi_aapcs_unwind +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"aapcs\" may break at runtime." ) +#define __cbindgen_abi_aapcs_unwind +#endif +#else +#pragma message ( "The AAPCS ABI is not available on non-ARM platforms but has been requested. This may result in code which breaks at runtime." ) +#define __cbindgen_abi_aapcs_unwind +#endif + +// Compiler-specific fastcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#fastcall +#define __cbindgen_abi_fastcall_unwind __fastcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_fastcall_unwind __fastcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-fastcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_fastcall_unwind __attribute__((fastcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/fastcall?view=msvc-170 +#define __cbindgen_abi_fastcall_unwind __fastcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"fastcall\" may break at runtime." ) +#define __cbindgen_abi_fastcall_unwind +#endif + +// Compiler-specific thiscall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#thiscall +#define __cbindgen_abi_thiscall_unwind __thiscall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_thiscall_unwind __thiscall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-thiscall-function-attribute_002c-x86-32 +#define __cbindgen_abi_thiscall_unwind __attribute__((thiscall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/thiscall?view=msvc-170 +#define __cbindgen_abi_thiscall_unwind __thiscall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"thiscall\" may break at runtime." ) +#define __cbindgen_abi_thiscall_unwind +#endif + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void test_none(void); + +void test_c(void); + +void __cbindgen_abi_cdecl test_cdecl(void); + +void __cbindgen_abi_stdcall test_stdcall(void); + +void __cbindgen_abi_win64 test_win64(void); + +void test_sysv64(void); + +void __cbindgen_abi_system test_rust(void); + +void __cbindgen_abi_aapcs test_aapcs(void); + +void __cbindgen_abi_fastcall test_fastcall(void); + +void __cbindgen_abi_thiscall test_thiscall(void); + +void __cbindgen_abi_efiapi test_efiapi(void); + +void test_c(void); + +void __cbindgen_abi_cdecl test_cdecl(void); + +void __cbindgen_abi_stdcall test_stdcall(void); + +void __cbindgen_abi_win64 test_win64(void); + +void test_sysv64(void); + +void __cbindgen_abi_system test_rust(void); + +void __cbindgen_abi_aapcs test_aapcs(void); + +void __cbindgen_abi_fastcall test_fastcall(void); + +void __cbindgen_abi_thiscall test_thiscall(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/cconv.cpp b/tests/expectations/cconv.cpp new file mode 100644 index 00000000..2c95c4eb --- /dev/null +++ b/tests/expectations/cconv.cpp @@ -0,0 +1,378 @@ +#include +#include +#include +#include +#include +// Compiler-specific cdecl calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#cdecl +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32 +#define __cbindgen_abi_cdecl __attribute__((cdecl)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 +#define __cbindgen_abi_cdecl __cdecl +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"cdecl\" may break at runtime." ) +#define __cbindgen_abi_cdecl +#endif + +// Compiler-specific stdcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#stdcall +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_stdcall __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 +#define __cbindgen_abi_stdcall __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"stdcall\" may break at runtime." ) +#define __cbindgen_abi_stdcall +#endif + +// Compiler-specific win64 calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi +#define __cbindgen_abi_win64 __attribute__((ms_abi)) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_win64 __attribute__((ms_abi)) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 +#define __cbindgen_abi_win64 __attribute__((ms_abi)) +#elif defined(_MSC_VER) +// MSVC: ms_abi is the default ABI on MSVC and does not need to be specified +#define __cbindgen_abi_win64 +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"win64\" may break at runtime." ) +#define __cbindgen_abi_win64 +#endif + +// Compiler-specific system calling convention definition +#if (defined(_WIN32) || defined(__WIN32__) || defined(__WIN32)) && (defined(__i386__) || defined(_M_IX86)) +// If we are targeting 32-bit windows, "system" is "stdcall" +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#system +#define __cbindgen_abi_system __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_system __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-system-function-attribute_002c-x86-32 +#define __cbindgen_abi_system __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/system?view=msvc-170 +#define __cbindgen_abi_system __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"system\" may break at runtime." ) +#define __cbindgen_abi_system +#endif +#else +// Otherwise, it is equivalent to "C" AKA empty +#define __cbindgen_abi_system +#endif + +// Compiler-specific aapcs calling convention definition +#if defined(__arm__) || defined(_M_ARM) +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs +#define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM +#define __cbindgen_abi_aapcs __attribute__((pcs("aapcs"))) +#elif defined(_MSC_VER) +// MSVC: Does not support an attribute for AAPCS, but it is the default +// as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 +#define __cbindgen_abi_aapcs +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"aapcs\" may break at runtime." ) +#define __cbindgen_abi_aapcs +#endif +#else +#pragma message ( "The AAPCS ABI is not available on non-ARM platforms but has been requested. This may result in code which breaks at runtime." ) +#define __cbindgen_abi_aapcs +#endif + +// Compiler-specific fastcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#fastcall +#define __cbindgen_abi_fastcall __fastcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_fastcall __fastcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-fastcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_fastcall __attribute__((fastcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/fastcall?view=msvc-170 +#define __cbindgen_abi_fastcall __fastcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"fastcall\" may break at runtime." ) +#define __cbindgen_abi_fastcall +#endif + +// Compiler-specific thiscall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#thiscall +#define __cbindgen_abi_thiscall __thiscall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_thiscall __thiscall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-thiscall-function-attribute_002c-x86-32 +#define __cbindgen_abi_thiscall __attribute__((thiscall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/thiscall?view=msvc-170 +#define __cbindgen_abi_thiscall __thiscall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"thiscall\" may break at runtime." ) +#define __cbindgen_abi_thiscall +#endif + +// Compiler-specific efiapi calling convention definition +#if (defined(__arm__) && !defined(__aarch64__)) || defined(_M_ARM) +// On ARM, EFIAPI is the same as AAPCS +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs +#define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM +#define __cbindgen_abi_efiapi __attribute__((pcs("aapcs"))) +#elif defined(_MSC_VER) +// MSVC: Does not support an attribute for AAPCS, but it is the default +// as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) +#define __cbindgen_abi_efiapi +#endif +#elif defined(__x86_64__) || defined(_M_X64) +// On x86_64, EFIAPI is MS_ABI +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi +#define __cbindgen_abi_efiapi __attribute__((ms_abi)) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_efiapi __attribute__((ms_abi)) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 +#define __cbindgen_abi_efiapi __attribute__((ms_abi)) +#elif defined(_MSC_VER) +// MSVC: ms_abi is the default ABI on MSVC and does not need to be specified +#define __cbindgen_abi_efiapi +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) +#define __cbindgen_abi_efiapi +#endif +#else +// On all other architectures, EFIAPI is a no-op +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +#define __cbindgen_abi_efiapi +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +#define __cbindgen_abi_efiapi +#elif defined(__GNUC__) || defined(__GNUG__) +#define __cbindgen_abi_efiapi +#elif defined(_MSC_VER) +#define __cbindgen_abi_efiapi +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"efiapi\" may break at runtime." ) +#define __cbindgen_abi_efiapi +#endif +#endif + +// Compiler-specific cdecl calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#cdecl +#define __cbindgen_abi_cdecl_unwind __cdecl +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_cdecl_unwind __cdecl +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32 +#define __cbindgen_abi_cdecl_unwind __attribute__((cdecl)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 +#define __cbindgen_abi_cdecl_unwind __cdecl +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"cdecl\" may break at runtime." ) +#define __cbindgen_abi_cdec_unwindl +#endif + +// Compiler-specific stdcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#stdcall +#define __cbindgen_abi_stdcall_unwind __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_stdcall_unwind __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_stdcall_unwind __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 +#define __cbindgen_abi_stdcall_unwind __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"stdcall\" may break at runtime." ) +#define __cbindgen_abi_stdcall_unwind +#endif + +// Compiler-specific win64 calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#ms-abi +#define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-ms_005fabi-function-attribute_002c-x86 +#define __cbindgen_abi_win64_unwind __attribute__((ms_abi)) +#elif defined(_MSC_VER) +// MSVC: ms_abi is the default ABI on MSVC and does not need to be specified +#define __cbindgen_abi_win64_unwind +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"win64\" may break at runtime." ) +#define __cbindgen_abi_win64 +#endif + +// Compiler-specific system calling convention definition +#if (defined(_WIN32) || defined(__WIN32__) || defined(__WIN32)) && (defined(__i386__) || defined(_M_IX86)) +// If we are targeting 32-bit windows, "system" is "stdcall" +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#system +#define __cbindgen_abi_system_unwind __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_system_unwind __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-system-function-attribute_002c-x86-32 +#define __cbindgen_abi_system_unwind __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/system?view=msvc-170 +#define __cbindgen_abi_system_unwind __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"system\" may break at runtime." ) +#define __cbindgen_abi_system_unwind +#endif +#else +// Otherwise, it is equivalent to "C" AKA empty +#define __cbindgen_abi_system_unwind +#endif + +// Compiler-specific aapcs calling convention definition +#if defined(__arm__) || defined(_M_ARM) +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#pcs +#define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/ARM-Function-Attributes.html#index-pcs-function-attribute_002c-ARM +#define __cbindgen_abi_aapcs_unwind __attribute__((pcs("aapcs"))) +#elif defined(_MSC_VER) +// MSVC: Does not support an attribute for AAPCS, but it is the default +// as described in: https://learn.microsoft.com/en-us/cpp/build/overview-of-arm-abi-conventions?view=msvc-170 +#define __cbindgen_abi_aapcs_unwind +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"aapcs\" may break at runtime." ) +#define __cbindgen_abi_aapcs_unwind +#endif +#else +#pragma message ( "The AAPCS ABI is not available on non-ARM platforms but has been requested. This may result in code which breaks at runtime." ) +#define __cbindgen_abi_aapcs_unwind +#endif + +// Compiler-specific fastcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#fastcall +#define __cbindgen_abi_fastcall_unwind __fastcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_fastcall_unwind __fastcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-fastcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_fastcall_unwind __attribute__((fastcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/fastcall?view=msvc-170 +#define __cbindgen_abi_fastcall_unwind __fastcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"fastcall\" may break at runtime." ) +#define __cbindgen_abi_fastcall_unwind +#endif + +// Compiler-specific thiscall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#thiscall +#define __cbindgen_abi_thiscall_unwind __thiscall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_thiscall_unwind __thiscall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-thiscall-function-attribute_002c-x86-32 +#define __cbindgen_abi_thiscall_unwind __attribute__((thiscall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/thiscall?view=msvc-170 +#define __cbindgen_abi_thiscall_unwind __thiscall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"thiscall\" may break at runtime." ) +#define __cbindgen_abi_thiscall_unwind +#endif + + +extern "C" { + +void test_none(); + +void test_c(); + +void __cbindgen_abi_cdecl test_cdecl(); + +void __cbindgen_abi_stdcall test_stdcall(); + +void __cbindgen_abi_win64 test_win64(); + +void test_sysv64(); + +void __cbindgen_abi_system test_rust(); + +void __cbindgen_abi_aapcs test_aapcs(); + +void __cbindgen_abi_fastcall test_fastcall(); + +void __cbindgen_abi_thiscall test_thiscall(); + +void __cbindgen_abi_efiapi test_efiapi(); + +void test_c(); + +void __cbindgen_abi_cdecl test_cdecl(); + +void __cbindgen_abi_stdcall test_stdcall(); + +void __cbindgen_abi_win64 test_win64(); + +void test_sysv64(); + +void __cbindgen_abi_system test_rust(); + +void __cbindgen_abi_aapcs test_aapcs(); + +void __cbindgen_abi_fastcall test_fastcall(); + +void __cbindgen_abi_thiscall test_thiscall(); + +} // extern "C" diff --git a/tests/expectations/cconv.pyx b/tests/expectations/cconv.pyx new file mode 100644 index 00000000..f621dae3 --- /dev/null +++ b/tests/expectations/cconv.pyx @@ -0,0 +1,47 @@ +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 *: + + void test_none(); + + void test_c(); + + void test_cdecl(); + + void test_stdcall(); + + void test_win64(); + + void test_sysv64(); + + void test_rust(); + + void test_aapcs(); + + void test_fastcall(); + + void test_thiscall(); + + void test_efiapi(); + + void test_c(); + + void test_cdecl(); + + void test_stdcall(); + + void test_win64(); + + void test_sysv64(); + + void test_rust(); + + void test_aapcs(); + + void test_fastcall(); + + void test_thiscall(); diff --git a/tests/expectations/cconv_cfg.c b/tests/expectations/cconv_cfg.c new file mode 100644 index 00000000..10fbf640 --- /dev/null +++ b/tests/expectations/cconv_cfg.c @@ -0,0 +1,6 @@ +#include +#include +#include +#include + +void test_cdecl(void); diff --git a/tests/expectations/cconv_cfg.compat.c b/tests/expectations/cconv_cfg.compat.c new file mode 100644 index 00000000..bdfb6471 --- /dev/null +++ b/tests/expectations/cconv_cfg.compat.c @@ -0,0 +1,14 @@ +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void test_cdecl(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/cconv_cfg.cpp b/tests/expectations/cconv_cfg.cpp new file mode 100644 index 00000000..846c74da --- /dev/null +++ b/tests/expectations/cconv_cfg.cpp @@ -0,0 +1,11 @@ +#include +#include +#include +#include +#include + +extern "C" { + +void test_cdecl(); + +} // extern "C" diff --git a/tests/expectations/cconv_cfg.pyx b/tests/expectations/cconv_cfg.pyx new file mode 100644 index 00000000..78206ddb --- /dev/null +++ b/tests/expectations/cconv_cfg.pyx @@ -0,0 +1,9 @@ +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 *: + + void test_cdecl(); diff --git a/tests/expectations/cconv_few.c b/tests/expectations/cconv_few.c new file mode 100644 index 00000000..ee8d0787 --- /dev/null +++ b/tests/expectations/cconv_few.c @@ -0,0 +1,46 @@ +#include +#include +#include +#include +// Compiler-specific cdecl calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#cdecl +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32 +#define __cbindgen_abi_cdecl __attribute__((cdecl)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 +#define __cbindgen_abi_cdecl __cdecl +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"cdecl\" may break at runtime." ) +#define __cbindgen_abi_cdecl +#endif + +// Compiler-specific stdcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#stdcall +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_stdcall __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 +#define __cbindgen_abi_stdcall __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"stdcall\" may break at runtime." ) +#define __cbindgen_abi_stdcall +#endif + + +void test_c(void); + +void __cbindgen_abi_cdecl test_cdecl(void); + +void __cbindgen_abi_stdcall test_stdcall(void); diff --git a/tests/expectations/cconv_few.compat.c b/tests/expectations/cconv_few.compat.c new file mode 100644 index 00000000..ad012827 --- /dev/null +++ b/tests/expectations/cconv_few.compat.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +// Compiler-specific cdecl calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#cdecl +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32 +#define __cbindgen_abi_cdecl __attribute__((cdecl)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 +#define __cbindgen_abi_cdecl __cdecl +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"cdecl\" may break at runtime." ) +#define __cbindgen_abi_cdecl +#endif + +// Compiler-specific stdcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#stdcall +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_stdcall __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 +#define __cbindgen_abi_stdcall __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"stdcall\" may break at runtime." ) +#define __cbindgen_abi_stdcall +#endif + + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +void test_c(void); + +void __cbindgen_abi_cdecl test_cdecl(void); + +void __cbindgen_abi_stdcall test_stdcall(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/cconv_few.cpp b/tests/expectations/cconv_few.cpp new file mode 100644 index 00000000..65e6581f --- /dev/null +++ b/tests/expectations/cconv_few.cpp @@ -0,0 +1,51 @@ +#include +#include +#include +#include +#include +// Compiler-specific cdecl calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#cdecl +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_cdecl __cdecl +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32 +#define __cbindgen_abi_cdecl __attribute__((cdecl)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/cdecl?view=msvc-170 +#define __cbindgen_abi_cdecl __cdecl +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"cdecl\" may break at runtime." ) +#define __cbindgen_abi_cdecl +#endif + +// Compiler-specific stdcall calling convention definition +#if defined(__clang__) && !defined(__INTEL_LLVM_COMPILER) +// Clang: https://clang.llvm.org/docs/AttributeReference.html#stdcall +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__clang__) && defined(__INTEL_LLVM_COMPILER) +// ICX: See Clang +#define __cbindgen_abi_stdcall __stdcall +#elif defined(__GNUC__) || defined(__GNUG__) +// GCC: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32 +#define __cbindgen_abi_stdcall __attribute__((stdcall)) +#elif defined(_MSC_VER) +// MSVC: https://learn.microsoft.com/en-us/cpp/cpp/stdcall?view=msvc-170 +#define __cbindgen_abi_stdcall __stdcall +#else +#pragma message ( "An unsupported compiler is in use. Functions declared as extern \"stdcall\" may break at runtime." ) +#define __cbindgen_abi_stdcall +#endif + + +extern "C" { + +void test_c(); + +void __cbindgen_abi_cdecl test_cdecl(); + +void __cbindgen_abi_stdcall test_stdcall(); + +} // extern "C" diff --git a/tests/expectations/cconv_few.pyx b/tests/expectations/cconv_few.pyx new file mode 100644 index 00000000..eadc16c0 --- /dev/null +++ b/tests/expectations/cconv_few.pyx @@ -0,0 +1,13 @@ +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 *: + + void test_c(); + + void test_cdecl(); + + void test_stdcall(); diff --git a/tests/rust/cconv.rs b/tests/rust/cconv.rs new file mode 100644 index 00000000..55c8541c --- /dev/null +++ b/tests/rust/cconv.rs @@ -0,0 +1,63 @@ +//! Test that all calling conventions are emitted correctly + +#[no_mangle] +pub extern "C" fn test_none() {} + +#[no_mangle] +pub extern "C" fn test_c() {} + +#[no_mangle] +pub extern "cdecl" fn test_cdecl() {} + +#[no_mangle] +pub extern "stdcall" fn test_stdcall() {} + +#[no_mangle] +pub extern "win64" fn test_win64() {} + +#[no_mangle] +pub extern "sysv64" fn test_sysv64() {} + +#[no_mangle] +pub extern "system" fn test_rust() {} + +#[no_mangle] +// NOTE: Accepting on non-arm may be a bug https://github.com/rust-lang/rust/issues/57182 +pub extern "aapcs" fn test_aapcs() {} + +#[no_mangle] +pub extern "fastcall" fn test_fastcall() {} + +#[no_mangle] +pub extern "thiscall" fn test_thiscall() {} + +#[no_mangle] +pub extern "efiapi" fn test_efiapi() {} + +#[no_mangle] +pub extern "C-unwind" fn test_c() {} + +#[no_mangle] +pub extern "cdecl-unwind" fn test_cdecl() {} + +#[no_mangle] +pub extern "stdcall-unwind" fn test_stdcall() {} + +#[no_mangle] +pub extern "win64-unwind" fn test_win64() {} + +#[no_mangle] +pub extern "sysv64-unwind" fn test_sysv64() {} + +#[no_mangle] +pub extern "system-unwind" fn test_rust() {} + +#[no_mangle] +// NOTE: Accepting on non-arm may be a bug https://github.com/rust-lang/rust/issues/57182 +pub extern "aapcs-unwind" fn test_aapcs() {} + +#[no_mangle] +pub extern "fastcall-unwind" fn test_fastcall() {} + +#[no_mangle] +pub extern "thiscall-unwind" fn test_thiscall() {} diff --git a/tests/rust/cconv_cfg.rs b/tests/rust/cconv_cfg.rs new file mode 100644 index 00000000..fd1df6ca --- /dev/null +++ b/tests/rust/cconv_cfg.rs @@ -0,0 +1,2 @@ +#[no_mangle] +pub extern "cdecl" fn test_cdecl() {} diff --git a/tests/rust/cconv_cfg.toml b/tests/rust/cconv_cfg.toml new file mode 100644 index 00000000..c5046a76 --- /dev/null +++ b/tests/rust/cconv_cfg.toml @@ -0,0 +1,2 @@ +[fn] +emit_calling_convention = false diff --git a/tests/rust/cconv_few.rs b/tests/rust/cconv_few.rs new file mode 100644 index 00000000..be0bb3ac --- /dev/null +++ b/tests/rust/cconv_few.rs @@ -0,0 +1,10 @@ +//! Test that only the used calling conventions are emitted as predefines + +#[no_mangle] +pub extern "C" fn test_c() {} + +#[no_mangle] +pub extern "cdecl" fn test_cdecl() {} + +#[no_mangle] +pub extern "stdcall" fn test_stdcall() {}